I'm in the process of porting an application from PyGTK to PyGObject. Mostly it's going well because mostly I did conventional things with PyGTK. But there's one somewhat ugly hack I was using to display the value of a SpinButton as currency (with a $ in front of it).

I originally got this solution from the PyGTK mailing list back in the days before Stack Overflow. As you can see, the magic happens on the input and output signals:

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

Doing my best to translate that into PyGObject, I came up with:

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

Unfortunately, this doesn't work. It shows up fine initially, but when I click the up or down error, it crashes and I see:

/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

Any idea what this error message means?

Or what part of my code might not work under PyGObject?

Or, better yet, how to fix this error?

Or, even better still, a more straightforward solution to my original problem (displaying a $ in front of the SpinButton contents)?

有帮助吗?

解决方案

From the PyGtk documentation:

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

The "input" signal is emitted when the value changes. The value_ptr is a GPointer to the value that cannot be accessed from PyGTK. This signal cannot be handled in PyGTK.

So, I'm atonished to see something like:

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

This is a real hack, so you got and awful error "Segmentation Fault" which means your are messing in memory you don't have to, and it's quite generic, it happens for example when in C you try to manually access a memory pointer not handled by your application.

This will be a hard one, I tried for one hour and all approaches I tried had problems. I know is not and answer, but as a workaround and if you only need the currency symbol (not grouping) you can experiment adding a currency symbol image to the inherited Gtk.Entry set_icon_from_pixbuf():

enter image description here

(Obviously set the image to a currency image)

Kind regards

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top