在PyGObject/GTK+3中格式化旋转按钮的显示

1 投票
2 回答
1506 浏览
提问于 2025-04-17 11:19

我正在把一个应用程序从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 个回答

0

或者,更好的办法是,有一个更简单的解决方案来解决我最初的问题(在SpinButton内容前面显示一个$符号)?

我通过将GTKSpinButton的output信号连接到一个简单的处理函数来实现这个功能:

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

在我的例子中,我是在数字后面加了一个百分号,但你可以很容易地把它改成在前面插入其他东西。请注意,这里设置的是文本而不是数值;这对于数字类型的spin按钮是行不通的。

3

来自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()

在这里输入图片描述

(显然要把图片换成货币符号的图片)

祝好

撰写回答