How to get variable from a class to another Tkinter window - python

The goal is to pass the variable string1 from class Display to be used in another Tkinter window.
So when the button named Next [in class Display load function] is clicked, it would open a new Tkinter window. And in the new window, the variable string1 from class Display needs to be retrieved for further action. May i know should i create another class Display2, or should i just add a method in the class Display?
Currently the string variable can be passed as reference from class Display to the class Action_Data. But how can it be passed to another Tkinter window when the button Next is clicked?
I am trying to get the variable via the callback function new_window. Just not sure if it's how it's done. Any pointer would be appreciated. Many thanks.
from tkinter import *
import tkinter as tk
#Application window
root = tk.Tk()
#Display Class
class Display (tk.Frame):
def __init__(self, master, display_data):
tk.Frame.__init__(self,master)
self.master = master
#passing data as reference
self.display= display_data
#button
self.load_button = tk.Button(self, text="Load", command=self.load)
self.load_button.pack()
def new_window(self):
self.master = tk.Tk() # create another Tk instance
var_string2 = Label(self, text="<<string1 value>>")
var_string2.pack()
print (var_string2)
def load(self):
#get value
string1='value1'
self.display.action1(string1)
self.acition_button = tk.Button(self, text="Next",
command=self.new_window)
self.acition_button.pack()
#Action_Data Class
class Action_Data(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
def action1(self, path1):
var_path1 = path1
print(var_path1)
display= Action_Data(root)
display.pack()
reader = Display(root, display)
reader.pack()
pathlabel2 = Label(root)
root.mainloop()
Issue
Now the new window is blank and cannot retrieve the value of variable string1 from the load function
Error

Use the lambda function to pass the button's command, that way you can pass the needed string as an argument.
You do not need to create two instances of Tk, if you need another window, create a Toplevel.
from tkinter import *
import tkinter as tk
#Application window
root = tk.Tk()
#Display Class
class Display (tk.Frame):
def __init__(self, master, display_data):
tk.Frame.__init__(self,master)
self.master = master
#passing data as reference
self.display= display_data
#button
self.load_button = tk.Button(self, text="Load", command=self.load)
self.load_button.pack()
def new_window(self, string):
#self.master.destroy() # close the current window
new_window = tk.Toplevel() # create toplevel
var_string2 = Label(new_window, text=string)
var_string2.pack()
new_window.focus()
print (var_string2.cget("text"))
def load(self):
#get value
string1='value1'
self.display.action1(string1)
self.acition_button = tk.Button(self, text="Next",
command= lambda : self.new_window(string1))
self.acition_button.pack()
#Action_Data Class
class Action_Data(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self,master)
def action1(self, path1):
var_path1 = path1
print(var_path1)
display= Action_Data(root)
display.pack()
reader = Display(root, display)
reader.pack()
pathlabel2 = Label(root)
root.mainloop()

Related

Is there a way to get values of dynamically added text fields in tkinter?

For homework, I have to create an application that creates a text field everytime a user clicks a button, and then get values from the fields when "submit" button is pressed.
The trace method shows up repeatedly, but I do not know how to use it. I know it requires a callback function, but what should that callback function be?
from tkinter import *
from tkinter import ttk
import sqlite3
import getpass
import wipComingIn
class Application(object):
def __init__(self,master):
self.master=master
self.ScanWIPIn = Button(master, text="Scan WIP In", width=25,
font='Calibri 12
bold',background='snow',command=self.scanWIPIn).grid(row=0, column=0,
padx=10)
def scanWIPIn(self):
incomingInventory=wipComingIn.scanIn()
def main():
root = Tk()
app=Application(root)
root.title("Main Menu")
root.configure(background="light cyan")
root.resizable(0, 0)
root.geometry('230x230+300+80')
root.mainloop()
if __name__=='__main__':
main()
class scanIn(Toplevel):
def __init__(self):
Toplevel.__init__(self)
self.geometry('300x100+350+100')
self.title('Scan In')
self.resizable(0,0)
self.num_rows=1
self.LocationLb = Label(self,text='Scan Location:',font='Arial
12').grid(row=1,column=1)
self.LocationBCText = Entry(self).grid(row=1,column=2)
self.AddLotBtn= Button(self,text="Scan
Lot",command=self.addField).grid(row=2,column=1)
self.CompleteTransaction =
Button(self,text="Complete",command=self.AddEntry).grid(row=2,column=4)
global listOfLots
listOfLots=[]
listOfLocation=[]
global rowNum
rowNum=2
def addField(self):
height =Toplevel.winfo_height(self)
height=height+25
global rowNum
rowNum=rowNum+1
listOfLots.append(StringVar())
newLot = Entry(self, textvariable=listOfLots[rowNum - 2])
newLot.grid(row=rowNum,column=2, pady=1)
listOfLots.append(StringVar())
geometryText='300'+str(height)+'350+100'
print(geometryText)
self.geometry('300x'+str(height)+'+350+100')
newLot.focus_set()
You could try just making a class that does it, for example:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.geometry('200x200')
class EntryListWidget(ttk.Frame):
"""Widget that creates a column of entry boxes."""
def __init__(self, master):
super().__init__(master)
self.entries = []
def add_entry(self):
"""Creates a new entry box and keeps reference to respective variable."""
entry_var = tk.StringVar()
self.entries.append(entry_var)
ttk.Entry(self, textvariable=entry_var).pack()
def get_entries(self):
"""Gets each entrybox text and returns as list."""
return [entry.get() for entry in self.entries]
entry_widget = EntryListWidget(root)
entry_widget.pack()
# Buttons to control adding new entry and getting their values
ttk.Button(root, text='Add Entry', command=entry_widget.add_entry).pack()
ttk.Button(root, text='Get Entries', command=entry_widget.get_entries).pack()
root.mainloop()
Just using the variable classes and not trace; I actually wouldn't use trace in this situation because I believe trace uses the callback every time the variable changes and here you have a one time "submit" button that collects all the values. You could extend this class idea to get what you're looking to do I bet.

Getting NameError trying to access my tkinter widget in my button command function

I wrote a class for my tkinter GUI and for some reason I can't access the Entry widget I created in my button's callback function:
import tkinter as tk
class MyGUI:
def __init__(self, master):
entry = tk.Entry(master)
entry.pack()
self.run = tk.Button(master, text="Run", command=self.run)
self.run.pack()
def run(self):
print('Entry content is:', entry.get())
root = tk.Tk()
my_gui = MyGUI(root)
root.mainloop()
The code throws NameError: name 'entry' is not defined. What am I doing wrong?
You forgot to set the entry as attribute in the self, nor did you access it from self. Furthermore you define a self.run, as well as a def run(..) method, which will result in the fact that the method, for an instance will be overwritten. You thus should rename it to something else, for example _run.
import tkinter as tk
class MyGUI:
def __init__(self, master):
self.entry = tk.Entry(master)
self.entry.pack()
self._run = tk.Button(master, text="Run", command=self.run)
self._run.pack()
def run(self):
print('Entry content is:', self.entry.get())
root = tk.Tk()
my_gui = MyGUI(root)
root.mainloop()

import a python file that create a window when main window button clicks

I am creating 2 window in my program and i am using two class, since the code is complex, i separate it in 2 different python file. After i imported the second window file, how can i make sure it open without having this error which show in this picture
The original result should look like this after the new window button clicked:
Coding for Main Window:
from tkinter import *
import classGUIProgram
class Window(Tk):
def __init__(self, parent):
Tk.__init__(self, parent)
self.parent = parent
self.initialize()
def initialize(self):
self.geometry("600x400+30+30")
self.wButton = Button(self, text='newWindow', command = self.OnButtonClick)
self.wButton.pack()
def OnButtonClick(classGUIProgram):
classGUIProgram.top = Toplevel()
master = Tk()
b = classGUIProgram.HappyButton(master)
master.mainloop()
if __name__ == "__main__":
window = Window(None)
window.title("title")
window.mainloop()
Coding for Second Window:
from tkinter import *
class HappyButton:
def __init__(self, master):
frame = Frame(master)
frame.pack()
self.printButton = Button(frame, text="Print message", command=self.printMessage)
self.printButton.pack(side=LEFT)
self.quitButton = Button(frame, text="Quit", command= quit)
self.quitButton.pack(side=LEFT)
self.downloadHistoryCB=Checkbutton(frame, text="Download History")
self.downloadHistoryCB.pack(side=LEFT)
def printMessage(self):
print("Wow this actually worked!")
master = Tk()
b = HappyButton(master)
master.mainloop()
You're creating extra Tk windows. Here is an example of using Toplevel widgets and another file.
mainWindow.py
import tkinter as tk
import secondWindow as sW
class MainWindow(tk.Tk):
def __init__(self):
super().__init__()
self.title("Main Window")
self.geometry("600x400+30+30")
tk.Button(self, text = "New Window", command = self.new_window).pack()
tk.Button(self, text = "Close Window", command = self.close).pack()
self._second_window = None
def new_window(self):
# This prevents multiple clicks opening multiple windows
if self._second_window is not None:
return
self._second_window = sW.SubWindow(self)
def close(self):
# Destory the 2nd window and reset the value to None
if self._second_window is not None:
self._second_window.destroy()
self._second_window = None
if __name__ == '__main__':
window = MainWindow()
window.mainloop()
secondWindow.py
import tkinter as tk
class SubWindow(tk.Toplevel):
def __init__(self, master):
super().__init__(master)
self.title("Sub Window")
self.geometry("400x300+30+30")
# Change what happens when you click the X button
# This is done so changes also reflect in the main window class
self.protocol('WM_DELETE_WINDOW', master.close)
tk.Button(self, text = "Print", command = self.printMessage).pack()
def printMessage(self):
print("Wow this actually worked!")
When using another file be sure to not have any global code you don't want running. Your classes don't have to inherit from Tk and Toplevel, this is just an example. But you need to ensure you only ever have one instance of Tk otherwise you get the behaviour you encountered

Python Tkinter Input Box

Good day.
I am trying to create my own input box for use in my project.
basically what i am trying to do is run my main form which will call the second. the user will provide some data on the second and when the press the ok/close button on the second for the data will be passed back to the first. similar in functionality to the inputbox.
here is what i have created, but being new to python i am not sure where i am going wrong/nor can i quick figure out when to put the return.
My Class is here
import tkinter as tk
class MainWindow():
def __init__(self, parent):
top = self.top = tk.Toplevel(parent)
self.myLabel = tk.Label(top, text='Enter a Grouping Name')
self.myLabel.pack()
self.myEntryBox = tk.Entry(top)
self.myEntryBox.focus_set()
self.myEntryBox.pack()
self.mySubmitButton = tk.Button(top, text='OK', command=self.DestWin)
self.mySubmitButton.pack()
def DestWin(self):
self.top.destroy()
The method to call it is here
abc=configurator.MainWindow(root)
Not exactly sure what you are trying to achieve, but if you are trying to get values from one window to another, below you can find an extended example based on your code.
import tkinter as tk
class MainWindow():
def __init__(self, parent):
top = self.top = tk.Toplevel(parent)
self.myLabel = tk.Label(top, text='Enter a Grouping Name')
self.myLabel.pack()
self.myEntryBox = tk.Entry(top)
self.myEntryBox.focus_set()
self.myEntryBox.pack()
self.mySubmitButton = tk.Button(top, text='OK', command=self.DestWin)
self.mySubmitButton.pack()
def DestWin(self):
# call callback function setting value in MyFrame
self.callback(self.myEntryBox.get())
self.top.destroy()
def set_callback(self, a_func):
self.callback = a_func
class MyFrame(tk.Frame):
def __init__(self, parent, **kwargs):
super().__init__(parent, **kwargs)
self.pack()
self.myLabel1 = tk.Label(parent, text='Click OK to enter the group name')
self.myLabel1.pack()
self.mySubmitButton1 = tk.Button(parent, text='OK', command=self.get_group_name)
self.mySubmitButton1.pack()
def get_group_name(self):
mw = MainWindow(None)
# provide callback to MainWindow so that it can return results to MyFrame
mw.set_callback(self.set_label)
def set_label(self, astr = ''):
self.myLabel1['text'] = astr
root = tk.Tk()
mf = MyFrame(root)
root.mainloop()
The screenshot:
The text from the right window, when OK is pressed, will be shown in the left window. This is achieved through callbacks. MainWindow takes a callback function, and when you press OK, it is executed. The callback is set_label from MyFrame.
Hope this helps.

Python GUI - Linking one GUI in a class to another class

What I am trying to do is to link a GUI from one class in a separate file to another.
My first class is a main menu which will display a few buttons that will link to another window.
The second class displays a different window, but the problem I am having at the moment is that I don't know how to link the button in the first class to call the second class.
Here's the code I have so far:
First file, the main menu:
from tkinter import *
import prac2_link
class main:
def __init__(self,master):
frame = Frame(master, width=80, height=50)
frame.pack()
self.hello = Label(frame, text="MAIN MENU").grid()
self.cont = Button(frame,text="Menu option 1", command=prac2_link.main2).grid(row=1)
root = Tk()
application = main(root)
root.mainloop()
second file:
from tkinter import *
class main2:
def __init__(self):
frame1 = Frame(self, width=80, height=50)
frame1.pack()
self.hello = Label(frame1, text="hello, its another frame").grid(row=0,column=0)
To create a new window, you have to use a Toplevel widget. You can use it as a superclass for your main2 class:
class main2(Toplevel):
def __init__(self):
Toplevel.__init__(self)
self.frame= Frame(self, width=80, height=50)
self.label = Label(self.frame, text='this is another frame')
self.frame.grid()
self.label.grid()
Then you only have to create an instance in the event handler of the Button in the other class:
class main1:
def __init__(self, master):
# ...
self.cont = Button(frame,text="Menu option 1", command=self.open_main2).grid(row=1)
def open_main2(self):
prac2_link.main2()

Categories