Search code examples
pythonwxpython

Do not bind a file entry in Bind to wx. Button buttons in the loop


Greetings to the respected community!

I have the following task: I need to create a panel with buttons whose names are taken from the file (all_classes). When clicking on each label, the buttons must be recorded in another file (chosen_classes). I managed to create buttons in the loop and arrange them on the panel, but the recording event to the button is not tied and I do not understand why.

all_classes = open('data/yolo2/yolo2.names', 'r').read().split()
chosen_classes = open('chosen_classes', 'w')

deltaxSize, deltaySize, c = 0, 0, 0
        for k, obj_class in enumerate(all_classes):
            self.buttons.append(wx.Button(self.panel, label=f'{obj_class}', pos=(50 + deltaxSize, 20 + deltaySize),
                                       size=(100, 20)))
            self.Bind(wx.EVT_BUTTON, lambda event: chosen_classes.write(f'{obj_class}\n'), self.buttons[k])
            deltaySize += 20
            c += 1
            if c == 30:
                deltaxSize += 100
                deltaySize, c = 0, 0

I tried instead of recording in the lambda just prints to check what was going on, but got a strange result: when you press any button, only the last label is displayed:

deltaxSize, deltaySize, c = 0, 0, 0
        self.buttons = []
        for k, obj_class in enumerate(all_classes):
            self.buttons.append(wx.Button(self.panel, label=f'{obj_class}', pos=(50 + deltaxSize, 20 + deltaySize),
                                       size=(100, 20)))
            self.Bind(wx.EVT_BUTTON, lambda event: print(f'{obj_class}\n'), self.buttons[k])
            deltaySize += 20
            c += 1
            if c == 30:
                deltaxSize += 100
                deltaySize, c = 0, 0

The same happens if you replace obj_class in the f-line with self.buttons [k]. GetLabelText () At the same time, if you turn to each button separately outside the loop, you can print the label, but the file still does not record. I am completely, admittedly, perplexed, if anyone can suggest anything, I would be infinitely grateful. Thanks.


Solution

  • You have managed to over complicate your solution a bit.
    The use of a sizer will make this easier and because the only event being fired is a button event and they all do the same thing, we only need to bind it once.
    Pick the bones out of the following, it should help.

    import wx
    
    all_classes = ["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]
    chosen_classes = open('chosen_classes.txt', 'w')
    
    class ButtonPanel(wx.Panel):
        def __init__(self, parent, *args, **kwargs):
            super().__init__(parent, *args, **kwargs)
            self.sizer = wx.BoxSizer(wx.VERTICAL)
            self.SetSizer(self.sizer)
            self.parent = parent
    
            for k, obj_class in enumerate(all_classes):
                self.add_button(obj_class)
            self.Bind(wx.EVT_BUTTON, self.OnButton)
            self.parent.Layout()
    
        def add_button(self, obj_class):
            self.sizer.Add(wx.Button(self, label=f'{obj_class}'), 0, wx.EXPAND, 0)
    
        def OnButton(self,event):
            obj = event.GetEventObject()
            label = obj.GetLabel()
            chosen_classes.write(label+" Pressed\n")
            print(label)
    
    class MyPanel(wx.Panel):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
    
            self.button_panel = ButtonPanel(self)
    
            sizer = wx.BoxSizer(wx.HORIZONTAL)
            sizer.Add(self.button_panel, 0, wx.EXPAND, 0)
            self.SetSizer(sizer)
    
    class MyFrame(wx.Frame):
        def __init__(self, *args):
            super().__init__(*args)
            panel = MyPanel(self)
    
    
    app = wx.App()
    frame = MyFrame(None)
    frame.Show()
    
    app.MainLoop()
    

    enter image description here