Binding zu einer unbekannten Zahl von Checkboxen

Plattformunabhängige GUIs mit wxWidgets.
Antworten
calo
User
Beiträge: 52
Registriert: Freitag 8. Dezember 2006, 21:35
Wohnort: Stuttgart

Hallo,

Ich stehe gerade auf der Leitung und komme einfach nicht weiter. Folgender Code:

Code: Alles auswählen

import wx


class Frame(wx.Frame):

    def __init__(self, parent, id, title, suites):
        wx.Frame.__init__(self, parent, id, title, size=(400, 200))
        self.suites = suites

        self.nb = wx.Notebook(self,-1)
        self.feat_book = feat_nb(self.nb, -1, suites)
        self.nb.AddPage(self.feat_book, "features")


################################################################################
class feat_nb(wx.Panel):
    def __init__(self, parent, id, suite_labels):
        wx.Panel.__init__(self, parent, id)

        self.all_boxes = []
        self.feature_boxes = {}
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        for suite in suite_labels.keys():
            box = self.MakeStaticBoxSizer(suite, suite_labels[suite])
            sizer.Add(box, 0, wx.ALL, 10)
            self.all_boxes.append(box)

        self.SetSizer(sizer)
        sizer.Fit(self)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def MakeStaticBoxSizer(self, suite_label, feat_labels):
        box = wx.StaticBox(self, -1, suite_label)
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

        for label in feat_labels:
            feat = wx.CheckBox(self, -1, label)
            self.feature_boxes[label] = feat
            sizer.Add(feat, 0, wx.ALL)

        return sizer

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def set_CheckBoxes(self, features, suites):
        for feature in features:
            for suite in suites.keys():
                if feature in suites[suite]:
                    self.feature_boxes[feature].SetValue(True)



###############################################################################
class App(wx.App):

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def __init__(self, redirect=False):
        wx.App.__init__(self, redirect)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def OnInit(self):
        self.suites = {"Gruppe 1": ["EINS", "ZWEI", "DREI"], "Gruppe 2": ["VIER", "FUENF", "SECHS", "SIEBEN"]}
        self.features_on_start = ["EINS", "DREI", "FUENF"]

        self.frame = Frame(None, -1, "test", self.suites)
        self.SetTopWindow(self.frame)
        self.frame.Show()       
        self.frame.feat_book.set_CheckBoxes(self.features_on_start, self.suites)

        self.Bind(wx.EVT_CHECKBOX, self.OnEinsCheckbox, self.frame.feat_book.feature_boxes["EINS"])

        return True


    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def OnEinsCheckbox(self, evt):
        print "EINS"        
        

###############################################################################
if __name__=="__main__":
    app = App()
    app.MainLoop()
Ich habe eine unbekannte Anzahl an Suites (Gruppe 1, Gruppe 2). Diese werde aus einer INI-Datei eingelesen. Außerdem habe ich zu jeder Suite eine unbekannte Anzahl an Features (EINS, ZWEI, ...). Für jedes Features/Suite-Kombination erzeuge ich eine Checkbox. Das klappt soweit.

Jetzt möchte ich auch zu jedem Feature eine Ereignis-Funktion schreiben. Dazu benötige ich aber eine dynamisch erstelltes Binding zwischen jeder Checkbox und der dazu gehörenden Funktion:
* EINS --> OnEinsCheckbox()
* ZWEI --> OnZweiCheckbox()
* ...
Rein statisch im Quellcode wäre das ja kein Problem. Aber ich weis halt vorher nicht wieviele Suiten und Features aus der INI-Datei eingelesen werden. Hat mir vielleicht einer von euch einen Tipp?

Calo
tordmor
User
Beiträge: 100
Registriert: Donnerstag 20. November 2008, 10:29
Wohnort: Stuttgart

calo hat geschrieben: Jetzt möchte ich auch zu jedem Feature eine Ereignis-Funktion schreiben. Dazu benötige ich aber eine dynamisch erstelltes Binding zwischen jeder Checkbox und der dazu gehörenden Funktion
Ich kann mir nicht vorstellen, dass dynamisch erzeugte Checkboxen tatsächlich alle eine vollständig unterschiedliche Funktion haben. Also wozu für jede Checkbox eine eigene Funktion?
http://www.felix-benner.com
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

functools.partial ist dein Freund. Mit lambda geht es auch noch, finde ich aber nicht so schön.

Sebastian
Das Leben ist wie ein Tennisball.
calo
User
Beiträge: 52
Registriert: Freitag 8. Dezember 2006, 21:35
Wohnort: Stuttgart

Zugegeben. Für jede Checkbox eine eigene Funktion zu schreiben, macht in meinem speziellen Fall nicht so viel Sinn. Vielleicht ist es Sinnvoller alle Checkboxen mit einem Binding zu verknüpfen:
Klick auf irgend eine Checkbox --> OnClickCheckbox()

Anschließend innerhalb von OnClickCheckbox eine Fallunterscheidung durchführen. In diesem Fall die Frage, wie erzeuge ich ein Binding, das auf alle Checkboxen reagiert:
self.Bind(EVT_CHECKBOX, self.OnClickCheckbox, self.anyCheckbox)

Mir fehlt hier die Verbindung zwischen den einzelnen Checkboxen, die in der Liste feat_book.all_boxes eingefügt wurden und anyCheckbox.
tordmor hat geschrieben:
calo hat geschrieben: Jetzt möchte ich auch zu jedem Feature eine Ereignis-Funktion schreiben. Dazu benötige ich aber eine dynamisch erstelltes Binding zwischen jeder Checkbox und der dazu gehörenden Funktion
Ich kann mir nicht vorstellen, dass dynamisch erzeugte Checkboxen tatsächlich alle eine vollständig unterschiedliche Funktion haben. Also wozu für jede Checkbox eine eigene Funktion?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Tja, hättest du nur meinen Beitrag gelesen ...
Das Leben ist wie ein Tennisball.
tordmor
User
Beiträge: 100
Registriert: Donnerstag 20. November 2008, 10:29
Wohnort: Stuttgart

calo hat geschrieben: Mir fehlt hier die Verbindung zwischen den einzelnen Checkboxen, die in der Liste feat_book.all_boxes eingefügt wurden und anyCheckbox.
Du musst schon für jede Checkbox ein binding machen, aber eben nicht mit unterschiedilchen Funktionen, sondern mit der selben- oder wie EyDu schrieb mit functools.partial.
http://www.felix-benner.com
calo
User
Beiträge: 52
Registriert: Freitag 8. Dezember 2006, 21:35
Wohnort: Stuttgart

@EyDu
Sorry. Ich konnte mit functools.partial erst einmal so rein gar nichts anfangen. Jetzt habe ich mich ein bisschen eingelesen ... und siehe da (ich meine unten) es funktioniert :lol:
EyDu hat geschrieben:Tja, hättest du nur meinen Beitrag gelesen ...

Code: Alles auswählen

# -*- coding: utf-8 -*-
import wx
from functools import partial


class Frame(wx.Frame):

    def __init__(self, parent, id, title, suites, app):
        wx.Frame.__init__(self, parent, id, title, size=(400, 200))
        self.suites = suites
        self.app = app

        self.nb = wx.Notebook(self,-1)
        self.feat_book = feat_nb(self.nb, -1, suites, app)
        self.nb.AddPage(self.feat_book, "features")


################################################################################
class feat_nb(wx.Panel):
    def __init__(self, parent, id, suite_labels, app):
        wx.Panel.__init__(self, parent, id)

        self.app = app
        self.all_boxes = []
        self.feature_boxes = {}
        sizer = wx.BoxSizer(wx.HORIZONTAL)

        for suite in suite_labels.keys():
            box = self.MakeStaticBoxSizer(suite, suite_labels[suite])
            sizer.Add(box, 0, wx.ALL, 10)
            self.all_boxes.append(box)

        self.SetSizer(sizer)
        sizer.Fit(self)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def MakeStaticBoxSizer(self, suite_label, feat_labels):
        box = wx.StaticBox(self, -1, suite_label)
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

        for label in feat_labels:
            feat = wx.CheckBox(self, -1, label)
            self.feature_boxes[label] = feat
            cmd = partial(self.app.OnClickCheckbox, arg=label)
            self.app.Bind(wx.EVT_CHECKBOX, cmd, feat)
            sizer.Add(feat, 0, wx.ALL)

        return sizer

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def set_CheckBoxes(self, features, suites):
        for feature in features:
            for suite in suites.keys():
                if feature in suites[suite]:
                    self.feature_boxes[feature].SetValue(True)



###############################################################################
class App(wx.App):

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def __init__(self, redirect=False):
        wx.App.__init__(self, redirect)

    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def OnInit(self):
        self.suites = {"Gruppe 1": ["EINS", "ZWEI", "DREI"], 
                       "Gruppe 2": ["VIER", "FUENF", "SECHS", "SIEBEN"]}
        self.features_on_start = ["EINS", "DREI", "FUENF"]

        self.frame = Frame(None, -1, "test", self.suites, self)
        self.SetTopWindow(self.frame)
        self.frame.Show()       
        self.frame.feat_book.set_CheckBoxes(self.features_on_start, self.suites)

        return True


    #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    def OnClickCheckbox(self, evt, arg):
        print arg       
       

###############################################################################
if __name__=="__main__":
    app = App()
    app.MainLoop() 
Antworten