wxPython: «Super» wx.SpinCtrl со значениями с плавающей точкой, макет внутри sizer - PullRequest
5 голосов
/ 16 июля 2010

wx.SpinCtrl ограничен вращением через целые числа, а не с плавающей точкой. Поэтому я создаю комбо-класс wx.TextCtrl + wx.SpinButton, который позволяет мне вращаться через поплавки. Я могу измерить и разметить их оба программно, чтобы комбо выглядело точно так же, как обычный wx.SpinCtrl.

Я создаю подкласс этого комбо из wx.TextCtrl, потому что я хочу, чтобы его родительская панель перехватила wx.EVT_TEXT события. Буду признателен, если вы улучшите мой аргумент.

События wx.EVT_SPIN_UP и wx.EVT_SPIN_DOWN из wx.SpinButton являются внутренними реализациями, и родительский фрейм не заботится об этих событиях.

Теперь я только что ударился о кирпичную стену. Мой комбо-класс плохо работает с классификаторами. После .Add() преобразования комбо-класса в wx.GridBagSizer, только wx.TextCtrl располагается внутри wx.GridBagSizer. wx.SpinButton оставлен сам по себе. Однако привязки wx.EVT_SPIN* работают очень хорошо.

Моя проблема в макете. Как мне написать класс, если я хочу, чтобы wx.GridBagSizer рассматривал его как один виджет?

Вот мой код класса комбо:

class SpinnerSuper(wx.TextCtrl):
  def __init__(self, parent, max):
    wx.TextCtrl.__init__(self, parent=parent, size=(48, -1))
    spin = wx.SpinButton(parent=parent, style=wx.SP_VERTICAL, size=(-1, 21))
    self.OnInit()
    self.layout(spin)
    self.internalBindings(spin)
    self.SizerFlag = wx.ALIGN_CENTER

    self.min = 0
    self.max = max

  def OnInit(self):
    self.SetValue(u"0.000")

  def layout(self, spin):
    pos = self.GetPosition()
    size = self.GetSize()
    RightEdge = pos[0] + size[0]
    TopEdge = pos[1] - (spin.GetSize()[1]/2 - size[1]/2)
    spin.SetPosition((RightEdge, TopEdge))

  def internalBindings(self, spin):
    spin.Bind(wx.EVT_SPIN_UP, self.handlerSpinUp(self), spin)
    spin.Bind(wx.EVT_SPIN_DOWN, self.handlerSpinDown(self), spin)

  def handlerSpinUp(CallerObject, *args):
    def handler(CallerObject, *data):
        text = data[0]
        prev = text.GetValue()
        next = float(prev) + 0.008
        text.SetValue("{0:0.3f}".format(next))
    return lambda event: handler(CallerObject, *args)

  def handlerSpinDown(CallerObject, *args):
    def handler(CallerObject, *data):
        text = data[0]
        prev = text.GetValue()
        next = float(prev) - 0.008
        text.SetValue("{0:0.3f}".format(next))
    return lambda event: handler(CallerObject, *args)

Ответы [ 2 ]

4 голосов
/ 16 июля 2010

Вам необходимо переопределить DoGetBestSize (), если вы хотите, чтобы ваш элемент управления правильно управлялся с помощью sizer.Взгляните на creationCustomControls .

Вы также можете взглянуть на FloatSpin , который поставляется с wxPython (в wx.lib.agw) начиная с версии 2.8.9.2 и выше..

В ответ на ваши комментарии:

  • Реализация DoGetBestSize () не требует непосредственного рисования растровых изображений.Вам просто нужно найти способ, как вы можете определить лучший размер вашего нового виджета.Обычно вы просто используете размеры двух виджетов, из которых он состоит (text + spinner) в качестве основы.
  • Чтобы позволить классификаторам обрабатывать два виджета как один, вы можете поместить их в другой классификатор.
  • Рекомендованным способом реализации пользовательского виджета с помощью wxPython является получение вашего нового виджета из wx.PyControl, добавление в него классификатора и добавление двух виджетов, которые вы хотите объединить, в этот классификатор.
1 голос
/ 22 декабря 2016

Как упомянуто в комментариях Кита, FloatSpin теперь путь.

Он был интегрирован в последние версии.

Вот простой пример использования:

import wx
from wx.lib.agw.floatspin import FloatSpin

class Example_FloatSpin(wx.Frame):
    def __init__(self, parent, title):
        super(Example_FloatSpin, self).__init__(parent, title=title, size=(480, 250))
        panel = wx.Panel(self)

        vbox = wx.BoxSizer(wx.VERTICAL)
        spin = FloatSpin(panel, value=0.0, min_val=0.0, max_val=8.0, increment=0.5, digits=2, size=(100,-1))
        vbox.Add(spin, proportion=0, flag=wx.CENTER, border=15)
        panel.SetSizer(vbox)

        self.Centre()
        self.Show() 


if __name__ == '__main__':
    app = wx.App()
    Example_FloatSpin(None, title='Check FloatSpin')
    app.MainLoop()
...