问题
I'm pretty new to Python, and even more new to tkinter. I've searched for an answer to this question and gotten some things that seem close, but none that I have been able to successfully implement.
Basically what I'm trying to do is create a main window with a dropdown list for the user to select an item from. When the user makes a selection, a simple calculation is done and the result printed to the screen. One of the choices is 'User Defined'. When this selection is made, I would like to create a child window using Toplevel that allows the user to make a few inputs and hit 'OK', at which point the same calculations are done and the same data displayed on the main window as if they had selected a pre-defined option.
I can get the windows to open and close as I want, but when the user defines a new item I can't pass their input back to the main program to make the necessary calculations (which would then be trivial to display). How do I pass the user inputs back to the main window?
In the sample code below, everything works for the first 3 items in the dropdown list, but for User Defined it does nothing since I can't figure out how to return the user inputted values to perform the calculations.
Thanks in advance for any help/advice.
import tkinter as tk
from tkinter import ttk
import numpy as np
class MainGUI:
def __init__(self, master):
self.master = master
master.title('Bolted Joint Analysis')
master.geometry('500x500')
# Adds tabs to main window
self.nb = ttk.Notebook(master)
self.nb.grid(row=1, column=0, columnspan=50, rowspan=49, sticky='NESW')
self.tab1 = ttk.Frame(self.nb)
self.nb.add(self.tab1, text='Tab1')
self.tab2 = ttk.Frame(self.nb)
self.nb.add(self.tab2, text='Tab2')
# defines a grid 50 x 50 cells in the main window & tabs
rows = 0
while rows < 50:
master.rowconfigure(rows, weight=1)
master.columnconfigure(rows, weight=1)
self.tab1.rowconfigure(rows, weight=1)
self.tab1.columnconfigure(rows, weight=1)
self.tab2.rowconfigure(rows, weight=1)
self.tab2.columnconfigure(rows, weight=1)
rows += 1
# Add Tab1 Labels
self.boltLabel = tk.Label(self.tab1, text="Select A Bolt:")
self.boltLabel.grid(column=0, row=1, sticky='SW')
self.labelMajD = tk.Label(self.tab1, text="Bolt Major Dia. [in]:")
self.labelMajD.grid(column=0, row=4, sticky='W')
self.labelMinD = tk.Label(self.tab1, text="Bolt Minor Dia. [in]:")
self.labelMinD.grid(column=0, row=5, sticky='W')
self.labelPitchD = tk.Label(self.tab1, text="Bolt Pitch Dia. [in]:")
self.labelPitchD.grid(column=0, row=6, sticky='W')
# Add Tab1 Dropdown List - Bolt Choices
self.boltValue = tk.StringVar()
self.BoltList = ttk.Combobox(self.tab1, textvariable=self.boltValue, state='readonly')
self.BoltList['values'] = ('',
'#2-56 (UNC)',
'1-1/2"-12 (UNF)',
'User Defined')
self.BoltList.grid(column=0, row=2, sticky='NS')
self.BoltList.current(0)
self.BoltList.bind("<<ComboboxSelected>>", self.boltSelectFunc)
# Add Tab1 Entry boxes to display values
self.majDiaBox = tk.Entry(self.tab1)
self.majDiaBox.insert(0, '0.0000')
self.majDiaBox.configure(state='disabled')
self.majDiaBox.grid(column=1, row=4, sticky='NS')
self.minDiaBox = tk.Entry(self.tab1)
self.minDiaBox.insert(0, '0.0000')
self.minDiaBox.configure(state='disabled')
self.minDiaBox.grid(column=1, row=5, sticky='NS')
self.pitchDiaBox = tk.Entry(self.tab1)
self.pitchDiaBox.insert(0, '0.0000')
self.pitchDiaBox.configure(state='disabled')
self.pitchDiaBox.grid(column=1, row=6, sticky='NS')
def UsrDefBolt(self):
self.newWindow = tk.Toplevel(self.master)
self.app = ChildWindow(self.newWindow)
def boltSelectFunc(self, event):
self.bolt = self.boltValue.get()
print(self.bolt)
if (self.bolt == ''):
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, '0.0000')
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, '0.0000')
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, '0.0000')
self.pitchDiaBox.configure(state='disabled')
elif (self.bolt == 'User Defined'):
self.newBoltData = None
self.UsrDefBolt()
# self.boltSpecs = self.boltBasics(d, n) # need to return d, n from child window to run this calculation
else:
if (self.bolt[0] == '#'):
lhs, rhs = self.bolt.split("-")
d = float(lhs[1:]) * 0.013 + .060
n = float(rhs.split(" ")[0])
self.boltSpecs = self.boltBasics(d, n)
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, format(self.boltSpecs['d'], '.4f'))
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, format(self.boltSpecs['dm'], '.4f'))
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, format(self.boltSpecs['dp'], '.4f'))
self.pitchDiaBox.configure(state='disabled')
else:
lhs, rhs = self.bolt.split("\"-")
n = float(rhs.split(" ")[0])
if ("-" in lhs):
d = float(eval(lhs.replace("-", "+")))
self.boltSpecs = self.boltBasics(d, n)
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, format(self.boltSpecs['d'], '.4f'))
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, format(self.boltSpecs['dm'], '.4f'))
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, format(self.boltSpecs['dp'], '.4f'))
self.pitchDiaBox.configure(state='disabled')
else:
d = float(eval(lhs))
self.boltSpecs = self.boltBasics(d, n)
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, format(self.boltSpecs['d'], '.4f'))
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, format(self.boltSpecs['dm'], '.4f'))
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, format(self.boltSpecs['dp'], '.4f'))
self.pitchDiaBox.configure(state='disabled')
def boltBasics(self, d, n):
P = 1.0 / n # in - thread pitch
dm = d - (1.299038 * P) # in - external thread minor diameter
dp = d - (0.649519 * P) # in - bolt pitch Diameter
return{'d': d, 'dm': dm, 'dp': dp}
class ChildWindow():
def __init__(self, master):
self.master = master
self.frame = tk.Frame(self.master)
master.title('User Defined Bolt Info')
master.geometry('350x250')
master.focus_set()
rows = 0
while rows < 10:
master.rowconfigure(rows, weight=1)
master.columnconfigure(rows, weight=1)
rows += 1
self.boltName = tk.Label(master, text="Bolt Name (e.g. NewBolt1):")
self.boltName.grid(column=5, row=1, sticky='NSEW')
self.boltDia = tk.Label(master, text="Bolt Major Diameter [in]:")
self.boltDia.grid(column=5, row=3, sticky='NSEW')
self.boltTPI = tk.Label(master, text="Bolt Threads per Inch (TPI) [-]:")
self.boltTPI.grid(column=5, row=5, sticky='NSEW')
self.bName = tk.StringVar()
self.bDia = tk.StringVar()
self.bTPI = tk.StringVar()
self.nameInput = tk.Entry(master, textvariable=self.bName)
self.nameInput.insert(0, 'BoltName')
self.nameInput.grid(column=5, row=2, sticky='NSEW')
self.diaInput = tk.Entry(master, textvariable=self.bDia)
self.diaInput.insert(0, '0.0000')
self.diaInput.grid(column=5, row=4, sticky='NSEW')
self.tpiInput = tk.Entry(master, textvariable=self.bTPI)
self.tpiInput.insert(0, '0.0000')
self.tpiInput.grid(column=5, row=6, sticky='NSEW')
# Create button to save user defined bolt
self.saveBoltBtn = tk.Button(master, text='Save Bolt', command=self.saveBolt)
self.saveBoltBtn.bind('<Return>', self.saveBolt)
self.saveBoltBtn.grid(column=5, row=8, sticky='NSEW')
def saveBolt(self, *event):
self.data = {}
self.data['name'] = self.bName.get()
self.data['d'] = float(self.bDia.get())
self.data['n'] = float(self.bTPI.get())
# NEED TO RETURN THIS DATA TO PARENT WINDOW
self.master.destroy()
def main():
root = tk.Tk()
app = MainGUI(root)
root.mainloop()
if __name__ == '__main__':
main()
回答1:
I think you would benefit from inheriting from the Tk
class and Toplevel
class here.
This way you can simplify how you pass data between the classes. I have rewritten your code to show how you can pass data between the 2 classes. In this example I created a method called do_somthing_with_data
that will print the results of self.data
. I added a class attribute to your main class called self.data
and from your Toplevel class I manipulate this class attribute by referencing master. From here you simply need to do the data manipulation with self.data
that you would do with your other options.
import tkinter as tk
from tkinter import ttk
class MainGUI(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title('Bolted Joint Analysis')
self.geometry('500x500')
# Adds tabs to main window
self.nb = ttk.Notebook(self)
self.nb.grid(row=1, column=0, columnspan=50, rowspan=49, sticky='NESW')
self.tab1 = ttk.Frame(self.nb)
self.nb.add(self.tab1, text='Tab1')
self.tab2 = ttk.Frame(self.nb)
self.nb.add(self.tab2, text='Tab2')
self.data = {}
# defines a grid 50 x 50 cells in the main window & tabs
rows = 0
while rows < 50:
self.rowconfigure(rows, weight=1)
self.columnconfigure(rows, weight=1)
self.tab1.rowconfigure(rows, weight=1)
self.tab1.columnconfigure(rows, weight=1)
self.tab2.rowconfigure(rows, weight=1)
self.tab2.columnconfigure(rows, weight=1)
rows += 1
# Add Tab1 Labels
self.boltLabel = tk.Label(self.tab1, text="Select A Bolt:")
self.boltLabel.grid(column=0, row=1, sticky='SW')
self.labelMajD = tk.Label(self.tab1, text="Bolt Major Dia. [in]:")
self.labelMajD.grid(column=0, row=4, sticky='W')
self.labelMinD = tk.Label(self.tab1, text="Bolt Minor Dia. [in]:")
self.labelMinD.grid(column=0, row=5, sticky='W')
self.labelPitchD = tk.Label(self.tab1, text="Bolt Pitch Dia. [in]:")
self.labelPitchD.grid(column=0, row=6, sticky='W')
# Add Tab1 Dropdown List - Bolt Choices
self.boltValue = tk.StringVar()
self.BoltList = ttk.Combobox(self.tab1, textvariable=self.boltValue, state='readonly')
self.BoltList['values'] = ('', '#2-56 (UNC)', '1-1/2"-12 (UNF)', 'User Defined')
self.BoltList.grid(column=0, row=2, sticky='NS')
self.BoltList.current(0)
self.BoltList.bind("<<ComboboxSelected>>", self.boltSelectFunc)
# Add Tab1 Entry boxes to display values
self.majDiaBox = tk.Entry(self.tab1)
self.majDiaBox.insert(0, '0.0000')
self.majDiaBox.configure(state='disabled')
self.majDiaBox.grid(column=1, row=4, sticky='NS')
self.minDiaBox = tk.Entry(self.tab1)
self.minDiaBox.insert(0, '0.0000')
self.minDiaBox.configure(state='disabled')
self.minDiaBox.grid(column=1, row=5, sticky='NS')
self.pitchDiaBox = tk.Entry(self.tab1)
self.pitchDiaBox.insert(0, '0.0000')
self.pitchDiaBox.configure(state='disabled')
self.pitchDiaBox.grid(column=1, row=6, sticky='NS')
def do_somthing_with_data(self):
print(self.data)
def boltSelectFunc(self, event):
self.bolt = self.boltValue.get()
print(self.bolt)
if (self.bolt == ''):
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, '0.0000')
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, '0.0000')
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, '0.0000')
self.pitchDiaBox.configure(state='disabled')
elif (self.bolt == 'User Defined'):
self.newBoltData = None
ChildWindow(self)
# self.boltSpecs = self.boltBasics(d, n) # need to return d, n from child window to run this calculation
else:
if (self.bolt[0] == '#'):
lhs, rhs = self.bolt.split("-")
d = float(lhs[1:]) * 0.013 + .060
n = float(rhs.split(" ")[0])
self.boltSpecs = self.boltBasics(d, n)
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, format(self.boltSpecs['d'], '.4f'))
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, format(self.boltSpecs['dm'], '.4f'))
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, format(self.boltSpecs['dp'], '.4f'))
self.pitchDiaBox.configure(state='disabled')
else:
lhs, rhs = self.bolt.split("\"-")
n = float(rhs.split(" ")[0])
if ("-" in lhs):
d = float(eval(lhs.replace("-", "+")))
self.boltSpecs = self.boltBasics(d, n)
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, format(self.boltSpecs['d'], '.4f'))
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, format(self.boltSpecs['dm'], '.4f'))
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, format(self.boltSpecs['dp'], '.4f'))
self.pitchDiaBox.configure(state='disabled')
else:
d = float(eval(lhs))
self.boltSpecs = self.boltBasics(d, n)
self.majDiaBox.configure(state='normal')
self.majDiaBox.delete(0, 'end')
self.majDiaBox.insert(0, format(self.boltSpecs['d'], '.4f'))
self.majDiaBox.configure(state='disabled')
self.minDiaBox.configure(state='normal')
self.minDiaBox.delete(0, 'end')
self.minDiaBox.insert(0, format(self.boltSpecs['dm'], '.4f'))
self.minDiaBox.configure(state='disabled')
self.pitchDiaBox.configure(state='normal')
self.pitchDiaBox.delete(0, 'end')
self.pitchDiaBox.insert(0, format(self.boltSpecs['dp'], '.4f'))
self.pitchDiaBox.configure(state='disabled')
def boltBasics(self, d, n):
P = 1.0 / n # in - thread pitch
dm = d - (1.299038 * P) # in - external thread minor diameter
dp = d - (0.649519 * P) # in - bolt pitch Diameter
return{'d': d, 'dm': dm, 'dp': dp}
class ChildWindow(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self, master)
self.frame = tk.Frame(self)
self.title('User Defined Bolt Info')
self.geometry('350x250')
self.focus_set()
rows = 0
while rows < 10:
self.rowconfigure(rows, weight=1)
self.columnconfigure(rows, weight=1)
rows += 1
self.boltName = tk.Label(self, text="Bolt Name (e.g. NewBolt1):")
self.boltName.grid(column=5, row=1, sticky='NSEW')
self.boltDia = tk.Label(self, text="Bolt Major Diameter [in]:")
self.boltDia.grid(column=5, row=3, sticky='NSEW')
self.boltTPI = tk.Label(self, text="Bolt Threads per Inch (TPI) [-]:")
self.boltTPI.grid(column=5, row=5, sticky='NSEW')
self.bName = tk.StringVar()
self.bDia = tk.StringVar()
self.bTPI = tk.StringVar()
self.nameInput = tk.Entry(self, textvariable=self.bName)
self.nameInput.insert(0, 'BoltName')
self.nameInput.grid(column=5, row=2, sticky='NSEW')
self.diaInput = tk.Entry(self, textvariable=self.bDia)
self.diaInput.insert(0, '0.0000')
self.diaInput.grid(column=5, row=4, sticky='NSEW')
self.tpiInput = tk.Entry(self, textvariable=self.bTPI)
self.tpiInput.insert(0, '0.0000')
self.tpiInput.grid(column=5, row=6, sticky='NSEW')
# Create button to save user defined bolt
self.saveBoltBtn = tk.Button(self, text='Save Bolt', command=self.saveBolt)
self.saveBoltBtn.bind('<Return>', self.saveBolt)
self.saveBoltBtn.grid(column=5, row=8, sticky='NSEW')
def saveBolt(self, *event):
self.master.data = {}
self.master.data['name'] = self.bName.get()
self.master.data['d'] = float(self.bDia.get())
self.master.data['n'] = float(self.bTPI.get())
self.master.do_somthing_with_data()
# NEED TO RETURN THIS DATA TO PARENT WINDOW
self.destroy()
def main():
MainGUI().mainloop()
if __name__ == '__main__':
main()
回答2:
i honestly didnt read all the code but to pass a input from your "ChildWindow" class to your "MainGUI" just do the following:
In your MainGUI class define a variable with the input you want either before your init function or in your init function (dont forget to declare self.your_variable).
def __init__(self):
self.input_from_child = None
Since you initialized the MainGUI in your "Main()" function, in your ChildWindow function you can just then change the variable:
app.input_from_child = "Whatever"
And then just use the variable inside the MainGUI class to do your calculations
来源:https://stackoverflow.com/questions/52927296/pass-user-input-from-child-to-parent-window-python-tkinter