Search code examples
pythonwxpython

SpinCtrl with step increment value


I'm trying to create a custom SpinCtrl with a step increment. It seems like such a simple thing so I was surprised the native SpinCtrl doesn't appear to have this functionality, and Google proves uncommonly useless in this matter as well.

When I try to make a custom one, however, I run into problems. Here's some quick and dirty code

class SpinStepCtrl( wx.SpinCtrl ):
    def __init__( self, *args, **kwargs ):
        super( SpinStepCtrl, self ).__init__( *args, **kwargs )

        self.step = 99

        self.Bind( wx.EVT_SPINCTRL, self.OnSpin )
        #self.Bind( wx.EVT_SPIN_UP, self.OnUp )
        #self.Bind( wx.EVT_SPIN_DOWN, self.OnDown )

    def OnSpin( self, event ):
        print 'X'
        self.SetValue( self.GetValue() + self.step )

The print is just there so I can see what, if anything, happens. The EVT_SPIN_UP and EVT_SPIN_DOWN events don't seem to work at all, at least the callbacks are never called which is why I took them out.

When using EVT_SPINCTRL, the callback is called, but end up in an infinite loop because SetValue apparently causes a new such event to be called. It doesn't help much either way, because I can't find a way of telling whether it was a spin up or spin down event, so I can't change the value appropriately.

How do I get this to work?


Solution

  • OK, not the best, but works on Ubuntu:

    #!/usr/bin/python
    import wx
    
    class SpinStepCtrl(wx.SpinCtrl):
        def __init__(self, *args, **kwargs):
            wx.SpinCtrl.__init__(self, *args, **kwargs)
            self.step = 99
            self.last_value = 0
            self.Bind(wx.EVT_SPINCTRL, self.OnSpin)
    
        def OnSpin(self, event):
            delta = self.GetValue() - self.last_value
            if delta == 0:
                return
            elif delta > 0:
                self.last_value = self.GetValue() + self.step
            else:
                self.last_value = self.GetValue() - self.step
            self.SetValue(self.last_value)
    
    class MainWindow(wx.Frame):
        def __init__(self, *args, **kwargs):
            wx.Frame.__init__(self, *args, **kwargs)
            self.panel = wx.Panel(self)
            self.spin = SpinStepCtrl(self.panel, min=0, max=1000)
            self.Show()
    
    app = wx.App(False)
    win = MainWindow(None)
    app.MainLoop()
    

    Still, I would consider "self.SetValue" generating "wx.EVT_SPINCTRL" a bug.