2010-07-16 47 views
5

wx.SpinCtrl est limité à la rotation sur des entiers, et non sur des flottants. Par conséquent, je construis une classe combo wx.TextCtrl + wx.SpinButton qui me permet de faire tourner les flotteurs. Je suis en mesure de dimensionner et de mettre en page les deux par programme afin que le combo ressemble exactement à un wx.SpinCtrl ordinaire.wxPython: "Super" wx.SpinCtrl avec valeurs flottantes, disposition à l'intérieur du calibreur

Je sous-classe ce combo à partir du wx.TextCtrl car je souhaite que son panneau parent capture les événements wx.EVT_TEXT. J'apprécierais que vous puissiez améliorer cet argument.

Les événements wx.EVT_SPIN_UP et wx.EVT_SPIN_DOWN provenant du wx.SpinButton sont des implémentations internes et le cadre parent ne tient pas compte de ces événements.

Maintenant, je viens de frapper un mur de briques. Ma classe de combo ne fonctionne pas bien avec les calibreurs. Après .Add() la classe combo à wx.GridBagSizer, seul le wx.TextCtrl est disposé dans le wx.GridBagSizer. Le wx.SpinButton est laissé seul. Les liaisons wx.EVT_SPIN* fonctionnent très bien, cependant.

Mon problème est la disposition. Comment dois-je écrire la classe si je veux que le wx.GridBagSizer le traite comme un widget?

Voici mon code de classe combo:

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) 

Répondre

3

Vous devez passer outre DoGetBestSize() si vous voulez que votre commande soit correctement géré par calibreurs. Jetez un oeil à CreatingCustomControls.

Vous pouvez également jeter un oeil à FloatSpin fourni avec wxPython (dans wx.lib.agw) à partir de la version 2.8.9.2.

En réponse à vos commentaires:

  • mise en œuvre DoGetBestSize() ne nécessite pas de dessin bitmaps directement. Vous avez juste besoin de trouver un moyen, comment vous pouvez déterminer la meilleure taille de votre nouveau widget. Généralement, vous utiliseriez simplement comme base des deux widgets dont il est composé (texte + spinner).
  • Pour permettre aux calibreurs de traiter deux widgets en même temps, vous pouvez les placer dans un autre calibreur.
  • La manière recommandée pour implémenter un widget personnalisé avec wxPython est de dériver votre nouveau widget depuis wx.PyControl, d'y ajouter un sizer et d'ajouter les deux widgets que vous souhaitez combiner à ce sizer.
+0

D'accord, je vais jeter un oeil à 'wx.lib.agw.FloatSpin'. A propos de l'autre lien que vous m'avez donné (CreatingCustomControls), il faut directement dessiner des bitmaps, ce que je ne suis pas prêt à faire pour le moment. Y a-t-il une procédure dans wxPython qui permet à un calibreur de traiter deux widgets en un?Il devrait être similaire à la fonction de groupe lors du dessin de nombreux objets dans MS Word. – Kit

+0

'FloatSpin' semble prometteur :) Mais ce' wx.PyControl' avec un 'wx.Sizer' contenant mes' wx.TextCtrl' et 'wx.SpinButton' est vraiment intéressant. Je rencontre des problèmes avec '.SetSizer (sizer)' 'wx.PyControl', mais ce serait une autre question. Merci pour le temps, Ralph! – Kit

1

Comme mentionné dans les commentaires de Kit, FloatSpin est maintenant le chemin à parcourir.

Il a été intégré dans les versions récentes.

Voici un exemple simple d'utilisation:

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