Catching EVT_CHAR: Verstaendnisproblem

Plattformunabhängige GUIs mit wxWidgets.
Antworten
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Servus,

Ich habe aktuell ein kleines Problem einen gewissen Umstand mit wx.EVT_CHAR zu verstehen und das binden, dieses events an widgets.

Nur ganz grob ohne specifics. Ich wollte ein paar hotkeys einbauen fuer ein applet und habe deswegen als test eine Funktion und eine anbindung an den Frame geschrieben (siehe unten). Das ging aber nicht. Erst als ich es an ein Button widget gebunden habe, in meinem fall

Code: Alles auswählen

self.playButton.Bind(wx.EVT_CHAR, self.onKeyPress) 
hat das ganze funktioniert. danach habe ich aus interesse an radioboxes und text_ctrl gehaengt aber leider kein glueck.

Ich versteh nicht so ganz, wieso ein button widget so viel anders als der rest ist und besonders warum man es nicht einfach an den Frame binden kann. Koennte mir das einer von euch erlaeutern? Das einzige woran ich denken koennte ist, dass das button widget, das erste widget im code ist, das definiert wird, aber ich faende es komisch, wenn das der grund waere.

Der gesamte code ist viel zu lang, deswegen nur der ausschnitt. Die GUI ist nur ein frame und nichts besonderes.

Code: Alles auswählen

    self.Bind(wx.EVT_CHAR, self.onKeyPress)

    # ... later

    def onKeyPress(self, event):
        print 'catching event'
        print event.GetKeyCode()
        
        event.Skip()
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

ok, natuerlich habe ich kurz danach kapiert was da ablaeuft. Sobald das widget in der application im focus ist bzw ausgewaehlt ist, dann wird auch das Event erfasst. Deswegen ging es beim button widget weil beim start des programms automatisch der button ausgewaehlt war.

und fuer die bindung an den frame muesste ich immer einmal ins "Leere" auf der bedienungsoberflaeche klicken, um den frame "auszuwaehlen", damit die Events erwischt werden. Das ist natuerlich nicht sinn der sache. An was muesste ich das Event den binden, damit es erwischt wird, wenn die application ausgewaehlt ist?

das ganze passiert in Windows XP mit python26 und wxpython28.

danke schonmal fuer die hilfe.

Johannes
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Oh boy,

wieso schaffe ich es immer mir solche sachen aufzuhalsen. Danke fuer den link. Ich habe leider keinerlei Erfahrung mit C (oder C++ oder womit wxWidgets bentuzt wird), deswegen bin ich mal gespannt wie gut ich damit zurecht komme ;)

Das hier ist mein lieblingssatz:
if you are trying to catch key events globally it can thus be a little tricky.
very nicely put, indeed :?
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Bin mit Hilfe von BlackJacks schluesselwoertern (key events global), auf das wx.AcceleratorTable widget gestossen

Ich habe es noch nicht ausprobiert, aber das "sollte" angeblich die hotkeys fuer dich handhaben. so bett. gute nacht :)
ntrunk
User
Beiträge: 83
Registriert: Sonntag 7. September 2008, 23:09
Wohnort: Buchen (Odenwald)

Nebelhom hat geschrieben:Bin mit Hilfe von BlackJacks schluesselwoertern (key events global), auf das wx.AcceleratorTable widget gestossen

Ich habe es noch nicht ausprobiert, aber das "sollte" angeblich die hotkeys fuer dich handhaben. so bett. gute nacht :)
Auf meinem System (Python2.6 mit wxWidgets2.8 ) benötigt ein Accelerator im Frame ein Control (z.B. Panel), damit er funktioniert. Wenn du direkt nach dem frame.Show() mit panel.SetFocus() noch den Focus setzt, sparst du dir ausserdem den Klick in das Fenster.
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Hi,

nur um den Thread zu einem Abschluss zu bringen:

Der AcceleratorTable hat mir nicht wirklich weiter geholfen, da, soweit ich es verstanden habe, man damit nur bereits an widgets gebundene funktionen rufen konnte (z.B. play auf play button). Das war in meinem Fall aber leider nicht hilfreich.

Ich habe jetzt eine relativ unelegante variante gefunden, die wenigstens funktioniert. Ich stelle einfach sicher, dass der Focus immer auf einem bestimmten widget ist (egal welches) und daran binde ich mein EVT_CHAR. Das ist nicht wirklich dolle, weil man nach jeder funktion, die ein widget ruft am ende immer widget.SetFocus() rufen muss, aber es tut seine Arbeit.

Danke fuer eure hilfe.

Nebelhom
ntrunk
User
Beiträge: 83
Registriert: Sonntag 7. September 2008, 23:09
Wohnort: Buchen (Odenwald)

Nebelhom hat geschrieben:[...]
Der AcceleratorTable hat mir nicht wirklich weiter geholfen, da, soweit ich es verstanden habe, man damit nur bereits an widgets gebundene funktionen rufen konnte (z.B. play auf play button).
[...]
Nein, nicht wirklich. Hier ein Minimalbeispiel:

Code: Alles auswählen

import wx

class MyFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        # Accelerator für CTRL-t setzen
        testid = wx.NewId()
        acctbl = wx.AcceleratorTable([(wx.ACCEL_CTRL, ord('T'), testid)])
        self.SetAcceleratorTable(acctbl)
        self.Bind(wx.EVT_MENU, self.on_test, id=testid)

        # Damit der Accelerator funktioniert, muss der Focus gesetzt sein;
        # dazu benötigt der Frame ein Control (z.B. ein Panel)
        panel = wx.Panel(self)
        self.Show()
        panel.SetFocus()

    def on_test(self, e):
        wx.MessageBox('Test!')

app = wx.App()
frm = MyFrame(None)
app.MainLoop()
Gruß
Norbert
Nebelhom
User
Beiträge: 155
Registriert: Mittwoch 19. Mai 2010, 01:31

Hi,

@ntrunk: Danke dir fuer die Erlaeuterung. Interessanterweise, habe ich mehr oder minder genau dasselbe ohne AcceleratorTable gemacht. Das Problem war der Focus. Leider wechselt der wenn man auf ein widget klickt, weshalb ich konstant den focus auf das widget haben muss, an das das event gebunden ist (so wie beim AcceleratorTable). Deshalb ist die loesung mit acceleratortable nur eine alternative. Das grundproblem bleibt aber dasselbe.

Ich hatte gehofft, dass der AcceleratorTable global funktioniert (ohne speziellen focus), dem ist aber nicht so. falls interesse da ist, kann ich mal meinen (zugegeben, sehr haesslichen) code posten, sobald ich an meinem PC daheim bin.

Gruss

Nebelhom

EDIT: Gibt es denn bei wxpython einen Befehl, der den Focus fuer die gesamte laufzeit auf ein bestimmtes widget legt? sowas wie SetConstantFocus(), oder so? Sorry, ich fange wieder wieder an von einer besseren Welt zu traeumen :mrgreen:
ntrunk
User
Beiträge: 83
Registriert: Sonntag 7. September 2008, 23:09
Wohnort: Buchen (Odenwald)

@Nebelhom:
Wenn du die AcceloratorTable verwendest, bist du nicht an ein bestimmtes Control gebunden. Lediglich mind. 1 (beliebiges) Control muss vorhanden sein. Du kannst aber auf das Panel beliebig viele weitere Controls legen, die Tastenkombination funktioniert unabhängig davon. Irgendwelche Klimmzüge, um den Focus auf einem Control zu halten sind nicht notwendig.

Gruß
Norbert
Antworten