54075

How can I execute more a command based on the Button that called it? (Classes and tkinter)

Question:

I am teaching myself Python and am currently working on my first project. I am making a calculator application in Python which I am calling Pythulator. I am trying to figure out how to concatenate the number pad's respective number to a number string whenever the button is pressed. I created a class called numpad that stores my number pad, and I got it to display on the GUI, but whenever I press a number on the number pad, nothing is printed in the console. Here is the code:

#!/usr/bin/python3 """Pythulator Version 1.0.0""" import math import tkinter as tk from decimal import Decimal, getcontext numstring = "" class Numpad: global numstring def __init__(self, master): num_frame = tk.Frame(master) num_frame.pack(side = tk.BOTTOM) self.numpad_1 = tk.Button(num_frame, text = "1", command = self.concat) self.numpad_1.grid(row = 6, column = 3) self.numpad_2 = tk.Button(num_frame, text = "2", command = self.concat) self.numpad_2.grid(row = 6, column = 4) self.numpad_3 = tk.Button(num_frame, text = "3", command = self.concat) self.numpad_3.grid(row = 6, column = 5) self.numpad_4 = tk.Button(num_frame, text = "4", command = self.concat) self.numpad_4.grid(row = 5, column = 3) self.numpad_5 = tk.Button(num_frame, text = "5", command = self.concat) self.numpad_5.grid(row = 5, column = 4) self.numpad_6 = tk.Button(num_frame, text = "6", command = self.concat) self.numpad_6.grid(row = 5, column = 5) self.numpad_7 = tk.Button(num_frame, text = "7", command = self.concat) self.numpad_7.grid(row = 4, column = 3) self.numpad_8 = tk.Button(num_frame, text = "8", command = self.concat) self.numpad_8.grid(row = 4, column = 4) self.numpad_9 = tk.Button(num_frame, text = "9", command = self.concat) self.numpad_9.grid(row = 4, column = 5) self.numpad_0 = tk.Button(num_frame, text = "0", command = self.concat) self.numpad_0.grid(row = 7, column = 4) def concat(self): self = str(self) numstring.join(self) print(numstring) root = tk.Tk() obj = Numpad(root) root.geometry("400x400") root.mainloop()

I'm thinking the reason nothing prints in the console when I press one of the number pad buttons, when it calls the concat function, there is nothing to concatenate since the variable isn't equivalent to a string. Is there anyway I could assign each button a string to concatenate? I tried creating a function in the class for each number pad button that assigns it a string, but that took up far too much space and I only want to do it with one or two functions.

Answer1:

This method is highly problematic:

def concat(self): self = str(self) numstring.join(self) print(numstring)

You have not defined __str__ so str(self) is going to be some funky string. Then numstring.join(self) is a no-operation -- it returns a string you're not assigning to anything at all! So you're always printing the empty numstring you started with.

And -- nowhere are you taking into account <strong>which</strong> key has been pressed... <strong>any</strong> keypress triggers exactly the same self.concat call, no info left about "which key was it again?".

functools.partial lets you bind arguments in advance (yes, you <strong>could</strong> do with a bedraggled lambda, but, you'll be a <strong>much</strong> happier camper if you forget about lambda's existence...).

So for example one button should be...:

self.numpad_1 = tk.Button(num_frame, text='1', command=functools.partial(self.concat, '1'))

and similarly for the others.

Now, the concat method will receive the text corresponding to the button that was clicked and of course it needs to record it somewhere.

I'd recommend eschewing globals and instead starting the __init__ with

self.nums = []

Now concat has an easy life:

def concat(self, digit): self.nums.append(digit) print(''.join(self.nums))

Incidentally, this lets you far more easily implement key features such as a delete key -- it just needs to drop the last item of the self.nums list (self.nums.pop() will suffice) and it's crucial to let the user correct a typo!

Answer2:

You can use lambda to make another function that call the original method with additional parameter

In addition to that, you need to declare global variable inside the method. To append a string to another string, you can use += operator.

class Numpad: def __init__(self, master): num_frame = tk.Frame(master) num_frame.pack(side = tk.BOTTOM) self.numpad_1 = tk.Button(num_frame, text="1", command=lambda: self.concat('1')) self.numpad_1.grid(row=6, column=3) self.numpad_2 = tk.Button(num_frame, text="2", command=lambda: self.concat('2')) self.numpad_2.grid(row=6, column=4) self.numpad_3 = tk.Button(num_frame, text="3", command=lambda: self.concat('3')) self.numpad_3.grid(row=6, column=5) self.numpad_4 = tk.Button(num_frame, text="4", command=lambda: self.concat('4')) self.numpad_4.grid(row=5, column=3) self.numpad_5 = tk.Button(num_frame, text="5", command=lambda: self.concat('5')) self.numpad_5.grid(row=5, column=4) self.numpad_6 = tk.Button(num_frame, text="6", command=lambda: self.concat('6')) self.numpad_6.grid(row=5, column=5) self.numpad_7 = tk.Button(num_frame, text="7", command=lambda: self.concat('7')) self.numpad_7.grid(row=4, column=3) self.numpad_8 = tk.Button(num_frame, text="8", command=lambda: self.concat('8')) self.numpad_8.grid(row=4, column=4) self.numpad_9 = tk.Button(num_frame, text="9", command=lambda: self.concat('9')) self.numpad_9.grid(row=4, column=5) self.numpad_0 = tk.Button(num_frame, text="0", command=lambda: self.concat('0')) self.numpad_0.grid(row=7, column=4) def concat(self, n): global numstring numstring += n print(n, numstring)

Recommend

  • web scrape with rvest
  • finding symmetric difference/unique elements in multiple arrays in javascript
  • Gruntfile.js - Throwing error 'Recursive process.nextTick detected\"
  • How to start server for Selenium grid Java Maven setup
  • Redirect to trailng slash (htaccess)
  • Allocating a 2D contiguous array within a function
  • How to make nicEditor snaplet? (Several questions)
  • Problem in concatenation of objects in javascript
  • Is there a Windows socket API call / option to “block” a range of ports à la SO_EXCLUSIVEADDRUSE
  • Dynamically load css stylesheet and wait for it to load
  • Enumerating Controls on a Form
  • ggplot2: make the points on the line a darker color than the line color
  • Retrieving specified columns from a list of csv files to create a data data frame in R
  • For loop with if condition on multiple R functions
  • order post according to custom array position
  • as3-flash: any way to access all the instances placed in different frames from document class?
  • Ember.js model to be organised as a tree structure
  • wxPython: displaying multiple widgets in same frame
  • Jackson Parser: ignore deserializing for type mismatch
  • OpenGL ES texture problem, 4 duplicate columns and horizontal lines (Android)
  • Android fill_parent issue
  • Avoid links criss cross / overlap in d3.js using force layout
  • how to adjust image in a panel in Java swing?
  • R - Combining Columns to String Based on Logical Match
  • Jenkins: How To Build multiple projects from a TFS repository?
  • What is the “return” in scheme?
  • How do I fake an specific browser client when using Java's Net library?
  • MySQL WHERE-condition in procedure ignored
  • jquery mobile loadPage not working
  • Web-crawler for facebook in python
  • How can I estimate amount of memory left with calling System.gc()?
  • Properly structure and highlight a GtkPopoverMenu using PyGObject
  • Apache 2.4 - remove | delete | uninstall
  • Run Powershell script from inside other Powershell script with dynamic redirection to file
  • trying to dynamically update Highchart column chart but series undefined
  • How can I get HTML syntax highlighting in my editor for CakePHP?
  • embed rChart in Markdown
  • Unable to use reactive element in my shiny app
  • java string with new operator and a literal
  • jQuery Masonry / Isotope and fluid images: Momentary overlap on window resize