Button Command with class in Python - python

I'm trying to get this right but so far no luck. Would appreciate it if someone can help me with it.
import tkinter
class MyGUI:
def __init__(self):
self.main_window = tkinter.Tk()
self.button1 = tkinter.Button(self.main_window,text='Average',command=self.average)
self.button1.pack()
tkinter.mainloop()
def average(self):
self.mini_window = tkinter.Tk()
self.avg_mess = tkinter.Label(self.mini_window,text='Results:')
self.avg_result_var = tkinter.StringVar()
self.avg_result_display = tkinter.Label(self.mini_window,textvariable=self.avg_result_var)
self.avg_mess.pack()
self.avg_result_display.pack()
self.button2 = tkinter.Button(self.mini_window,text='Calculate',command=self.avg_calc)
self.button2.pack()
def avg_calc(self):
self.avg_result = (100+300+80)/3
self.avg_result_var.set(self.avg_result)
gui = MyGUI()
The problem occurs when the Calculate button is clicked but the avg_result_var does not change its value. And hence the avg.result_display remains blank. I suspect there is something wrong with the function call when the button is pressed. I'm using Python 3.x. Thanks.

You're almost doing it correctly, but there are a couple of problems
First, the result never changes because you use the same numbers each time you do a calculation. The result is always the same so it appears that it is not changing.
The second problem is that you're creating two instances of Tk. Tkinter isn't designed to work like that, and it causes problems such as the one you are observing. If you need additional pop-up windows, use Toplevel rather than Tk.
Here's a modified version of your program, though I've added a random number in the computation so you can see it change each time.
import Tkinter as tkinter
import random
class MyGUI:
def __init__(self):
self.main_window = tkinter.Tk()
self.button1 = tkinter.Button(self.main_window,text='Average',command=self.average)
self.button1.pack()
tkinter.mainloop()
def average(self):
self.mini_window = tkinter.Toplevel()
self.avg_mess = tkinter.Label(self.mini_window,text='Results:')
self.avg_result_var = tkinter.StringVar()
self.avg_result_display = tkinter.Label(self.mini_window,textvariable=self.avg_result_var)
self.avg_mess.pack(fill="both")
self.avg_result_display.pack()
self.button2 = tkinter.Button(self.mini_window,text='Calculate',command=self.avg_calc)
self.button2.pack()
def avg_calc(self):
x = random.randint(100,200)
self.avg_result = (100+300+x)/3
print "result:", self.avg_result
self.avg_result_var.set(self.avg_result)
gui = MyGUI()

Related

"TclError: Unknown Option" whilst trying to generate 3x3 grid for Noughts and Crosses

I am working on a small noughts and crosses game to help me start off with Python but I keep getting the error: _tkinter.TclError: unknown option "-11BUTTON", how can I fix this.
This is my code to give the error some context:
import ThreadManager
import tkinter as tk
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.CreateWidgets()
def CreateWidgets(self):
ButtonList = []
for x in range(3):
for y in range(3):
self[f'{x+1}{y+1}BUTTON'] = tk.Button(self, text=f'{x+1}{y+1}_BUTTON')
self[f'{x+1}{y+1}BUTTON'].grid(row=x+1,column=y+1)
self.RestartApp = tk.Button(self, text="RESTART", fg="green",
command=self.restart)
self.RestartApp.grid(row=4,column=1)
self.QuitApp = tk.Button(self, text="QUIT", fg="red",
command=self.master.destroy)
self.QuitApp.grid(row=4,column=3)
def Restart():
print('Restarting')
# Start game stuff goes here, I haven't gotten onto this part yet as I've only just started it
Window = tk.Tk()
App = Application(master=Window)
App.mainloop()
Is there anyway I can fix this? I haven't added any game functions yet and ThreadManager is another file which handles some other stuff.
Stuff tried:
Setting the value to None before setting it as a button.
Since your class inherits from tk.Frame, it inherits all of the behavior of a frame widget. Part of that behavior is the fact that self[x] is just a convenient alias for the x attribute (eg: self['width'] = 100 and self.configure(width=100) are synonymous).
The error is telling you that 11BUTTON is not a valid attribute. It's the same error you get if you do self.configure('11BUTTON') = ...
You can't do that with self[...]. Instead, you need to create an instance attribute.
For example:
self.buttons = {}
for x in range(3):
for y in range(3):
self.buttons[f'{x+1}{y+1}BUTTON'] = tk.Button(self, text=f'{x+1}{y+1}_BUTTON')
...
Though, the code would at least arguably be a bit easier to understand if you used a tuple rather than a formatted string:
self.buttons[(x,y)] = tk.Button(...)

getting information from Entry

my name is Rod. I recently started programming with OOP and it's not yet quite clear to me. I want to make my Button get information from my four entries but i don't know how to say to the program to get it from the four of them at the same time. I know i have to use the get() method but i don't understand how to insert it in the class so it will recognize my four Entries. Thanks!
from tkinter import *
from tkinter import ttk
class Application(Frame):
def __init__(self):
Frame.__init__(self)
self.grid()
def createButton(self,b_text,b_command,r,c):
self.newButton = Button(self, text=b_text,command=b_command)
self.newButton.grid(padx=20, pady=10, row=r,column=c)
def createEntry(self,px,r,c):
text = StringVar()
self.newEntry = Entry(self,width=8,textvariable=text)
self.newEntry.grid(padx=px, pady=10,row=r,column=c)
def printEntryData():
#code here
app = Application()
entry1 = app.createEntry(20,0,0)
entry2 = app.createEntry(20,0,1)
entry3 = app.createEntry(20,0,2)
entry4 = app.createEntry(20,0,3)
app.createButton("add",printEntryData,1,6)
app.mainloop()
Every time you make an entry you overwrite the previous value of text. All those previous Entry boxes now are orphans: there's no way to access them to get the information out. (they would have been inaccessible anyway since they are local variables).
Instead, you could add the new StringVars to a container like a list, so that you have access to all of them.
from tkinter import *
from tkinter import ttk
class Application(Frame):
def __init__(self):
Frame.__init__(self)
self.entry_list = []
self.grid()
def createButton(self,b_text,b_command,r,c):
self.newButton = Button(self, text=b_text,command=b_command)
self.newButton.grid(padx=20, pady=10, row=r,column=c)
def createEntry(self,px,r,c):
text = StringVar()
self.newEntry = Entry(self,width=8,textvariable=text)
self.newEntry.grid(padx=px, pady=10,row=r,column=c)
self.entry_list.append(text)
def printEntryData():
for entry in app.entry_list:
print(entry.get())
app = Application()
app.createEntry(20,0,0)
app.createEntry(20,0,1)
app.createEntry(20,0,2)
app.createEntry(20,0,3)
app.createButton("add",printEntryData,1,6)
app.mainloop()

Modifying a Window Class in Tkinter (Python 3)

I've been trying to get to grips with OOP and tkinter in python 3. I'd really like to have sub-windows pop up during use, either for data, output, etc. However, I cannot figure out how to assign the title in my Windows class, depending on what sort of window is being made. Please find a simplified example of what I have done so far.
from tkinter import *
from tkinter import messagebox
class Window(Frame):
def __init__(self, master = None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("ProgramName")
self.pack(fill = BOTH, expand = 1)
menu = Menu(self.master)
self.master.config(menu=menu)
prog_help = Menu(menu)
prog_help.add_command(label='Help', command=self.help_popup)
prog_help.add_command(label='About', command=self.version_popup)
menu.add_cascade(label='Help', menu=prog_help)
#Method 1: Using message.box
def version_popup(self):
messagebox.showinfo("About program", "Version 0.1")
return
#Method 2: Using another window
def help_popup(self):
helpwindow()
return
def helpwindow():
hwindow = Toplevel()
hwindow.geometry("100x100")
root = Tk()
root.geometry("400x300")
app = Window(root)
root.mainloop()
I think that I should be doing something in the definition of helpwindow() which alters a variable in self.master.title(x), but I cannot figure out what.
Many thanks for your time.
In your case, the help window isn't a subclass of anything. All you need to do is call the title method of the Toplevel
def helpwindow():
hwindow = Toplevel()
hwindow.title("I am the help window")
...

Python, Tkinter library, Attribute Error in Object involving GUI

I'm making a very simple program for class that involves multiplying the number of a GUI slider by another number of another GUI slider. But, for some reason when I run the program now, I get an AttributeError saying that 'gui' object has no attribute 'slider1'. Any ideas? Here's the code:
import tkinter
import random
class gui:
def __init__(self):
self.main_window = tkinter.Tk()
#widgets
self.__canvas = tkinter.Canvas(self.main_window,bg='white',width=300,height=10)
self.label = tkinter.Label(self.main_window,text=('Product:',0))
self.slider1 = tkinter.Scale(self.main_window,from_=0, to=12)
self.slider2 = tkinter.Scale(self.main_window,from_=0, to=12)
#packs
self.__canvas.pack()
self.label.pack(side='top')
self.slider1.pack(side='left')
self.slider2.pack(side='right')
self.button = tkinter.Button(self.main_window,text='Click to multiply',command=self.multiply())
self.button.pack(side='bottom')
tkinter.mainloop()
def multiply(self):
x = int(self.slider1.get())
y = int(self.slider2.get())
num = x*y
self.label.config(text=('Product:',num))
gui()
There is a few syntax error in the program, I commented those. As well as you should put orientations on the scales. Here is the code.
import tkinter as tk
class gui:
def __init__(self):
self.root = tk.Tk()
# the widgets
self.button = tk.Button(self.root, text="Multiply!", command=self.multiply)
# you need no '()' for the function when inputing it in tkinter.
self.label = tk.Label(self.root, text="Product: 0") # the '0 must be a string
self.sliderX = tk.Scale(self.root, from_=0, to=12, orient=tk.HORIZONTAL)
self.sliderY = tk.Scale(self.root, from_=0, to=12, orient=tk.VERTICAL)
# add an orient to the scales.
# now pack the widgets.
self.button.pack()
self.label.pack()
self.sliderX.pack()
self.sliderY.pack()
def multiply(self):
x = int(self.sliderX.get())
y = int(self.sliderY.get())
num = str(x * y) # need to turn the int to a string.
self.label.config(text="Product: "+num)
app = gui()
app.root.mainloop()
The reason it isn't working for you is because there is no instance of the program. This is what I do at the very end. Python's garbage collecting collects the instance made with gui() and so Tkinter can't reference an instance of the class.

How to get value from a text field in another module?

I've written a simple program with a tkinter GUI. The entire code is in one big module and I'd like to split it into two or three modules to separate the logic from the GUI.
This is the example code:
main.py:
import gui
inst1 = gui.guitest()
gui.py:
import tkinter, defs
class guitest:
def __init__(self):
win1 = tkinter.Tk()
self.field1 = tkinter.Text(win1)
self.field1.grid(column = 0, row = 0)
self.but1 = tkinter.Button(win1, text='click',
command=defs.getVar)
self.but1.grid(column = 1, row = 0)
win1.mainloop()
defs.py:
def getVar():
captured = str(field1.get(1.0))
I can't get getVar to work; I'd like it to get the value from the Text field, but after trying different solutions all I get are Name or Attribute Errors.
Is there any possibility to make it work that way? Or maybe my idea is completely wrong? If it is, then please let me know how to do it. I wonder if there are more problems with this code.
Alright, let's start from the beginning, here's a working example of your code:
import tkinter
class guitest:
def __init__(self):
win1 = tkinter.Tk()
self.field1 = tkinter.Text(win1)
self.field1.grid(column=0, row=0)
self.but1 = tkinter.Button(win1, text='click', command=self.getVar)
self.but1.grid(column=1, row=0)
win1.mainloop()
def getVar(self):
captured = str(self.field1.get("1.0", tkinter.END))
print captured
inst1 = guitest()
Now, before breaking down that piece of code, you should ask yourself if the reason you want to is strong enough. In case your answer is affirmative (think it twice) one possible way to do it would be this:
# main.py
import gui
inst1 = gui.guitest()
# gui.py
import tkinter
import defs
class guitest:
def __init__(self):
win1 = tkinter.Tk()
self.field1 = tkinter.Text(win1)
self.field1.grid(column=0, row=0)
self.but1 = tkinter.Button(win1, text='click', command=self.getVar)
self.but1.grid(column=1, row=0)
win1.mainloop()
def getVar(self):
defs.getVar(self)
# defs.py
import tkinter
def getVar(guitest_inst):
captured = str(guitest_inst.field1.get("1.0", tkinter.END))
print captured
But again, think twice before breaking down widgets like this... just saying :)

Categories