在PyGObject/GTK+3中格式化旋转按钮的显示
我正在把一个应用程序从PyGTK移植到PyGObject。大部分过程都很顺利,因为我在PyGTK中做的事情都是比较常规的。不过,有一个比较麻烦的技巧,我用来把SpinButton的值显示为货币格式(前面加个$)。
这个解决方案最初是我在PyGTK的邮件列表上找到的,那时候还没有Stack Overflow。你可以看到,关键在于输入和输出信号:
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的内容前面显示一个$)?
2 个回答
或者,更好的办法是,有一个更简单的解决方案来解决我最初的问题(在SpinButton内容前面显示一个$符号)?
我通过将GTKSpinButton的output
信号连接到一个简单的处理函数来实现这个功能:
def onSpinOutput(self, spinbutton):
adjustment = spinbutton.get_adjustment()
spinbutton.set_text(str(int(adjustment.get_value())) + "%")
return True
在我的例子中,我是在数字后面加了一个百分号,但你可以很容易地把它改成在前面插入其他东西。请注意,这里设置的是文本而不是数值;这对于数字类型的spin按钮是行不通的。
来自PyGtk文档:
http://developer.gnome.org/pygtk/stable/class-gtkspinbutton.html#signal-gtkspinbutton--input
当数值发生变化时,会发出“输入”信号。value_ptr是一个指向值的指针,但在PyGTK中无法直接访问。这个信号在PyGTK中无法处理。
所以,我看到这样的情况感到很惊讶:
double = ctypes.c_double.from_address(hash(gpointer))
这真是个黑科技,所以你会遇到一个可怕的错误“段错误”,这意味着你在访问不该碰的内存。这种情况很常见,比如在C语言中,你试图手动访问一个你的程序不管理的内存指针。
这会很棘手,我尝试了一个小时,所有的方法都有问题。我知道这不是答案,但作为一种变通方法,如果你只需要货币符号(不需要分组),你可以试着给继承的Gtk.Entry添加一个货币符号的图片,使用set_icon_from_pixbuf():
(显然要把图片换成货币符号的图片)
祝好