Related
Running python 3.8 in PyCharm
I'm trying to create a class to allow creation of a tkinter checkbutton (and eventually other widgets) that will hold all the formatting and definition for the widget. I would like to be able to test the state of the checkbutton and act on it in a callback. But like many others, my checkbutton variable seems to always be 0. I'm fairly sure its a garbage collection issue, but I can't figure a way around it. Note the second set of parameters in the class definition specify the location of the label to display the checkbutton variable state. At the moment, the callback is just to display the variable state in a label.
Acknowledgement:
I modified code from Burhard Meier's book "Python GUI Programming Cookbook" for this. The code related to the class is mine, the rest is from Burkhard Meier.
'''
This is a modification of code by Burhard A. Meier
in "Python GUI Programming Cookbook"
Created on Apr 30, 2019
#author: Burkhard A. Meier
'''
#======================
# imports
#======================
import tkinter as tk
from tkinter import ttk
# Create instance
win = tk.Tk()
# Add a title
win.title("GUI Test Box")
# Modify adding a Label
a_label = ttk.Label(win, text="Testing TK Widgets")
a_label.grid(column=0, row=0)
# Modified Button Click Function
def click_me():
action.configure(text='Hello ' + name.get() + ' ' +
number_chosen.get())
#Define the Checkbutton Class
class ChkBut(): #lable, xloc, yloc, xlab, ylab
def __init__(self, lable, xloc, yloc, xlab, ylab): # , xloc, yloc, text="default", variable = v, onvalue='Set', offvalue='NotSet'):
v = tk.IntVar()
self.v = v
self.lable = lable
self.xloc = xloc
self.yloc = yloc
self.xlab = xlab
self.ylab = ylab
c = tk.Checkbutton(
win,
text= self.lable,
variable=self.v,
command=self.cb(self.v, xlab,ylab))
c.grid(column=xloc, row=yloc, sticky = tk.W)
c.deselect()
def cb (self, c, xlab, ylab):
if c.get()==1:
c_label = ttk.Label(win, text="Set")
c_label.grid(column=xlab, row=ylab)
elif c.get()==0:
c_label = ttk.Label(win, text="NotSet")
c_label.grid(column=xlab, row=ylab)
else:
c_label = ttk.Label(win, text=c.v.get())
c_label.grid(column=xlab, row=ylab)
# Changing the Label
ttk.Label(win, text="Enter a name:").grid(column=0, row=0)
# Adding a Textbox Entry widget
name = tk.StringVar()
name_entered = ttk.Entry(win, width=12, textvariable=name)
name_entered.grid(column=0, row=1)
# Adding a Button
action = ttk.Button(win, text="Click Me!", command=click_me)
action.grid(column=2, row=1)
# Creating three checkbuttons
ttk.Label(win, text="Choose a number:").grid(column=1, row=0)
number = tk.StringVar()
number_chosen = ttk.Combobox(win, width=12, textvariable=number, state='readonly')
number_chosen['values'] = (1, 2, 4, 42, 100)
number_chosen.grid(column=1, row=1)
number_chosen.current(0)
check1 = ChkBut("Button 1", 0, 4, 0, 5)
chVarUn = tk.IntVar()
check2 = tk.Checkbutton(win, text="UnChecked", variable=chVarUn)
check2.deselect()
check2.chVarUn = 0
check2.grid(column=1, row=4, sticky=tk.W)
chVarEn = tk.IntVar()
check3 = tk.Checkbutton(win, text="Enabled", variable=chVarEn)
check3.select()
check3.chVarEn = 0
check3.grid(column=2, row=4, sticky=tk.W)
name_entered.focus() # Place cursor into name Entry
#======================
# Start GUI
#======================
win.mainloop()
I noticed if I eliminate/comment the ########### Create Dropdown list for Code corresponding name ########### section below, the window appears. Also, if I use the same code in a different file, the DropDown list appears as normal.... super weird!!
Not sure what is going on here.
Can you help?
Code below:
from tkinter import *
########### Create main window, call it root ###########
root = Tk()
#Defining classes and methods
class Code:
def __init__(self, code, name, skill, description):
self.code = code
self.name = name
self.skill = skill
self.description = description
codesList.append(self)
namesList.append(name)
#Defining variables
codesList = []
namesList = []
selectedname = StringVar()
selectedname.set('Please select the correct the correct knowledge category necessary to resolve the ticket.')
A11 = Code(11, 'Fundamentals', 'A', '')
B11 = Code(11,'Geology', 'B', '')
B12 = Code(12,'Reservoir Engineering', 'B', '')
########### Create list of Dictionaries ###########
TypeD = {}
SiteD = {}
P4dcD = {}
SkillD = {}
########### Create Incident Types Dictionary###########
TypeD = dict(Normal='NORMAL', \
Parent='PARENT', \
Child='CHILD')
TypeNameL = list()
for i in TypeD.keys():
TypeNameL.append(i)
########### Create Skill Levels ###########
SkillD = dict(Awareness = 'A', \
Foundation = 'B', \
Skill = 'C', \
Advance = 'D')
SkillNameL = list()
for i in SkillD.keys():
SkillNameL.append(i)
########### Create main menu ###########
mainmenu = Menu(root)
root.config(menu = mainmenu)
submenu = Menu(mainmenu)
mainmenu.add_cascade(label = "File", menu=submenu)
submenu.add_command(label = "New Project", command=doNothing)
submenu.add_separator()
submenu.add_command(label = "Exit", command= exitmeth)
editmenu = Menu(mainmenu)
mainmenu.add_cascade(label = "Edit", menu=editmenu)
editmenu.add_command(label = "Redo", command = doNothing)
########### Toolbar ###########
toolbar = Frame(root, bg="blue")
insertButt = Button(toolbar, text = "Insert image", command = InsertImgcmd)
insertButt.pack(side=LEFT, padx = 2, pady=2)
printButt = Button(toolbar, text="Print", command = printP4dcD)
printButt.pack(side=LEFT, padx = 2, pady=2)
toolbar.pack(side=TOP, fill=X)
########### Create Dropdown list for Code corresponding name ###########
LabelCodeDDL = Label(root, text="Petrel Code").grid(row=2, column=0, sticky=W)
CodeDDL = OptionMenu(root, selectedname, *namesList)
CodeDDL.pack()
CodeDDL.configure(font=("Calibri", 11))
CodeDDL.grid(row=3, column=0)
########## Statusbar ##########
statusbar = Label(root, text='', bd=1, relief=SUNKEN, anchor=W)
statusbar.pack(side=BOTTOM, fill=X)
root.title("Ticket Summary Tool")
root.geometry("300x200")
root.mainloop()
I should get some errors or the window should display. I can't figure out what is happening...
You are using both pack and grid with widgets that are directly in root (for example, LabelCodeDDL = Label(root, text="Petrel Code").grid(row=2, column=0, sticky=W) and toolbar.pack(side=TOP, fill=X)). You cannot mix them like that. All widgets that have the same parent or master must use one or the other.
I would like to use a tkinter GUI to iterate through a dictionary (for example) and allow the user to take actions on its values.
For example, my boss might want to iterate through departments and select which employees to fire. The below code works (mostly) for the first department, but I don't understand how to advance to the next department (self.advance below) .
This question is related but just updates values of existing widgets. The number of employees in each department varies, so I can't just update the names, and I also have to allow vertical scrolling.
The iteration occurs within a frame (innerFrame) and the rest of the UI is mostly static. Should I be destroying and recreating that innerFrame, or just all of the widgets inside it? Either way, how can I advance to the next iteration?
# Example data
emp = {'Sales':['Alice','Bryan','Cathy','Dave'],
'Product':['Elizabeth','Frank','Gordon','Heather',
'Irene','John','Kristof','Lauren'],
'Marketing':['Marvin'],
'Accounting':['Nancy','Oscar','Peter','Quentin',
'Rebecca','Sally','Trevor','Umberto',
'Victoria','Wally','Xavier','Yolanda',
'Zeus']}
import tkinter as tk
from tkinter import messagebox
class bossWidget(tk.Frame):
def __init__(self, root):
"""
Scrollbar code credit to Bryan Oakley:
https://stackoverflow.com/a/3092341/2573061
"""
super().__init__()
self.canvas = tk.Canvas(root, borderwidth=0)
self.frame = tk.Frame(self.canvas)
self.scroll = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.initUI()
def initUI(self):
"""
Creates the static UI content and the innerFrame that will hold the
dynamic UI content (i.e., the Checkbuttons for the copies)
"""
self.master.title("Boss Interface")
self.instructLabel = tk.Label( self.frame, justify='left',
text = "Select the employees you wish to FIRE")
self.skipButton = tk.Button( self.frame, text="Skip Department",
command = self.advance)
self.deleteButton = tk.Button( self.frame, text="Fire employees", fg = 'red',
command = self.executeSelection )
self.quitButton = tk.Button( self.frame, text="Exit", command=self.frame.quit)
self.innerFrame = tk.Frame( self.frame)
self.instructLabel.pack(anchor = 'nw', padx=5,pady=5)
self.innerFrame.pack(anchor='nw', padx=5, pady=20, expand=True)
self.deleteButton.pack(side='left', padx=5,pady=5)
self.skipButton.pack(side='left', padx=5,pady=5)
self.quitButton.pack(side='left', padx=5,pady=5)
def populateUI(self, title, labelList):
"""
Creates and packs a list of Checkbuttons (cbList) into the innerFrame
By default, the first Checkbutton will be unchecked, all others checked.
You should help the boss out by passing the best employee at the head of the list
"""
self.instructLabel.config(text = title + ' department:\nSelect the employees you wish to FIRE')
self.cbList = [None] * len(labelList)
self.cbValues = [tk.BooleanVar() for i in range(len(labelList))]
for i in range(len(labelList)):
self.cbList[i] = tk.Checkbutton( self.innerFrame,
text=labelList[i],
variable = self.cbValues[i])
if i: self.cbList[i].select() # Check subsequent buttons by default
self.cbList[i].pack(anchor = 'w', padx=5,pady=5)
def advance(self):
# -------------> this is what I don't understand how to do <-------------
self.innerFrame.destroy() # this destroys everything!
# how to advance to next iteration?
def querySelection(self):
return [x.get() for x in self.cbValues]
def executeSelection(self):
fired = self.querySelection()
if ( not all(x for x in fired) or
messagebox.askokcancel(message='Fire ALL the employees in the department?')
):
for i in range(len(self.cbList)):
empName = self.cbList[i].cget('text')
if fired[i]:
print('Sorry, '+ empName + ', but we have to let you go.', flush=True)
else:
print('See you Monday, '+ empName, flush=True)
self.advance()
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def main():
root = tk.Tk()
root.geometry("400x250+250+100") # width x height + xOffset + yOffset
app = bossWidget(root)
while emp:
department, employees = emp.popitem()
app.pack(side='top',fill='both',expand=True)
app.populateUI(title = department, labelList = employees)
root.mainloop()
try:
root.destroy()
except tk.TclError:
pass # if run in my IDE, the root already is destroyed
if __name__ == '__main__':
main()
Here's a short rework of your code to handle updating the checkboxes on firing employees and switching frames to display the new employees from the department. I didn't handle advancing if all employees have been fired. There's also a small bug, but I'll leave that to you to figure out.
This could be a lot cleaner. I just didn't want to rewrite all of your code....
# Example data
emp = [['Sales', ['Alice','Bryan','Cathy','Dave']],
['Product', ['Elizabeth','Frank','Gordon','Heather',
'Irene','John','Kristof','Lauren']],
['Marketing', ['Marvin']],
['Accounting', ['Nancy','Oscar','Peter','Quentin',
'Rebecca','Sally','Trevor','Umberto',
'Victoria','Wally','Xavier','Yolanda',
'Zeus']]]
import tkinter as tk
from tkinter import messagebox
class bossWidget(tk.Frame):
def __init__(self, root):
"""
Scrollbar code credit to Bryan Oakley:
https://stackoverflow.com/a/3092341/2573061
"""
super().__init__()
self.cursor = 0
self.canvas = tk.Canvas(root, borderwidth=0)
self.frame = tk.Frame(self.canvas)
self.scroll = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.initUI()
def initUI(self):
"""
Creates the static UI content and the innerFrame that will hold the
dynamic UI content (i.e., the Checkbuttons for the copies)
"""
self.master.title("Boss Interface")
self.instructLabel = tk.Label( self.frame, justify='left',
text = "Select the employees you wish to FIRE")
self.skipButton = tk.Button( self.frame, text="Skip Department",
command = self.advance)
self.deleteButton = tk.Button( self.frame, text="Fire employees", fg = 'red',
command = self.executeSelection )
self.quitButton = tk.Button( self.frame, text="Exit", command=self.frame.quit)
self.innerFrame = tk.Frame(self.frame)
self.instructLabel.pack(anchor = 'nw', padx=5,pady=5)
self.innerFrame.pack(anchor = 'nw', padx=5,pady=5)
self.deleteButton.pack(side='left', padx=5,pady=5)
self.skipButton.pack(side='left', padx=5,pady=5)
self.quitButton.pack(side='left', padx=5,pady=5)
self.populateUI(*self.get_populate_items())
def get_populate_items(self):
return (emp[self.cursor][0], emp[self.cursor][1])
def populateUI(self, title, labelList):
"""
Creates and packs a list of Checkbuttons (cbList) into the innerFrame
By default, the first Checkbutton will be unchecked, all others checked.
You should help the boss out by passing the best employee at the head of the list
"""
for child in self.innerFrame.winfo_children():
child.destroy()
self.instructLabel.config(text = title + ' department:\nSelect the employees you wish to FIRE')
self.cbList = [None] * len(labelList)
self.cbValues = [tk.BooleanVar() for i in range(len(labelList))]
for i in range(len(labelList)):
self.cbList[i] = tk.Checkbutton( self.innerFrame,
text=labelList[i],
variable = self.cbValues[i])
if i: self.cbList[i].select() # Check subsequent buttons by default
self.cbList[i].pack(anchor = 'w', padx=5,pady=5)
def advance(self):
if (self.cursor < len(emp) - 1):
self.cursor += 1
else:
self.cursor = 0
self.populateUI(*self.get_populate_items())
def querySelection(self):
return [x.get() for x in self.cbValues]
def executeSelection(self):
fired = self.querySelection()
if ( not all(x for x in fired) or
messagebox.askokcancel(message='Fire ALL the employees in the department?')
):
for i in range(len(self.cbList)):
empName = self.cbList[i].cget('text')
if fired[i]:
emp[self.cursor][1].remove(empName)
print('Sorry, '+ empName + ', but we have to let you go.', flush=True)
else:
print('See you Monday, '+ empName, flush=True)
self.populateUI(*self.get_populate_items())
# self.advance()
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def main():
root = tk.Tk()
root.geometry("400x250+250+100") # width x height + xOffset + yOffset
app = bossWidget(root)
root.mainloop()
# while emp:
# department, employees = emp.popitem()
# app.pack(side='top',fill='both',expand=True)
# app.populateUI(title = department, labelList = employees)
# root.mainloop()
# try:
# root.destroy()
# except tk.TclError:
# pass # if run in my IDE, the root already is destroyed
if __name__ == '__main__':
main()
The basic pattern is to have a class or a function for each frame. Each of these classes or functions creates a single Frame, and places all of its widgets in that frame.
Then, all you need to do to switch frames is delete the current frame, and call the function or object to create the new frame. It's as simple as that.
Some examples on this site:
Switching between frames in python with functions
Switch between two frames in tkinter
I accepted Pythonista's answer but eventually wound up doing the following:
the UI constructor gets the data as an argument (perhaps better practice than the global data variable)
the UI populator deletes any existing labels first (see accepted answer)
the UI populator then pops a record off (if remaining, otherwise terminate)
the execute button calls the UI populator after doing its other tasks
the skip button just calls the UI populator (thus the advance function could be removed entirely)
This is what I wound up using. As Pythonista said, it's messy, but we all have to start somewhere.
# Example data
emp = {'Sales':['Alice','Bryan','Cathy','Dave'],
'Product':['Elizabeth','Frank','Gordon','Heather',
'Irene','John','Kristof','Lauren'],
'Marketing':['Marvin'],
'Accounting':['Nancy','Oscar','Peter','Quentin',
'Rebecca','Sally','Trevor','Umberto',
'Victoria','Wally','Xavier','Yolanda',
'Zeus']}
import tkinter as tk
from tkinter import messagebox
class bossWidget(tk.Frame):
def __init__(self, root, data):
"""
Scrollbar code credit to Bryan Oakley:
https://stackoverflow.com/a/3092341/2573061
"""
super().__init__()
self.canvas = tk.Canvas(root, borderwidth=0)
self.frame = tk.Frame(self.canvas)
self.scroll = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.scroll.set)
self.scroll.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.data = data
self.initUI()
def initUI(self):
"""
Creates the static UI content and the innerFrame that will hold the
dynamic UI content (i.e., the Checkbuttons for the copies)
"""
self.master.title("Boss Interface")
self.instructLabel = tk.Label( self.frame, justify='left',
text = "Select the employees you wish to FIRE")
self.skipButton = tk.Button( self.frame, text="Skip Department",
command = self.populateUI)
self.deleteButton = tk.Button( self.frame, text="Fire employees", fg = 'red',
command = self.executeSelection )
self.quitButton = tk.Button( self.frame, text="Exit", command=self.frame.quit)
self.innerFrame = tk.Frame( self.frame)
self.instructLabel.pack(anchor = 'nw', padx=5,pady=5)
self.innerFrame.pack(anchor='nw', padx=5, pady=20, expand=True)
self.deleteButton.pack(side='left', padx=5,pady=5)
self.skipButton.pack(side='left', padx=5,pady=5)
self.quitButton.pack(side='left', padx=5,pady=5)
self.populateUI()
def populateUI(self):
"""
Creates and packs a list of Checkbuttons (cbList) into the innerFrame
By default, the first Checkbutton will be unchecked, all others checked.
You should help the boss out by passing the best employee at the head of the list
"""
for child in self.innerFrame.winfo_children():
child.destroy()
try:
title, labelList = self.data.popitem()
self.instructLabel.config(text = title + ' department:\nSelect the employees you wish to FIRE')
self.cbList = [None] * len(labelList)
self.cbValues = [tk.BooleanVar() for i in range(len(labelList))]
for i in range(len(labelList)):
self.cbList[i] = tk.Checkbutton( self.innerFrame,
text=labelList[i],
variable = self.cbValues[i])
if i: self.cbList[i].select() # Check subsequent buttons by default
self.cbList[i].pack(anchor = 'w', padx=5,pady=5)
except KeyError:
messagebox.showinfo("All done", "You've purged all the departments. Good job, boss.")
self.frame.quit()
def querySelection(self):
return [x.get() for x in self.cbValues]
def executeSelection(self):
fired = self.querySelection()
if ( not all(x for x in fired) or
messagebox.askokcancel(message='Fire ALL the employees in the department?')
):
for i in range(len(self.cbList)):
empName = self.cbList[i].cget('text')
if fired[i]:
print('Sorry, '+ empName + ', but we have to let you go.', flush=True)
else:
print('See you Monday, '+ empName, flush=True)
self.populateUI()
def onFrameConfigure(self, event):
"""Reset the scroll region to encompass the inner frame"""
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
def main():
root = tk.Tk()
root.geometry("400x250+250+100") # width x height + xOffset + yOffset
app = bossWidget(root, data=emp)
app.mainloop()
try:
root.destroy()
except tk.TclError:
pass # if run in my IDE, the root already is destroyed
if __name__ == '__main__':
main()
I want to create a program in Python with Tkinter GUI, and I want it to take string inputs from a user, then I want to do some operations on these strings - in this case, I want to mix parts of two words and get a new word. How can I handle this data entered by a user and use it to receive the result? Below is my code. I couldn't find the answer to this problem and nothing I tried works.
from Tkinter import *
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("Mix words")
self.pack(fill=BOTH, expand=1)
menu = Menu(self.master)
self.master.config(menu=menu)
entryLbl1 = Label(self, text="Write the first word: ")
entryLbl1.pack()
self.entrytext1 = StringVar()
Entry(self, textvariable=self.entrytext1).pack()
self.buttontext1 = StringVar()
self.buttontext1.set("OK")
Button(self, textvariable=self.buttontext1, command=self.clicked1).pack()
self.label1 = Label(self, text="")
self.label1.pack()
global user_entry1
user_entry1 = self.entrytext1.get()
entryLbl2 = Label(self, text="Write the second word: ")
entryLbl2.pack()
self.entrytext2 = StringVar()
Entry(self, textvariable=self.entrytext2).pack()
self.buttontext2 = StringVar()
self.buttontext2.set("OK")
Button(self, textvariable=self.buttontext2, command=self.clicked2).pack()
self.label2 = Label(self, text="")
self.label2.pack()
global user_entry2
user_entry2 = self.entrytext2.get()
entryLbl3 = Label(self, text="Result: ")
entryLbl3.pack()
self.buttontext3 = StringVar()
self.buttontext3.set("Result")
Button(self, textvariable=self.buttontext1, command=self.clicked3).pack()
self.label3 = Label(self, text="")
self.label3.pack()
def clicked1(self):
input = self.entrytext1.get()
self.label1.configure(text=input)
def clicked2(self):
input = self.entrytext2.get()
self.label2.configure(text=input)
def clicked3(self):
self.user_entry1 = user_entry1
self.user_entry2 = user_entry2
first2a = user_entry1[0:2]
rest_a = user_entry1[2:]
first2b = user_entry2[0:2]
rest_b = user_entry2[2:]
input = first2b + rest_a + " " + first2a + rest_b
self.label3.configure(text=input)
root = Tk()
root.iconbitmap("py.ico")
root.geometry("600x300")
app = Window(root)
root.mainloop()
You need Entry() objects.
The following will show two Entry widgets and a Button.
When the button is pressed, the contents of both of the Entry objects will be printed to the console:
import sys
# Determine if you're running Python 3
is_py_3 = sys.version[0] == '3'
# Import Tkinter for the correct version of Python
if is_py_3:
from tkinter import Button, Entry, Tk
else:
from Tkinter import Button, Entry, Tk
class GUI:
def __init__(self):
# Set up the "Root" or "Parent" of the window.
self.root = Tk()
# Set up two "Entry" widgets.
self.entry1 = Entry(self.root)
self.entry1.insert(0, "Enter something here.")
self.entry2 = Entry(self.root)
self.entry2.insert(0, "and here...")
# Set up a button to handle the event.
self.button = Button(self.root, text="CLICK ME", command=self.onClicked)
self.entry1.pack()
self.entry2.pack()
self.button.pack()
def onClicked(self):
# Print the contents of the entry widgets.
s1 = self.entry1.get()
s2 = self.entry2.get()
print(s1, s2)
app = GUI()
app.root.mainloop()
Forgive me if this is a badly mangled way of doing things, but I'm new to development in general.
I am trying to create a window with a number of buttons using tkinter, each button having the name of a player on it using a class called from main().
I then want to be able to use the name on the button that is pressed later in the app, so I want to pass that back to main(). So, if I click on the Annie button, I want to open up a new window later called 'Options for Annie' and I'm assuming that the value 'Annie' needs to be passed back to the main function.
My main code:
<imports appear here>
def main():
players = ['Annie','Benny','Carrie','Donny']
winHome = playerWindow(root,players)
print("In main() : " + winHome.selected)
root.mainloop()
if __name__ == "__main__":
main()
My class code:
<imports appear here>
root=Tk()
class playerWindow():
def selectPlayer(self,selname):
self.selected = selname
print("In class: " + self.selected)
def __init__(self, master, players=[]):
colours = ['red','green','orange','white','yellow','blue']
self.selected = ""
r = 0
for p in players:
randcol = random.randint(0,len(colours))-1
if colours[randcol] in ('blue','green'):
fgcol='white'
else:
fgcol='black'
playername = delplayer = p
playername = Button(root, text=playername, bg=colours[randcol], fg=fgcol, width=15, command=lambda name = playername:self.selectPlayer(name)).grid(row=r,column=0)
s = ttk.Separator(root, orient=VERTICAL)
delplayer = Button(root, text='Del', bg='grey', fg='red', width=5, command=lambda name = delplayer: print("Delete Player %s" % name)).grid(row=r,column=1)
r = r + 1
Button(root, text="New Player", fg="black", command=lambda: print("New Player Functionality"), width=15).grid(row = len(players)+3,column=0)
Button(root, text="QUIT", fg="red", command=root.destroy, width=15).grid(row = len(players)+3,column=1)
What is happening is that the window gets created, the next line in main() is run (my added print statement) which is empty, obviously as main is continuing. When I press the button, the sleectPlayer function is called and works.
Somehow I need to get the value back to main() to go on to the next task using that value, however I don't seem to be able to frame the question correctly to get the answers I need.
Any help would be greatly appreciated.
I am using Python 3.5.1
You are already accessing it. I personally don't like returning to the main function, instead I suggest creating a top-level class to link back to. This should help make things flow better.
import tkinter as tk
from tkinter import ttk
import random
class PlayerWindow():
def __init__(self, master, parent, players=[]):
self._parent = parent
colours = ['red','green','orange','white','yellow','blue']
self.selected = ""
r = 0
for p in players:
randcol = random.randint(0,len(colours))-1
if colours[randcol] in ('blue','green'):
fgcol='white'
else:
fgcol='black'
playername = delplayer = p
playername = tk.Button(master, text=playername, bg=colours[randcol], \
fg=fgcol, width=15, command=lambda name = \
playername:self.selectPlayer(name)).grid(row=r,column=0)
s = ttk.Separator(master, orient=tk.VERTICAL)
delplayer = tk.Button(master, text='Del', bg='grey', fg='red', \
width=5, command=lambda name = delplayer: \
print("Delete Player %s" % name)).grid(row=r,column=1)
r = r + 1
tk.Button(master, text="New Player", fg="black", command=lambda: \
print("New Player Functionality"), width=15).\
grid(row = len(players)+3,column=0)
tk.Button(master, text="QUIT", fg="red", command=self._parent.close,
width=15).grid(row = len(players)+3,column=1)
def selectPlayer(self, selname):
self.selected = selname
print("In class: " + self.selected)
self._parent.hello() # call hello function of top-level, links back
class MyApplication(object):
def __init__(self, master):
self._master = master
players = ['Annie','Benny','Carrie','Donny']
self._player_window = PlayerWindow(master, self, players)
print("In main() : " + self._player_window.selected)
def hello(self):
name = self._player_window.selected
print("Hello, %s" % name)
def close(self):
# any other clean-up
self._master.destroy()
def main():
root = tk.Tk()
app = MyApplication(root)
root.mainloop()
if __name__ == "__main__":
main()