-1

I need to store the value of a button that was clicked into a variable. So I need to connect the button with the variable how can I do that? Here are my variables:

    self.first_num = 0
    self.second_num = 0
    self.result = 0
    self.operation = ""

And then I need to use them in this function e.g. in an addition:

    def equal_clicked(self, result):
    if self.operation == "plus":
        self.result = self.first_num + self.second_num
        self.entry.set_text(self.result)

    def button2_clicked(self, button2):
    self.entry.set_text(self.entry.get_text() + str(2))

I hope this is enough code to show you my problem and i would appreciate an answer.

    button5 = Gtk.Button(label="5")
    button5.connect("clicked", self.button_clicked)
    vbox.pack_start(button5, True, True, 0)
    vbox.pack_end(button5, True, True, 0)
    self.add(button5)
Rise Blink
  • 121
  • 1
  • 13
  • I assume you're making something like a calculator? I'm not sure what you mean by the value of a button as buttons can't hold values, but if you mean use the number from each number button, just set up a callback function that connects to the `clicked` signal, then initialize your variables with a static number hardcoded into each callback. – oldtechaa Dec 23 '16 at 13:06
  • So i added the function for the button with the number of "2". Do i have to initialize the variables in that function? Or am I assuming wrong? And btw yes I am working on a calculator. – Rise Blink Dec 23 '16 at 13:16
  • that would work. You could also use your original plan and just set `self.first_num` to two when that button is clicked. The answer looks like it should work though. I don't use Python so I don't have experience in Python lambdas. – oldtechaa Dec 24 '16 at 00:00

1 Answers1

1

I make GUI applications for work a lot. The main idea is to bind a single function to each button, but pass in a different variable with each button.

Here is a full example for Python Gtk:

import pygtk
import gtk

class Example:
    def __init__(self):
        #Setup window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_border_width(10)
        self.boxSizer = gtk.HBox(False, 0)

        #Create widgets
        self.button1     = gtk.Button("1")
        self.button2     = gtk.Button("2")
        self.button3     = gtk.Button("3")
        self.buttonPlus  = gtk.Button("+")
        self.buttonEqual = gtk.Button("=")
        self.entry       = gtk.Entry(max=0)

        #Bind Events to a single function
        #You would do this for every button. 
        #The first parameter in the connect() function is the name, 
        #the second is the function you are binding, 
        #and the third is the argument we are passing into the function.
        self.button1.connect("clicked", self.button_clicked, 1)
        self.button2.connect("clicked", self.button_clicked, 2)
        self.button3.connect("clicked", self.button_clicked, 3)
        self.buttonPlus.connect("clicked", self.button_clicked, "+")
        self.buttonEqual.connect("clicked", self.button_clicked, "=")

        #Build Window
        self.window.add(self.boxSizer)
        self.boxSizer.pack_start(self.button1, True, True, 0)
        self.boxSizer.pack_start(self.button2, True, True, 0)
        self.boxSizer.pack_start(self.button3, True, True, 0)
        self.boxSizer.pack_start(self.buttonPlus, True, True, 0)
        self.boxSizer.pack_start(self.buttonEqual, True, True, 0)
        self.boxSizer.pack_start(self.entry, True, True, 0)

        #Show objects
        self.button1.show()
        self.button2.show()
        self.button3.show()
        self.buttonPlus.show()
        self.buttonEqual.show()
        self.entry.show()
        self.boxSizer.show()
        self.window.show()

    def button_clicked(self, widget, value):
        """Your first function and second function could be combined like this.
        What this would do is have a single function that is bound to each button. 
        The arguments passed into it would be different for each button.

        Despite using the 'evil eval' function, I figure this is the route you are going.

        This removes the need to (1) have a different function for each button, 
        and (2) you do not need to store values in variables like this:
            self.first_num = 0
            self.second_num = 0
            self.operation = ""

        Your code will be cleaner and easier to modify for future projects.
        """
        if (value != None):
            if (value != "="):
                #Add something to the text
                self.entry.set_text(self.entry.get_text() + str(value))
            else:
                #Evaluate the text
                self.result = eval(self.entry.get_text())
                self.entry.set_text(str(self.result))
        else:
            #Clear the text
            self.entry.set_text("")

    def main(self):
        gtk.main()

if __name__ == "__main__":
    example = Example()
    example.main()

This concept should work for any GUI creation package. Some packages may take a bit more work than others, though. For example, wxPython does not let you pass arguments into functions. You can get around this limitation by doing what "Florian Bosch" says on Is it possible to pass arguments into event bindings?. (Note: This method should work for any GUI package that does not allow you to pass arguments into bound functions)

For, wxPython: Bind all of your buttons like this:

self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "1"), button1)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "2"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "3"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "4"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "5"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "6"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "7"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "8"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "9"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "0"), button2)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "+"), buttonAdd)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "-"), buttonSubtract)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "*"), buttonMultiply)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "/"), buttonDivide)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, "="), buttonEqual)
self.Bind(wx.EVT_BUTTON, lambda event: button_clicked(event, None), buttonClear)

(Use this part: lambda event: button_clicked(event, "1") in place of where you would normally connect a button to a function.)


The idea here, regardless of the GUI module used, is to bind a single function to all of your calculator's buttons and just pass in a different value for each button.

Community
  • 1
  • 1
Kade
  • 901
  • 13
  • 18
  • So I added the defintion of one button to my question. Is this the right way to go? And I do not understand how or where I define the value in the button_clicked function? And btw thanks for the answer. – Rise Blink Dec 29 '16 at 14:43
  • I did a bit of research into Python Gtk. Looks like it is easier to bind functions than it is for wxPython. I added some more information to my answer. – Kade Jan 03 '17 at 15:44
  • Thanks for the answer. So I tried using the code and I changed some things around but it does not work. For me this is the solution I just need to change something. Have you tried the code? – Rise Blink Jan 03 '17 at 16:40
  • I have changed my code a bit you can see it above. Thats how I binded my buttons previously. – Rise Blink Jan 04 '17 at 08:54
  • I downloaded Python Gtk and created a working simple example for you. I hope this helps. – Kade Jan 04 '17 at 15:50
  • Thanks so much you helped me al lot. – Rise Blink Jan 05 '17 at 08:27