EVT_KILL_FOCUS Event abfangen

Plattformunabhängige GUIs mit wxWidgets.
Antworten
darkG0D
User
Beiträge: 10
Registriert: Montag 10. April 2006, 19:00

Hallo.

Als Einsteiger habe ich folgendes Problem: Ich möchte, ein SpinCtrl und einen Slider haben, deren Werte sich gegenseitig aktualisieren (wxPython 2.6.3.0, Python 2.4, winXP SP2).

Das klappt soweit auch. Wenn man in dem SpinCtrl allerdings von Hand eine Zahl eingibt und das SpinCtrl dann mit Tab verlässt, wird der Slider nicht aktualisiert.

Ich wollte das so lösen, indem ich auf den EVT_KILL_FOCUS event reagiere. Leider klappt dies nicht, wie ich es mir vorstelle.

Mit der Erzeugung des Dialogs mache ich vermutlich auch noch etwas falsch, da sich das Programm - auch bei Schließen des angezeigten Dialogs - nicht beendet.

Bild

Für jede Hilfe oder jeden Hinweis bin ich dankbar.

Hier der Code:

Code: Alles auswählen

import wx
import wx.xrc as xrc

class AppFrame(wx.Frame):
    def OnKill(self, event):
        b = wx.MessageBox("KILL!!")
    
    def OnSpin(self, event):
        print self.spin.GetValue()
        self.slider.SetValue(self.spin.GetValue())
    
    def OnScrollChanged(self, event):
        self.spin.SetValue(self.slider.GetValue())
        print 'sliding'
    
    def __init__(self):
        wx.Frame.__init__( self,
                          None, -1, "",
                          style=wx.DEFAULT_FRAME_STYLE )
        
        res = xrc.XmlResource('slider.xrc')
        
        dialog = res.LoadDialog(self, "ID_DIALOG")
        
        self.slider = wx.xrc.XRCCTRL(dialog, 'ID_SLIDER')
        self.spin = wx.xrc.XRCCTRL(dialog, 'ID_SPINCTRL')
        
        dialog.Bind(wx.EVT_SPINCTRL, self.OnSpin, self.spin)
        dialog.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged, self.slider)
        dialog.Bind(wx.EVT_KILL_FOCUS, self.OnKill, self.spin)
        
        dialog.Show(True)


app = wx.PySimpleApp()
frame = AppFrame()
app.MainLoop()
und das dazugehörige .XRC file (slider.xrc)

Code: Alles auswählen

<?xml version="1.0" encoding="windows-1252"?>
<resource version="2.3.0.1" xmlns="http://www.wxwidgets.org/wxxrc">
    <object class="wxDialog" name="ID_DIALOG">
        <style>wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU|wxCLOSE_BOX</style>
        <exstyle>wxWS_EX_BLOCK_EVENTS</exstyle>
        <size>400,300</size>
        <title>slider</title>
        <centered>1</centered>
        <object class="wxBoxSizer">
            <orient>wxVERTICAL</orient>
            <object class="sizeritem">
                <flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>
                <border>5</border>
                <object class="wxSpinCtrl" name="ID_SPINCTRL">
                    <style>wxSP_ARROW_KEYS</style>
                    <value>0</value>
                    <min>0</min>
                    <max>100</max>
                </object>
            </object>
            <object class="sizeritem">
                <flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>
                <border>5</border>
                <object class="wxSlider" name="ID_SLIDER">
                    <style>wxSL_HORIZONTAL</style>
                    <value>0</value>
                    <min>0</min>
                    <max>100</max>
                </object>
            </object>
        </object>
    </object>
</resource>
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Hallo,

1.) das Frame wird nicht angezeigt und damit nicht geschlossen.
Daher beendet sich das Programm nicht (ordnungsgemäß).

2.
in dialog init, die Zeile änderte ich auf:

Code: Alles auswählen

self.spin.Bind(wx.EVT_KILL_FOCUS, self.OnKill)
und OnKill:

Code: Alles auswählen

    def OnKill(self, event):
        #b = wx.MessageBox("KILL!!")
        self.slider.SetValue(self.spin.GetValue())

das ganze also:

Code: Alles auswählen

import wx
import wx.xrc as xrc

class AppFrame(wx.Frame):
    def OnKill(self, event):
        #b = wx.MessageBox("KILL!!")
        self.slider.SetValue(self.spin.GetValue())
   
    def OnSpin(self, event):
        print self.spin.GetValue()
        self.slider.SetValue(self.spin.GetValue())
   
    def OnScrollChanged(self, event):
        self.spin.SetValue(self.slider.GetValue())
        print 'sliding'
   
    def __init__(self):
        wx.Frame.__init__( self,
                          None, -1, "",
                          style=wx.DEFAULT_FRAME_STYLE )
       
        res = xrc.XmlResource('slider.xrc')
       
        dialog = res.LoadDialog(self, "ID_DIALOG")
       
        self.slider = wx.xrc.XRCCTRL(dialog, 'ID_SLIDER')
        self.spin = wx.xrc.XRCCTRL(dialog, 'ID_SPINCTRL')
       
        dialog.Bind(wx.EVT_SPINCTRL, self.OnSpin, self.spin)
        dialog.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged, self.slider)
        self.spin.Bind(wx.EVT_KILL_FOCUS, self.OnKill)
       
        dialog.Show(True)


app = wx.PySimpleApp()
frame = AppFrame()
frame.Show(True)
app.MainLoop()
darkG0D
User
Beiträge: 10
Registriert: Montag 10. April 2006, 19:00

Danke für die schnelle Antwort.

Punkt 2. hatte ich nach einiger Zeit auch herausgefunden. Mir ist allerdings noch nicht ganz klar, wie ich vorgehen muss, wenn ich einen Dialog anzeigen möchte, den ich aus einem XRC File generiere (leider habe ich keine Dokumentation hierzu gefunden und die Demo von wxPython ist mir leider keine große Hilfe, da dort keine "selbstständige" Applikation gezeigt wird, sondern eine, die in einem Tab der "Demo-Applikation" läuft.

Für den Hinweis, wie ich das Programm umändern muss, damit nur der Dialog angezeigt wird, wäre ich sehr dankbar (ich nehme an, ich muss gar nicht von wx.Frame ableiten, evtl. von wx.App?).

Wenn ich von wx.App ableite, dann werden Fehlermeldungen bei mir nicht mehr in der Konsole angezeigt, sondern es öffnet sich ein graphisches Fenster, indem die Fehlermeldungen angezeigt werden. Leider schließt sich das Fenster aber sofort wieder, so dass ich nicht weiß, was für (syntaktische) Fehler mein Code noch enthält und ich ihn als Folge dessen auch nicht zum Laufen bekomme.
Wie kann ich es bewerkstelligen, dass ich dieses Fehlerfenster immer sehe (ich benutze Eclipse, aber auch aus einer Python-Shell heraus ist das Verhalten identisch).

Vielen Dank!
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

darkG0D hat geschrieben:Danke für die schnelle Antwort.

Punkt 2. hatte ich nach einiger Zeit auch herausgefunden. Mir ist allerdings noch nicht ganz klar, wie ich vorgehen muss, wenn ich einen Dialog anzeigen möchte, den ich aus einem XRC File generiere (leider habe ich keine Dokumentation hierzu gefunden und die Demo von wxPython ist mir leider keine große Hilfe, da dort keine "selbstständige" Applikation gezeigt wird, sondern eine, die in einem Tab der "Demo-Applikation" läuft.

Für den Hinweis, wie ich das Programm umändern muss, damit nur der Dialog angezeigt wird, wäre ich sehr dankbar (ich nehme an, ich muss gar nicht von wx.Frame ableiten, evtl. von wx.App?).
Das ist richtig.
Mit dem XRC kenne ich mich zwar nicht aus,
aber ich habe das Programm mal folgendermassen geändert.
Weiss nicht, ist wahrscheinlich nicht die schönste Lösung, aber
es funktioniert:

Code: Alles auswählen

import wx
import wx.xrc as xrc

class MyDlgApp:
    def OnKill(self, event):
        #b = wx.MessageBox("KILL!!")
        self.slider.SetValue(self.spin.GetValue())
   
    def OnSpin(self, event):
        print self.spin.GetValue()
        self.slider.SetValue(self.spin.GetValue())
   
    def OnScrollChanged(self, event):
        self.spin.SetValue(self.slider.GetValue())
        print 'sliding'
   
    def __init__(self):
        res = xrc.XmlResource('slider.xrc')
       
        dialog = res.LoadDialog(None, "ID_DIALOG")
       
        self.slider = wx.xrc.XRCCTRL(dialog, 'ID_SLIDER')
        self.spin = wx.xrc.XRCCTRL(dialog, 'ID_SPINCTRL')
       
        dialog.Bind(wx.EVT_SPINCTRL, self.OnSpin, self.spin)
        dialog.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged, self.slider)
        self.spin.Bind(wx.EVT_KILL_FOCUS, self.OnKill)
       
        dialog.ShowModal()


#app = wx.PySimpleApp()
app = wx.App() #genuegt auch
mydlg = MyDlgApp()
mydlg.dialog.Destroy()
app.MainLoop()
darkG0D hat geschrieben: Wenn ich von wx.App ableite, dann werden Fehlermeldungen bei mir nicht mehr in der Konsole angezeigt, sondern es öffnet sich ein graphisches Fenster, indem die Fehlermeldungen angezeigt werden. Leider schließt sich das Fenster aber sofort wieder, so dass ich nicht weiß, was für (syntaktische) Fehler mein Code noch enthält und ich ihn als Folge dessen auch nicht zum Laufen bekomme.


Wie kann ich es bewerkstelligen, dass ich dieses Fehlerfenster immer sehe (ich benutze Eclipse, aber auch aus einer Python-Shell heraus ist das Verhalten identisch).

Vielen Dank!

Für solche Fälle ist es am besten,
wx.App(redirect=0) oder wx.App(0) aufzurufen.
Antworten