Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You don't say why you're having a problem using buttons, so I don't know what problem you're trying to solve. Certainly it's possible to create a grid of buttons, and certainly it's possible for buttons to call functions when clicked. </p> <p>To me, the real challenge here is to write code that is compact, understandable, and easy to maintain. You want it to be easy to add new functions and/or new operators without having to rework the whole GUI.</p> <p>Personally I would use an object-oriented approach, creating custom objects that represent numerals, functions and operators. Since you're using a non-OO approach, I recommend creating some helper functions to abstract out some of the details.</p> <p>You have three types of buttons: numbers, operators ("+", "-", etc) and functions ("C", "="). I would create a pair of functions for each type: one function to create the button, and one function to respond to the button. Doing this avoids having a single monolithic function to handle all button presses.</p> <p>I would also add a helper function to lay out the buttons, just to make it easier to visualize the final product in the code.</p> <p>Let's start with the number buttons. We know that all the number button has to do is insert that number into the calculator. So, let's first write a function to do that. In this case I'll assume you have an entry widget to hold the value, since working with canvas text objects is cumbersome:</p> <pre><code>def do_number(n): global entry # the entry where we should insert the number entry.insert("end", n) </code></pre> <p>If we call this function with <code>do_number("3")</code>, it will insert "3" into the calculator. We can use this same function for all of the buttons, all we have to do is pass in what number to insert. You can create similar functions named <code>do_operator</code> and <code>do_function</code>, which take the label of the button and do the appropriate thing. You could just as well have a unique function for each button if you want. </p> <p>To create the button, we want a little helper function that can tie a button to that function. This example uses <code>lambda</code>, but you can use <code>functools.partial</code>, or a function factory. <code>lambda</code> requires the fewest extra steps, so we'll go with that.</p> <pre><code>def number(number): global frame b = Button(frame, text=label, command=lambda: do_number(number)) return b </code></pre> <p>When we call this function like <code>number("4")</code>, it will create a button with "4" as the label. It will also call the function <code>do_number</code> with the number "4" as an argument, so that it will insert the proper string. You can then create similar functions named "operator" and "function" to create buttons that act as operators and those that act as functions.</p> <blockquote> <p>Note 1: I'm generally against using global variables in this manner. Generally speaking it better to pass in the containing frame rather than rely on a global. In this specific case the use of the global makes the code a bit more compact, as you'll see in another paragraph or two. If we were building this calculator as class, we could use an instance variable instead of a global.</p> <p>Note 2: declaring the variable as global here has no real effect. Globals must only be declared when you want to modify the variable. However, I put the global statement in to serve as a declaration that I intend for the variable named <code>frame</code> to be global. This is purely a matter of personal preference</p> </blockquote> <p>So, now we can create buttons of each time, and have them call a function with a unique parameter. Now all that is left is to use <code>grid</code> to organize the buttons. Another helper function will make this easier:</p> <pre><code>def make_row(row, *buttons): for column,button in enumerate(buttons): button.grid(row=row, column=column, sticky="nsew") </code></pre> <p>This helper function lets us pass in a list of buttons, and it will lay them out in a row. Now, combining this with our helper functions to create the buttons, we can create the GUI with something like this:</p> <pre><code>frame = Frame(window, bg="beige") entry = Entry(frame, borderwidth=1, relief="solid") entry.grid(row=0, column=0, columnspan=4, sticky="nsew") make_row(1, number("7"), number("8"), number("9"), operator("/")) make_row(2, number("4"), number("5"), number("6"), operator("*")) make_row(3, number("1"), number("2"), number("3"), operator("-")) make_row(4, number("0"), function("="), function("C"), operator("+")) </code></pre> <p>Notice how it's now possible to see the layout of the buttons in the code. If you want to add another column, add another row, or rearrange the existing buttons, it should be completely self-evident how to do that. </p> <p>Now, of course, this isn't the only way to accomplish this. You can do all of this without helper functions, and just create a few hundred lines of code. By taking a little extra time to break the code down into logical chunks you can create code that is considerably easier to read and maintain.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload