Форматирование отображения вращающейся кнопки в PyGObject/GTK+3

Я занимаюсь переносом приложения с PyGTK на PyGObject. В основном все идет хорошо, потому что в основном я делал обычные вещи с PyGTK. Но есть один довольно уродливый хак, который я использовал для отображения значения SpinButton в виде валюты (с $ перед ним).

Первоначально я получил это решение из списка рассылки PyGTK назад за несколько дней до переполнения стека. Как видите, волшебство происходит с входными и выходными сигналами:

import gtk, ctypes

def _currency_input(spinbutton, gpointer):
    text = spinbutton.get_text()
    if text.startswith('$'):
        text = text[1:]
    double = ctypes.c_double.from_address(hash(gpointer))
    double.value = float(text)
    return True

def _currency_output(spinbutton):
    text = '$%.*f' % (int(spinbutton.props.digits), 
spinbutton.props.adjustment.value)
    spinbutton.set_text(text)
    return True

def format_spinbutton_currency(spinbutton):
    spinbutton.connect('input', _currency_input)
    spinbutton.connect('output', _currency_output)

def _test():
    s = gtk.SpinButton(gtk.Adjustment(value=1, lower=0, upper=1000, 
step_incr=1))
    s.props.digits = 2
    format_spinbutton_currency(s)
    w = gtk.Window()
    w.props.border_width = 12
    w.add(s)
    w.show_all()
    w.connect('destroy', gtk.main_quit)
    gtk.main()

if __name__ == '__main__':
    _test()

Делая все возможное, чтобы перевести это в PyGObject, я придумал:

from gi.repository import Gtk
import ctypes

def _currency_input(spinbutton, gpointer):
    text = spinbutton.get_text()
    if text.startswith('$'):
        text = text[1:]
    double = ctypes.c_double.from_address(hash(gpointer))
    double.value = float(text)
    return True

def _currency_output(spinbutton):
    text = '$%.*f' % (int(spinbutton.props.digits), 
spinbutton.get_value())
    spinbutton.set_text(text)
    return True

def format_spinbutton_currency(spinbutton):
    spinbutton.connect('input', _currency_input)
    spinbutton.connect('output', _currency_output)

def _test():
    s = Gtk.SpinButton()
    s.set_adjustment(Gtk.Adjustment(value=1, lower=0, upper=1000, 
step_increment=1))
    s.props.digits = 2
    format_spinbutton_currency(s)
    w = Gtk.Window()
    w.props.border_width = 12
    w.add(s)
    w.show_all()
    w.connect('destroy', Gtk.main_quit)
    Gtk.main()

if __name__ == '__main__':
    _test()

К сожалению, это не работает. Сначала он отображается нормально, но когда я нажимаю на ошибку вверх или вниз, он падает, и я вижу:

/usr/lib/python2.7/dist-packages/gi/types.py:43: Warning: g_value_get_double: assertion `G_VALUE_HOLDS_DOUBLE (value)' failed
  return info.invoke(*args, **kwargs)
Segmentation fault

Любая идея, что означает это сообщение об ошибке?

Или какая часть моего кода может не работать под PyGObject?

Или, еще лучше, как исправить эту ошибку?

Или, что еще лучше, более простое решение моей первоначальной проблемы (отображение $ перед содержимым SpinButton)?


person dumbmatter    schedule 29.01.2012    source источник
comment
Проблема возникает в строке double.value = .... Для меня это похоже на ошибку PyGObject (хотя тот факт, что нам нужно использовать ctypes, сам по себе является ошибкой, ИМХО).   -  person Johannes Sasongko    schedule 29.01.2012


Ответы (2)


Из документации PyGtk:

http://developer.gnome.org/pygtk/stable/class-gtkspinbutton.html#signal-gtkspinbutton--input

«Входной» сигнал выдается при изменении значения. value_ptr — это GPointer на значение, к которому нельзя получить доступ из PyGTK. Этот сигнал не может быть обработан в PyGTK.

Итак, я поражен, увидев что-то вроде:

double = ctypes.c_double.from_address(hash(gpointer))

Это настоящий взлом, поэтому вы получили ужасную ошибку «Ошибка сегментации», что означает, что вы возитесь с памятью, в которой вы не должны, и это довольно общее, это происходит, например, когда в C вы пытаетесь вручную получить доступ к указателю памяти не обрабатывается вашим приложением.

Это будет сложно, я пытался в течение часа, и все подходы, которые я пробовал, имели проблемы. Я знаю, что нет, и отвечаю, но в качестве обходного пути, и если вам нужен только символ валюты (а не группировка), вы можете поэкспериментировать, добавив изображение символа валюты в унаследованный Gtk.Entry set_icon_from_pixbuf():

введите здесь описание изображения

(Очевидно, установите изображение на изображение валюты)

С уважением

person Havok    schedule 10.05.2012
comment
Для справки, вот ошибка pygobject по этому поводу: bugzilla.gnome.org/show_bug.cgi? идентификатор = 644927 - person Marius Gedminas; 09.09.2015

Или, что еще лучше, более простое решение моей первоначальной проблемы (отображение $ перед содержимым SpinButton)?

Я получил это, подключив сигнал GTKSpinButton output к простому обработчику:

    def onSpinOutput(self, spinbutton):
      adjustment = spinbutton.get_adjustment()
      spinbutton.set_text(str(int(adjustment.get_value())) + "%")
      return True

В моем случае я добавляю знак процента после числа, но вы можете легко изменить это, вставив вместо него что-то другое. Обратите внимание, что при этом устанавливается текст, а не значение записи; это не будет работать для цифровых кнопок вращения.

person Ola Tuvesson    schedule 24.01.2021