Validator reagiert nicht...

Plattformunabhängige GUIs mit wxWidgets.
Antworten
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

ich versuche gerade, mir eine Datumseingabe zu basteln. Dabei soll die Eingabe auf Gültigkeit überprüft werden. Allerdings ruft wx.TextCtrl die darin angegebene Validator-Klasse nicht auf.

Hier der Code:

Code: Alles auswählen

#!/usr/bin/python
#-*- coding: utf-8 -*-

import wx

class Frame(wx.Frame):
    def __init__(self, parent, id, size, pos, title):
        wx.Frame.__init__(self, parent, id, title, pos, size)
        
        self.panel = wx.Panel(self)
        
        self.datlabel = wx.StaticText(parent=self.panel, label="Datum", pos=(10,10))
        self.datum = wx.TextCtrl(parent=self.panel, value="Datum", pos=(80,5), size=(250,-1), 
                                validator=MyValidator())
        self.status = wx.StaticText(parent=self.panel, label="Cancel oder Eingabe?", pos=(80,100))
        
        buttonOK = wx.Button(parent=self.panel, label="OK", pos=(10,250))
        buttonOK.Bind(wx.EVT_BUTTON, self.Ok, buttonOK)
        buttonCANCEL = wx.Button(parent=self.panel, label="Cancel", pos=(100,250))
        buttonCANCEL.Bind(wx.EVT_BUTTON, self.Cancel, buttonCANCEL)
    
    def Ok(self, event):
        self.status.SetLabel("Datumfeld: "+self.datum.GetValue())
    
    def Cancel(self, event):
        self.status.SetLabel("Cancel gedrückt...")

class MyValidator(wx.PyValidator):
     def __init__(self):
         print "init"
         wx.PyValidator.__init__(self)

     def Clone(self):
         print "clone"
         return MyValidator()

     def Validate(self, win):
         print "validate"
         textCtrl = self.GetWindow()
         text = textCtrl.GetValue()

         if len(text) == 0:
             wx.MessageBox("Feld ist leer!", "Error")
             textCtrl.SetBackgroundColour("pink")
             textCtrl.SetFocus()
             textCtrl.Refresh()
             return False
         else:
             textCtrl.SetBackgroundColour(
                 wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
             textCtrl.Refresh()
             return True

     def TransferToWindow(self):
         return True 

     def TransferFromWindow(self):
         return True
         
class App(wx.App):
    def __init__(self):
        wx.App.__init__(self)
    
    def OnInit(self):
        frame = Frame(parent=None, id=-1, size=(600,500), 
                                pos=(500,150), title='KalP')
        frame.Show()        
        return True

if __name__ == '__main__':
    app = App()
    app.MainLoop()
Ich vermute mal, dass es damit zusammenhängt, dass sich das TextCtrl auf dem Panel und nicht in einem Dialogfenster befindet, bzw. beim Drücken des OK-Buttons das TextCtrl-Feld nicht "abgeschickt" wird. Oder so ähnlich... :?

Kann mir jemand helfen, mich aus meiner Sackgasse zu befreien??

Gruß
mutetella
Pekh
User
Beiträge: 482
Registriert: Donnerstag 22. Mai 2008, 09:09

Es gibt da ein Flag, daß du beim style-Attribut des Fensters setzen solltest. WX_VALIDATE_RECURSIVELY oder so ähnlich. Kann es grad nicht nachgucken.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Vielen Dank für den Tipp!! Den entscheidenden Hinweis hab' ich inzwischen in der wyPython Mail-List gefunden. Dort wird nochmals recht gut erklärt, was ich in 'wxPython in Action' leider überlesen hab':
I'm not that far in my study of wxPython but I just looked at Section 9.5 (p. 282 & ss) and I must admit it is not easy reading / understanding, much less even for a non-English speaker. Anyway, reading on p.285:
"The code that explicitly tells the dialog to check the validators is not in the listing - it is part of the wxPython event system. Another difference between dialogs and frames is that dialogs have the validator behavior built-in and frames do not. If you would like to use validators for validating controls not located in a dialog, call the parent window's Validate() method. If the wx.WS_EX_VALIDATE_RECURSIVELY extra style is set for window, Validate() of all the child windows is also called. If any of the validations fail, Validate returns False."
My understanding of the above is the following:
1) Dialogs (via their event system) will automatically call validator(s) if a validator is specified as in the example (validator=NotEmptyValidator()).
2) This is true for controls (e.g. TextCtrl) that are within the dialog box.
3) If the control is placed in another container, say a TextCtrl within a panel belonging to the top level frame, that you must call the Validate() method of the container of that control. In this case the Validate() method of the panel.
4) Frames are different from dialogs and thus there is no automatic check by the frame event system that verifies if there is a need to validate something. In that case you need to call yourself the Validate() method of the widget that contains the control you wish to validate.
Ich habe also die Funktion Ok(), die beim Drücken des Ok-Buttons aufgerufen wird, um die Zeile

Code: Alles auswählen

        self.panel.Validate()
erweitert. Die Funktion sieht demnach folgendermaßen aus:

Code: Alles auswählen

    def Ok(self, event):        
        self.panel.Validate()
        self.status.SetLabel("Datumfeld: "+self.datum.GetValue())

Und siehe da: Alles funktioniert prächtig!

Bin mir nur nicht sicher, ob das so auch "sauber" gelöst ist. Bin für Vorschläge diesbezüglich sehr dankbar!

Gruß
mutetella
Antworten