Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[wxPython ]Problème de Validator pour TxtCtrl déclenché par un bouton

9 réponses
Avatar
loic.mahe
J'essaye d'utilser un Validator pour un TxtCtrl place dand un Panel
avec un bouton
Je souhaite que ce bouton déclenche la validation des données
contenues dans le TxtCtrl

Mais je n'y parviens pas, même après avoir regardé la documentatio
wxPython, la demo wxPython et fait quelques recherches sur Google.

Mon problème est que je ne parviens pas a appeler la méthode
Validate() à partir de mon gestionnaire de bouton.

Quand j'essaye de lancer le programme, j'ai toujours une erreur du
type :
AttributeError: 'Frame' object has no attribute 'Validate'

J'ai essayer d'appeler la méthode Validate() à partir, du bouton, du
panel et à partir d'autres objets, mais sans success pour l'instant.

Si quelqu'un à une idée à propos de mon problème, un morceau de code
qui fonctionne
Avec un panel et un bouton customisé (différent du bouton OK) je suis
preneur !!!

Merci d'avance pour votre aide !!!

Loïc


Voici le code:


#!/usr/bin/env python

import wx

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

def Clone(self):
print "Clone"
return TextObjectValidator()

def Validate(self, win):
print "Validate"
textCtrl = self.GetWindow()
text = textCtrl.GetValue()
if len(text) == 0:
wx.MessageBox("A text object must contain some text!",
"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):
print "TransferToWindow"
return True # Prevent wxDialog from complaining.

def TransferFromWindow(self):
print "TransferFromWindow"
return True # Prevent wxDialog from complaining.


class Frame(wx.Frame):

def __init__(self, parent=None, id=-1, title='<Title here>',
pos=wx.DefaultPosition, size=(400, 200)):
wx.Frame.__init__(self, parent, id, title, pos, size)
self.CenterOnScreen()

panel = wx.Panel(self, -1)
panel.SetBackgroundColour(wx.Colour(255, 255, 255))

fgs = wx.FlexGridSizer(cols=2, vgap=4, hgap=4)

self.label = wx.StaticText(panel, -1, 'word'+":")
self.tc = wx.TextCtrl(panel, -1, 'word', size=(50,-1),
validator=TextObjectValidator() )
fgs.Add(self.label, 1, flag=wx.ALIGN_RIGHT |
wx.ALIGN_CENTER_VERTICAL)
fgs.Add(self.tc, 1, flag=wx.EXPAND|wx.RIGHT, border=25)

b = wx.Button(panel, 2000, "Save" )
fgs.Add(b, 1, flag=wx.EXPAND | wx.RIGHT)
wx.EVT_BUTTON(panel, b.GetId(), self.OnSave)

panel.InitDialog()
panel.SetSizer( fgs )
panel.SetAutoLayout(1)

def OnSave(self, event):
print "OnSave"
### ERROR BELOW:
if self.Validate():
print "Validate OK"
else:
print "Validate KO"
pass


class App(wx.App):

def OnInit(self):
self.frame = Frame()
self.frame.Show()
self.SetTopWindow(self.frame)
return True


def main():
app = App()
app.MainLoop()


if __name__ == '__main__':
main()

9 réponses

Avatar
Michel Claveau, résurectionné d'outre-bombe informatique
Bonsoir !

Je tout débute en wxPython ; je ne comprends rien à la doc, qui n'est pas en
français, ni en occitan.
Alors, petit à petit, je tente de me faire des exemples de codes, à
réutiliser.
C'est long, et galère, mais, j'ai réussi à faire deux ou trois trucs
(mini-mini).

Je ne sais pas, non plus, ce que tu entend par "validator".

Cependant, j'ai fait un essai, de saisie d'un champ, avec récupération du
contenu ; peut-être cet exemple t'aidera-t'il ? Alors le voilà :




import wx
import time

ID_FERMER10
ID_VISU20

class MyFrame(wx.Frame):
def __init__(
self, parent, ID, title, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE
):

wx.Frame.__init__(self, parent, ID, title, pos, size, style)
panel = wx.Panel(self, -1)

bt1 = wx.Button(panel, ID_FERMER, "Fermer")
bt1.SetPosition((15, 15))
self.Bind(wx.EVT_BUTTON, self.quitter, bt1)

bt2 = wx.Button(panel, ID_VISU, "Visu")
bt2.SetPosition((15, 45))
self.Bind(wx.EVT_BUTTON, self.visu, bt2)

wx.StaticText(panel, -1, "Saisir ici :", (150, 30))
fieldsai=wx.TextCtrl(panel, 40, "", (200,30), size=(60, 20))

self.fieldmem=fieldsai



def visu(self, event):
val = self.fieldmem.GetString(0, 255)
wx.MessageBox(str(val), "La valeur saisie est : ")

def quitter(self, event):
self.Destroy()





class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'Ma fenetre avec wxPython', (20,200),
(300,130))
frame.Show(True)
self.SetTopWindow(frame)
return True


app = MyApp(wx.App)
app.MainLoop()
Avatar
ardechou
Salut
voici une réponse pour que ton programme marche , enfin saches que
c'est ma méthode , il doit y en avoir d'autres .....



#*****************************************************************
# tu utilises import wx , pas moi donc je l'ai remplacé
# ça me permet de ne pas utiliser wx. donc d'appeler directement les
wxFrame,
# wxPanel, wxButton ainsi de suite
from wxPython.wx import *
import time

ID_FERMER10
ID_VISU20

class MyFrame(wxFrame):
def __init__(self, parent, ID, title,
pos=wxDefaultPosition,size=wxDefaultSize,
style=wxDEFAULT_FRAME_STYLE):
wxFrame.__init__(self, parent, ID, title, pos, size, style)
panel = wxPanel(self, -1)
bt1 = wxButton(panel, ID_FERMER, "Fermer")
bt1.SetPosition((15, 15))
#~ self.Bind(wx.EVT_BUTTON, self.quitter, bt1)
# j'appelle les evenements de cette manière
EVT_BUTTON(bt1, ID_FERMER, self.quitter)
bt2 = wxButton(panel, ID_VISU, "Visu")
bt2.SetPosition((15, 45))
#même exemple d'événement
EVT_BUTTON(bt2, ID_VISU, self.visu)
#~ self.Bind(wx.EVT_BUTTON, self.visu, bt2)
wxStaticText(panel, -1, "Saisir ici :", (150, 30))
fieldsai=wxTextCtrl(panel, 40, "", (200,30), size=(60, 20))
self.fieldmem=fieldsai

def visu(self, event):
val = self.fieldmem.GetString(0, 255)
wxMessageBox(str(val), "La valeur saisie est : ")

def quitter(self, event):
self.Destroy()

class MyApp(wxApp):
def OnInit(self):
frame = MyFrame(None, -1, 'Ma fenetre avec
wxPython',20,200),(300,130))
frame.Show(True)
self.SetTopWindow(frame)
return True
app = MyApp(wxApp)
app.MainLoop()
#******************************************************


Voilà , je pense que ça marche , chez moi avec python 2.2 pas de
problème
Avatar
Rostok
Bonjour, voila comment je m'y prends


1°) creation du validator ...

class FloatValidator(wxPyValidator):
def __init__(self, chrCurrency=chr(70)):
self.chrCurrency = chrCurrency
wxPyValidator.__init__(self)
EVT_CHAR(self, self.OnChar)

def TransferToWindow(self):
return True

def TransferFromWindow(self):
return True

def Clone(self):
return FloatValidator()

def Validate(self, win):
return True

def OnChar(self, event):
key = event.KeyCode()
if key < WXK_SPACE or key == WXK_DELETE or key > 255:
event.Skip()
return
tc = self.GetWindow()
text = tc.GetValue()
posFrom, posTo = tc.GetSelection()
val = text[:posFrom] + chr(key)
val += text[posTo:]

if self.chrCurrency != (chr(70)):
nb = string.count(val, self.chrCurrency)
if nb > 0:
val2 = string.strip(val)
val = val2[:-1]

if val == "-":
event.Skip()
return

try:
value = float(val)
event.Skip()
except ValueError:
if not wxValidator_IsSilent():
wxBell()

# Returning without calling even.Skip eats the event before it
# gets to the text control
return

==> Tu remarqueras que je n'utilise pas le validate. Je ne comprends pas
moi non plus, il n'est pas appelé !!


2°) passer le validator

self.tcLastPrice.SetValidator(validator=FloatValidator(chr(128)))



Je te laisse adapter la chose ..
A+
Avatar
Michel Claveau, résurectionné d'outre-bombe informatique
Bonjour !

J'utilise wx, simplement parce que c'est comme ça dans la dernière version
de wxPython. Et, perso, je déteste le "from XXX import *" car je suis déjà
tombé sur des conflits de noms de fonctions.

Sinon, mon exemple fonctionnait chez moi (P2.3 & wxPython 2.5.1.5) ; reste
à savoir cela (ta version et/ou la mienne) servira à Lo?c Mah?



Autre chose : Ardechou... Serais-tu ardéchois ?



@-salutations
--
Michel Claveau
mél : http://cerbermail.com/?6J1TthIa8B
sites : http://mclaveau.com http://bergoiata.org http://ponx.org
Avatar
Michel Claveau, résurectionné d'outre-bombe informatique
Bonjour !

Je vois, avec effarement, qu'il me reste énormément de choses à comprendre,
avec wxPython. et, sans doc utilisable (française), ça va pas être triste !

Aussi, je me permet quelques questions :
- Pourquoi intercepter les caractères inférieurs à l'espace ? Si
l'utilisateur se trompe, en saisie, pourra-t'il utiliser le backspace
(chr(8)) ?
- A quoi servent TransferToWindow(self), TransferFromWindow(self) et
Clone(self) (et autres) ?
- Pourquoi utiliser chr(70), plutôt que 'F' ?
- Que se passera-t'il, si l'utilisateur tente de taper (par mégarde) des
espaces, au milieu des chiffres ? il risque d'être bloqué.
- A quoi sert le chr(128) lors de la mise en place du
validator=FloatValidator ?


Bref, je ne comprend pas grand chose...


Merci quand même, car j'ai réussi (par miracle ?) à adapter ton code à mon
exemple, mais cela ne fonctionne qu'à peu près (suffisamment pour que
j'essaie de comprendre) (rappel : wxPython 2.5.1.5 & P2.3) :




import wx
import time

ID_FERMER10
ID_VISU20



class FloatValidator(wx.PyValidator):
def __init__(self, chrCurrency=chr(70)):
self.chrCurrency = chrCurrency
wx.PyValidator.__init__(self)
self.Bind(wx.EVT_CHAR, self.OnChar)

def TransferToWindow(self):
return True

def TransferFromWindow(self):
return True

def Clone(self):
return FloatValidator()

def Validate(self, win):
return True

def OnChar(self, event):
key = event.KeyCode()
if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255:
event.Skip()
return
tc = self.GetWindow()
text = tc.GetValue()
posFrom, posTo = tc.GetSelection()
val = text[:posFrom] + chr(key)
val += text[posTo:]

if self.chrCurrency != (chr(70)):
nb = string.count(val, self.chrCurrency)
if nb > 0:
val2 = string.strip(val)
val = val2[:-1]

if val == "-":
event.Skip()
return

try:
value = float(val)
event.Skip()
except ValueError:
if not wx.Validator_IsSilent():
wx.Bell()



class MyFrame(wx.Frame):
def __init__(
self, parent, ID, title, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE
):

wx.Frame.__init__(self, parent, ID, title, pos, size, style)
panel = wx.Panel(self, -1)


bt1 = wx.Button(panel, ID_FERMER, "Fermer")
bt1.SetPosition((15, 15))
self.Bind(wx.EVT_BUTTON, self.quitter, bt1)

bt2 = wx.Button(panel, ID_VISU, "Visu")
bt2.SetPosition((15, 45))
self.Bind(wx.EVT_BUTTON, self.visu, bt2)

wx.StaticText(panel, -1, "Saisir ici :", (150, 30))
fieldsai=wx.TextCtrl(panel, 40, "", (200,30), size=(60, 20))
fieldsai.SetValidator(validator=FloatValidator(chr(128)))

self.fieldmem=fieldsai


def visu(self, event):
val = float(self.fieldmem.GetString(0, 255))
wx.MessageBox(str(val), "La valeur saisie est : ")

def quitter(self, event):
self.Destroy()





class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'Ma fenetre avec wxPython', (20,200),
(300,130))
frame.Show(True)
self.SetTopWindow(frame)
return True


app = MyApp(wx.App)
app.MainLoop()
Avatar
Rostok
Je vais certainement te décevoir

Michel Claveau, résurectionné d'outre-bombe informatique wrote:
Bonjour !

Je vois, avec effarement, qu'il me reste énormément de choses à comprendre,
avec wxPython. et, sans doc utilisable (française), ça va pas être triste !

Aussi, je me permet quelques questions :
- Pourquoi intercepter les caractères inférieurs à l'espace ? Si
l'utilisateur se trompe, en saisie, pourra-t'il utiliser le backspace
(chr(8)) ?
oui

pkoi chai plus !

- A quoi servent TransferToWindow(self), TransferFromWindow(self) et
Clone(self) (et autres) ?
Je ne sais plus. Mais si je me souviens bien j'ai pompé tout ca sur le

site wiki python fait une recherche sur google tu devrais trouvé. Cerise
: c'est en francais !!!
- Pourquoi utiliser chr(70), plutôt que 'F' ?
chais plus


- Que se passera-t'il, si l'utilisateur tente de taper (par mégarde) des
espaces, au milieu des chiffres ? il risque d'être bloqué.
non ca marche, mais c'est vrai qu'il y a quelques bugs. Je viens de

m'appercevoir que d et e passe entre les chiffres

Je suis allé tres (trop)vite en programmant, pour une petite appli simple


- A quoi sert le chr(128) lors de la mise en place du
validator=FloatValidator ?
c'est pour mon appli c'est le caractère "Euro" et j'ai surtout un bug

dans ce cas la car il faut absolument effacer le symbole euro pour modifier

A+

Avatar
Michel Claveau, résurectionné d'outre-bombe informatique
Bonsoir !

Ton message m'aura au moins permis de réviser ma conjugaison du verbe savoir
:-)))
Avatar
Loïc Joly
Michel Claveau, résurectionné d'outre-bombe informatique wrote:

Bonsoir !


Chalut

Ton message m'aura au moins permis de réviser ma conjugaison du verbe savoir
:-)))



Chavoir

--
Loïc

Avatar
loic.mahe
Merci à tous pour toutes vos réponses !
Mais mon problème exact était plutôt de savoir
comment appeler la méthode Validate() définie
dans le Validator, à partir de la fonction gérant les événements liés
au bouton ?

Je viens de trouver la solution à mon problème,
et je vous la poste ci dessous :

La ligne de code pour appeler Validate est la suivante :
self.tc.GetValidator().Validate(self.tc)
C'est assez tordu et pas très beau …
Si vous avez une meilleure solution … je suis preneur

Le code complet est à la fin de ce post !

Juste quelques explications avant :

* TransferToWindow(self) sert à transférer les données contenues dans
la fenêtre ou contrôle vers une structure de donnée
* TransferFromWindow(self) sert à transférer les données contenues
dans une structure de donnée vers la fenêtre ou contrôle
* Clone(self) est nécessaire au fonctionnement interne des Validators
est est normalement obligatoire




Voici le code complet qui fonctionne :

Pour voir le fonctionnement du validator,
Il faut effacer les caractères contenus dans le TxtCtrl puis appuyer
sur le bouton ….

Et voilà !!!

A+

Loïc



#!/usr/bin/env python

import wx

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

def Clone(self):
print "Clone"
return TextObjectValidator()

def Validate(self, win):
print "Validate"
textCtrl = self.GetWindow()
text = textCtrl.GetValue()
if len(text) == 0:
wx.MessageBox("A text object must contain some text!",
"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):
print "TransferToWindow"
self.GetWindow().SetValue("aaa")
return True # Prevent wxDialog from complaining.

def TransferFromWindow(self):
print "TransferFromWindow"
print self.GetWindow().GetValue()
return True # Prevent wxDialog from complaining.


class Frame(wx.Frame):

def __init__(self, parent=None, id=-1, title='<Title here>',
pos=wx.DefaultPosition, size=(400, 200)):
wx.Frame.__init__(self, parent, id, title, pos, size)
self.CenterOnScreen()

panel = wx.Panel(self, -1)
panel.SetBackgroundColour(wx.Colour(255, 255, 255))

fgs = wx.FlexGridSizer(cols=2, vgap=4, hgap=4)

self.label = wx.StaticText(panel, -1, 'word'+":")
# self.tc = wx.TextCtrl(panel, -1, 'word', size=(50,-1),
validator=TextObjectValidator() )
self.tc = wx.TextCtrl(panel, -1, '', size=(50,-1),
validator=TextObjectValidator() )
fgs.Add(self.label, 1, flag=wx.ALIGN_RIGHT |
wx.ALIGN_CENTER_VERTICAL)
fgs.Add(self.tc, 1, flag=wx.EXPAND|wx.RIGHT, border%)

b = wx.Button(panel, 2000, "Save" )
fgs.Add(b, 1, flag=wx.EXPAND | wx.RIGHT)
wx.EVT_BUTTON(panel, b.GetId(), self.OnSave)

panel.InitDialog() ### call TransferToWindow of panel objects
panel.SetSizer( fgs )
panel.SetAutoLayout(1)

def OnSave(self, event):
print "OnSave"
if self.tc.GetValidator().Validate(self.tc) and
self.tc.GetValidator().TransferFromWindow():
print "Validate OK"
else:
print "Validate KO"
pass


class App(wx.App):

def OnInit(self):
self.frame = Frame()
self.frame.Show()
self.SetTopWindow(self.frame)
return True


def main():
app = App()
app.MainLoop()


if __name__ == '__main__':
main()