how to use a variable with a GUI in python 3 - python

I'm trying to get this so when you press 'HELLO' five time the text turn red
just its not adding any thing on when i add anything to the viable.this is the code.
from tkinter import *
class application(Frame):
global t
t=1
def info(self):
print ("test")
global t
t=t+5
def createWidgets(self):
global t
t=t
self.exet= Button(self)
self.exet["text"] = "QUIT"
self.exet["fg"] = "red"
self.exet["command"] = self.quit
self.exet.pack({"side": "left"})
self.hi = Button(self)
self.hi["text"] = "HELLO",
if t == 5:
self.hi["fg"] = "red"
self.hi["command"] = self.info
self.hi.pack({"side": "left"})
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
Thanks to anyone helps!

You have a couple of problems here: First, you use a global variable and then you include it within the scope of your functions. Instead of this, you should use an instance variable (self.t, or even self.counter for better readability). Secondly, you are checking the value of the counter in createWidgets, which is only called once by the __init__ method. You should increase and check its value in the event handler function on the button.
class application(Frame):
def info(self):
self.counter += 1
print(self.counter)
if self.counter == 5:
self.hi["fg"] = "red"
def createWidgets(self):
self.counter = 0
self.exet= Button(self)
self.exet["text"] = "QUIT"
self.exet["fg"] = "red"
self.exet["command"] = self.quit
self.exet.pack({"side": "left"})
self.hi = Button(self)
self.hi["text"] = "HELLO",
self.hi["command"] = self.info
self.hi.pack({"side": "left"})
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()

Related

How to change row-'value' every time i try to position a label using grid?

I am trying to create a terminal GUI using python tkinter module and I already managed to access the tk.Label from TextFrame class.
class TextFrame(tk.Frame):
def __init__(self, container):
super().__init__()
self.container = container
self['bg']='black'
self.pack(fill='both', expand=True)
self.label = tk.Label(self)
Now the problem is that, I can't change the row everytime I call show() function inside Instances class.
class Instances(Window):
def __init__(self):
super().__init__()
self.string = tk.StringVar()
self.index_row = 0
self.text_frame = TextFrame(self)
self.text_frame.pack()
self.entry_frame = EntryFrame(self)
self.entry_frame.pack(side='bottom',fill='both')
def show(self, e):
textvar = self.string.get()
self.entry_frame.entry.delete(0, 'end')
self.text_frame.label.config(text=textvar)
self.text_frame.label.grid(column=0, row=self.index_row, sticky="w")
self.index_row += 1
Here is the full code of my problem:
import tkinter as tk
class Window(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry('800x600')
self.title('Terminal')
class Instances(Window):
def __init__(self):
super().__init__()
self.string = tk.StringVar()
self.index_row = 0
self.text_frame = TextFrame(self)
self.text_frame.pack()
self.entry_frame = EntryFrame(self)
self.entry_frame.pack(side='bottom',fill='both')
def show(self, e):
textvar = self.string.get()
self.entry_frame.entry.delete(0, 'end')
self.text_frame.label.config(text=textvar)
self.text_frame.label.grid(column=0, row=self.index_row, sticky="w")
self.index_row += 1
class TextFrame(tk.Frame):
def __init__(self, container):
super().__init__()
self.container = container
self['bg']='black'
self.pack(fill='both', expand=True)
self.label = tk.Label(self)
class EntryFrame(tk.Frame):
def __init__(self, container):
super().__init__()
self.entry = tk.Entry(self, textvariable=container.string)
self.entry.pack(fill='both')
self.entry.bind('<Return>', container.show)
if __name__ == '__main__':
window = Instances()
window.mainloop()
Any help would be appreciated.
Problem Solved
I added 1 line of code on show() function
def show(self, e):
textvar = self.string.get()
self.entry_frame.entry.delete(0, 'end')
self.text_frame.label = tk.Label(self.text_frame, fg='green', bg='black')
self.text_frame.label.config(text=textvar)
if len(textvar) > 0 :
self.text_frame.label.grid(column=0, row=self.index_row, sticky="w")
self.index_row += 1

Make a Tkinter Gui using classes

I want to create a GUI in a class that can create pages using another class that creates frames and widgets. The pages are set using a class for them. I want to be able to GUI to be able to switch between the different set of pages. I can't create a button for the class of the Login_page that with switch the Login_page with the class of the Sign_page.
from tkinter import *
import random
class maingui:
def __init__(self,title, geometry,):
self.root = Tk()
self.root.title(title)
self.root.geometry(geometry)
self.pageshow = Login_Page(self.root)
self.root.mainloop()
def changepage(self, page):
self.page = page
if self.page == 0:
self.pageshow = Login_Page(self.root)
if self.page == 1:
self.pageshow = Sign_Page(self.root)
self.root.mainloop()
class createWindow:
def __init__(self,root, title, geometry,):
self.root = root
self.root.title(title)
self.root.geometry(geometry)
self.root.mainloop()
class createFrame:
def __init__(self,window):
self.window = window
self.frame = Frame(self.window)
self.frame.pack()
print('c')
def clear(self):
pass
def createlabel(self,message,postion = None):
self.message =message
self.postion = postion
self.label= Label(self.frame, text =self.message)
if self.postion == None:
self.label.pack()
print('a')
else:
print('b')
def createbutton(self, text, command):
self.text = text
self.command = command
self.button = Button(self.frame, text = self.text, command =self.command)
class Login_Page():
def __init__(self,window):
self.window = window
self.frame = createFrame(self.window)
self.frame.createlabel("Hello World")
self.frame.createbutton("1",maingui.changepage(self.window,1))
class Sign_Page():
def __init__(self,window):
self.window = window
self.frame = createFrame(self.window)
self.frame.createlabel("Hello ")
maingui = maingui("Rpg", "400x400")
Edit: Exception has occurred: AttributeError
'_tkinter.tkapp' object has no attribute 'root'
On line
if self.page == 1:
self.pageshow = Sign_Page(self.root)
On this line
self.frame.createbutton("1",maingui.changepage(self.window,1))
I try to create a button using a class and the command is from a different class.
Since you pass self.root (instance of Tk()) of maingui class to Login_Page and assign it to self.window. Then self.window is used in maingui.changepage(self.window, 1) inside Login_Page class. Since you use class name to access changepage(), self.window will be treat as the self argument of changepage() and used in Sign_Page(self.root). That means you want to access the attribute root of self (instance of Tk()) but Tk does not have attribute root.
Suggest to make maingui interit from Tk instead of creating it inside __init__().
Below is an updated example based on yours:
from tkinter import *
#import random
class maingui(Tk):
def __init__(self, title, geometry):
super().__init__()
self.title(title)
self.geometry(geometry)
self.pageshow = Login_Page(self)
def changepage(self, page):
self.page = page
if self.page == 0:
self.pageshow = Login_Page(self)
if self.page == 1:
self.pageshow = Sign_Page(self)
class createFrame:
def __init__(self,window):
self.window = window
self.frame = Frame(self.window)
self.frame.pack()
print('c')
def clear(self):
pass
def createlabel(self,message,postion = None):
self.message =message
self.postion = postion
self.label= Label(self.frame, text =self.message)
if self.postion == None:
self.label.pack()
print('a')
else:
print('b')
def createbutton(self, text, command):
self.text = text
self.command = command
self.button = Button(self.frame, text = self.text, command =self.command)
self.button.pack() ###
class Login_Page():
def __init__(self,window):
self.window = window
self.frame = createFrame(self.window)
self.frame.createlabel("Hello World")
###self.frame.createbutton("1", maingui.changepage(self.window, 1)) ###
self.frame.createbutton("1", lambda: self.window.changepage(1)) ###
class Sign_Page():
def __init__(self,window):
self.window = window
self.frame = createFrame(self.window)
self.frame.createlabel("Hello ")
maingui = maingui("Rpg", "400x400")
maingui.mainloop()
Here is a working code, I would also suggest you read and practice classes before moving further.
(Note: I have not defined your clear method or added any new method, I have just corrected your existing code and rectified your error. you may further if you want, define your clear method and destroy your widgets).
from tkinter import *
import random
class maingui:
def __init__(self, root, title, geometry):
self.root = root
self.root.title(title)
self.root.geometry(geometry)
self.pageshow = Login_Page(self, self.root)
def changepage(self, page):
self.page = page
if self.page == 0:
self.pageshow = Login_Page(self, self.root)
if self.page == 1:
self.pageshow = Sign_Page(self, self.root)
class createWindow:
def __init__(self,root, title, geometry):
self.root = root
self.root.title(title)
self.root.geometry(geometry)
class createFrame:
def __init__(self, parent, window):
self.window = window
self.frame = Frame(self.window)
self.frame.pack()
self.label = Label(self.frame)
self.button = Button(self.frame)
self.parent = parent
def clear(self):
pass
def createlabel(self,message,postion = None):
self.message =message
self.postion = postion
self.label.config(text=self.message)
if self.postion == None:
self.label.pack()
else:
pass
def createbutton(self, text='Login', cmd=0):
self.text = text
self.button.configure(text=self.text, command=lambda :self.parent.changepage(cmd))
self.button.pack()
class Login_Page():
def __init__(self, parent, window):
self.window = window
self.frame = createFrame(parent, self.window)
self.frame.createlabel("Hello World bye")
self.frame.createbutton("Welcome", 1)
class Sign_Page():
def __init__(self, parent, window):
self.window = window
self.frame = createFrame(parent, self.window)
self.frame.createlabel("Hello ")
def main():
root = Tk()
maingui(root, "Rpg", "400x400")
root.mainloop()
if __name__ =='__main__':
main()
update: here is a way you can switch between pages(in my case you can switch between the sign-up and login page). click on login it will direct you to sign-up and vice-versa.
from tkinter import *
import random
class maingui:
def __init__(self, root, title, geometry):
self.root = root
self.root.title(title)
self.root.geometry(geometry)
self.pageshow = Login_Page(self, self.root)
def changepage(self, page):
self.page = page
if self.page == 0:
#del self.pageshow
self.pageshow = Login_Page(self, self.root)
if self.page == 1:
#del self.pageshow
self.pageshow = Sign_Page(self, self.root)
class Login_Page:
def __init__(self, parent, window):
self.parent = parent
self.frame = Frame(window)
self.frame.pack()
self.welcm_lbl = Label(self.frame, text='welcome')
self.welcm_lbl.grid(row=0, column=1)
self.name_lbl = Label(self.frame, text='name:')
self.name_lbl.grid(row=1, column=0)
self.name_entry = Entry(self.frame)
self.name_entry.grid(row=1, column=1)
self.sbt = Button(self.frame, text='login', command=self.clicked)
self.sbt.grid(row=2, column=1)
def clicked(self):
self.frame.destroy()
self.parent.changepage(1)
class Sign_Page():
def __init__(self, parent, window):
self.parent = parent
self.frame = Frame(window)
self.frame.pack()
self.welcm_lbl = Label(self.frame, text='welcome sign-up')
self.welcm_lbl.grid(row=0, column=1)
self.name_lbl = Label(self.frame, text='name:')
self.name_lbl.grid(row=1, column=0)
self.name_entry = Entry(self.frame)
self.name_entry.grid(row=1, column=1)
self.sbt = Button(self.frame, text='sign-up', command=self.clicked)
self.sbt.grid(row=2, column=1)
def clicked(self):
self.frame.destroy()
self.parent.changepage(0)
def main():
root = Tk()
maingui(root, "Rpg", "400x400")
root.mainloop()
if __name__ =='__main__':
main()

Tkinter passing callback function result to another class

I wonder how to pass return value from one class to another class in tkinter.
In my program I have DataChosenForm class where I want to choose option in Combobox and pass this result to another class ReturnData to set a variable in a Label.
import tkinter as tk
from tkinter import ttk
class DataChosenForm(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
chosen = tk.LabelFrame(self, text="wybór")
chosen.grid(row=0)
self.combo = ttk.Combobox(chosen)
self.combo['values'] = ('wizz', 'ryanair', 'lot')
self.combo.grid(row=0, column=2, padx=80, pady=10)
self.combo.bind("<<ComboboxSelected>>", self.callback)
def callback(self, event=None):
if event.widget.get() == 'wizz':
print('wizz')
return 'wizz'
elif event.widget.get() == 'ryanair':
print('ryanair')
return 'ryanair'
elif event.widget.get() == 'lot':
print('lot')
return 'lot'
class ReturnData(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
var = tk.StringVar()
message_box = tk.LabelFrame(self, text="wynik")
message_box.grid(row=1)
mb = tk.Label(message_box, textvariable=var,anchor='nw')
mb.pack(padx=120, pady=30)
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.title("program do wyszukiwania cen lotów")
self.geometry('300x200')
self.resizable(width=False, height=False)
DataChosenForm(self).grid(row=0, column=0)
ReturnData(self).grid(row=1)
if __name__ == "__main__":
app = Application()
app.mainloop()
You could first display the combobox DataChosenForm(self).grid(row=0, column=0) without calling the ReturnData in the Application class.
Then, in the callback() method collect the choice choice = event.widget.get() and pass it to ReturnData. This would mean, however, that the LabelFrame is displayed only after a choice is made.
import tkinter as tk
from tkinter import ttk
class DataChosenForm(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
chosen = tk.LabelFrame(self, text="wybór")
chosen.grid(row=0)
self.combo = ttk.Combobox(chosen)
self.combo['values'] = ('wizz', 'ryanair', 'lot')
self.combo.grid(row=0, column=2, padx=80, pady=10)
self.combo.bind("<<ComboboxSelected>>", self.callback)
def callback(self, event=None):
choice = event.widget.get()
print(choice)
ReturnData(self, choice).grid(row=1)
class ReturnData(tk.Frame):
def __init__(self, parent, choice):
super().__init__(parent)
message_box = tk.LabelFrame(self, text="wynik")
message_box.grid(row=1)
mb = tk.Label(message_box, text=choice, anchor='nw')
mb.pack(padx=120, pady=30)
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.title("program do wyszukiwania cen lotów")
self.geometry('300x200')
self.resizable(width=False, height=False)
DataChosenForm(self).grid(row=0, column=0)
if __name__ == "__main__":
app = Application()
app.mainloop()
I think #Julia has the basically the right architecture for your tkinter application, but her answer could be improved by using a tkinter Variable — because all widgets associated with one will automatically update their displayed value whenever the Variable is changed (by one of them or something else).
Here's a little documentation on Variable Classes. Note that since ttk.Combobox with have all the methods of a tk.Entry widgets, here's a bit of documentation about them (which also happens to illustrate the "pattern" of using of a StringVar in conjunction with one so it also applies to a ttk.Comboboxs).
Generally, you can tell a widget to use a tkinter Variable by specifying an instance of one as the option textvariable= keyword argument when the widget is created. You can also set the option using the partial dictionary interface most widgets support, so assignments like widget['textvariable'] = variable are another way to make use of them — the code below makes use of both of these ways.
Here's Julia's code modified to use a tk.StringVar. Note the Combobox doesn't need a callback function to bind the <<ComboboxSelected>> event to it, so all that complexity has been eliminated.
import tkinter as tk
from tkinter import ttk
class DataChosenForm(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
choice = tk.LabelFrame(self, text="wybór")
choice.grid(row=0)
self.combo = ttk.Combobox(choice)
self.combo['textvariable'] = parent.var # Use shared variable.
self.combo['values'] = ('wizzair', 'ryanair', 'lot')
self.combo.grid(row=0, column=2, padx=80, pady=10)
class ReturnData(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
message_box = tk.LabelFrame(self, text="wynik")
message_box.grid(row=1)
mb = tk.Label(message_box, textvariable=parent.var, # Use shared variable.
anchor='nw', width=20)
mb.pack(padx=120, pady=30)
class Application(tk.Tk):
def __init__(self):
super().__init__()
self.title("program do wyszukiwania cen lotów")
self.geometry('300x200')
self.resizable(width=False, height=False)
self.var = tk.StringVar(value='Dokonać wyboru') # Create shared variable.
DataChosenForm(self).grid(row=0, column=0)
ReturnData(self).grid(row=1)
if __name__ == "__main__":
app = Application()
app.mainloop()
You can just pass other class or it's field to __init__ of the DataChosenForm, and to callback function from there, where then you can change class/field directly. Here's what I mean, but I use TreeView:
import tkinter as tk
from tkinter import ttk
class ConnectedClass:
def __init__(self):
self.received = "will be changed"
class TreeViewWrapper(ttk.Treeview):
def __init__(self, master, connected_class, **kw):
super().__init__(master, **kw)
parents = []
for i in range(10):
parent = self.insert("", "end", text="Item %s" % i, tags=str(i))
for i in range(3):
self.insert(parent, "end", text="Item %s" % i, tags=str(i))
self.bind("<Control-r>", lambda e: self.pass_to_other(e, connected_class))
def pass_to_other(self, _, connected_class):
items = self.selection()
connected_class.received = items
class App:
def __init__(self):
self.root = tk.Tk()
self.con_class = ConnectedClass()
self.tree = TreeViewWrapper(self.root,self.con_class)
self.tree.pack()
self.root.bind("<Control-p>",lambda e:print(self.con_class.received))
self.root.mainloop()
if __name__ == "__main__":
app = App()

How to communicate between classes in Python?

I'm trying to build calculator based on tkinter. I also follow tips from there.
Program for sure is still in progress. I'm currently stuck because of this error:
AttributeError: 'Calculator_GUI' object has no attribute 'main'
I have no idea how to get to work communication between both classes. I'm also asking for short review of what already is done. Thanks in advance!
Here's the code:
import tkinter as tk
from tkinter import ttk
class Calculator_Core():
def __init__(self):
self.input = tk.StringVar()
def buttonClick(self, a):
self.input.set(a)
#DEBUG:
print(self.input)
class Calculator_GUI(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.button = {}
self.configure_gui()
self.create_widgets()
self.main = Calculator_Core()
def configure_gui(self):
self.master.title("Calculator")
self.master.resizable(False, False)
def create_widgets(self):
self.configure_input_space()
row_number = 1
column_number = 0
a = -1
text_buttons = ('789+', '456-', '123*', '0=/C')
for button_row in text_buttons:
for text_button in button_row:
a += 1
self.configure_button(text_button, row_number, column_number, a)
column_number += 1
row_number += 1
column_number = 0
def configure_button(self, text, row, column, key):
self.button[key] = ttk.Button(self.master, text=text,
command=lambda: self.main.buttonClick(text))
self.button[key].grid(row=row, column=column)
def configure_input_space(self):
self.entry = ttk.Entry(self.master, textvariable=self.main.input)
self.entry.grid(columnspan=4, sticky='we')
if __name__ == "__main__":
root = tk.Tk()
Calculator_GUI(root)
root.mainloop()
You need to 'make' the self.main before running the create_widgets() funtion, so this:
class Calculator_GUI(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.button = {}
self.configure_gui()
self.create_widgets()
self.main = Calculator_Core()
Should be like this:
class Calculator_GUI(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.main = Calculator_Core()
self.button = {}
self.configure_gui()
self.create_widgets()
Because the create_widgets() function runs the configure_button() and configure_input_space() functions which have references to self.main.

Button to add widgets , in Tkinter

In Tkinter, how would look like the code of button that adds a widget when clicked, infinitely if necessary?
Thanks and sorry for bad english.
This is a more "classy" version:
from Tkinter import *
class Application(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.number = 0
self.widgets = []
self.grid()
self.createWidgets()
def createWidgets(self):
self.cloneButton = Button ( self, text='Clone', command=self.clone)
self.cloneButton.grid()
def clone(self):
widget = Label(self, text='label #%s' % self.number)
widget.grid()
self.widgets.append(widget)
self.number += 1
if __name__ == "__main__":
app = Application()
app.master.title("Sample application")
app.mainloop()
Note you keep your widgets in self.widgets list, so you can recall them and modify them if you like.
Well it could look something like this (it could look like a lot of different things):
import Tkinter as tk
root = tk.Tk()
count = 0
def add_line():
global count
count += 1
tk.Label(text='Label %d' % count).pack()
tk.Button(root, text="Hello World", command=add_line).pack()
root.mainloop()

Categories

Resources