I am trying to figure out how to pass data from one class into another. My knowledge of python is very limited and the code I am using has been taken from examples on this site.
I am trying to pass the User name from "UserNamePage" class into "WelcomePage" class. Can someone please show me how to achieve this. I will be adding more pages and I will need to pass data between the different pages
Below is the full code - as mentioned above most of this code has come from other examples and I am using these examples to learn from.
import tkinter as tk
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import datetime
import re
def Chk_String(mystring):
Allowed_Chars = re.compile('[a-zA-Z_-]+$')
return Allowed_Chars.match(mystring)
def FnChkLogin(Page):
booAllFieldsCorrect = False;
myFName = Page.FName.get()
myFName = myFName.replace(" ", "")
myLName = Page.LName.get()
myLName = myLName.replace(" ", "")
if myFName == "":
messagebox.showinfo('Login Ifo is Missing', "Please type in your First Name")
elif not Chk_String(myFName):
messagebox.showinfo('First Name Error:', "Please only use Leter or - or _")
elif myLName == "":
messagebox.showinfo('Login Info is Missing', "Please type in your Last Name")
elif not Chk_String(myLName):
messagebox.showinfo('Last Name Error:', "Please only use Leter or - or _")
else:
booAllFieldsCorrect = True;
if booAllFieldsCorrect == True:
app.geometry("400x200")
app.title("Welcome Screen")
PageController.show_frame(app,"WelcomePage")
def FnAddButton(Page,Name,Label,Width,X,Y,FnAction):
Name = ttk.Button (Page, text=Label,width=int(Width),command=FnAction)
Name.place(x=int(X),y=int(Y))
class PageController(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top",fill="both",expand="True")
container.grid_rowconfigure(0,weight=1)
container.grid_columnconfigure(0,weight=1)
self.frames={}
for F in (UserNamePage,WelcomePage):
page_name = F.__name__
frame = F(container,self)
self.frames[page_name] = frame
frame.grid(row=0,column=0,sticky="nsew")
self.show_frame("UserNamePage")
def show_frame(self,page_name):
frame= self.frames[page_name]
frame.tkraise()
class UserNamePage(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
self.controller = controller
lblFName = Label(self,text="First Name ",relief=GROOVE,width=12,anchor=E).place(x=50,y=50)
lblLName = Label(self,text="Last Name ",relief=GROOVE,width=12,anchor=E).place(x=50,y=75)
self.FName = StringVar()
inputFName = Entry(self,textvariable=self.FName,width=25).place(x=142,y=50)
self.LName = StringVar()
inputLName = Entry(self,textvariable=self.LName,width=25).place(x=142,y=75)
cmdContinue = ttk.Button (self, text='Continue',width=9,command=lambda:FnChkLogin(self)).place(x=320,y=70)
class WelcomePage(tk.Frame):
def __init__(self,parent,controller):
tk.Frame.__init__(self,parent)
self.controller = controller
UserNamePageData = UserNamePage(parent,controller)
UserFName = str(UserNamePageData.FName)
UserLName = str(UserNamePageData.LName)
strWelcome = "Welcome " + UserFName + " " + UserLName
lblWelcome = Label(self,text=strWelcome,relief=FLAT,width=50,anchor=W).place(x=25,y=25)
if __name__ == "__main__":
app = PageController()
app.geometry("400x200")
app.title("User Page")
app.eval('tk::PlaceWindow %s center' % app.winfo_pathname(app.winfo_id()))
app.mainloop()
In the method show_frame(self,page_name) in class PageController, add the following lines
if page_name == 'WelcomePage':
self.frames['WelcomePage'].UserFName = self.frames['UserNamePage'].FName.get()
self.frames['WelcomePage'].UserLName = self.frames['UserNamePage'].LName.get()
and remove the two lines UserFName = str(UserNamePageData.FName)and UserLName = str(UserNamePageData.LName).
Explanation: it must be done in a place that has references to both frames (i.e. class PageController).
Related
I am trying to create my own python code editor. For that I tried to use the tkcode module. Tkcode partially covers my needs (colors in the text for example), but it does not have the keyboard events that Idle has (automatic indentation when pressing enter, when pressing tab puts 4 spaces, etc). Some of them I can try to recreate, but automatic indentation is difficult. Is there any way to associate the Idle events to my code editor using the idlelib without creating another window (since I am making a notebook)? I went through the source code of Idle and couldn't find the way.
I know that this site is not to ask for recommendations, but if you recommend a better module to create a text widget that allows me to create this editor, it would be great too.
This is the code I have made:
from tkcode import CodeEditor
from tkinter import ttk
import tkinter as tk
import re
class CodeEditor(CodeEditor):
def __init__(Self, *args, **kargs):
super().__init__(*args, **kargs)
Self.bind("<Return>", Self.enter)
def get_current_line(Self):
return Self.get("insert linestart", "insert lineend")
def enter(Self, event):
for index, char in enumerate(Self.get_current_line()):
if(char != " "):
break
else:
index += 1
Self.insert("insert", "\n")
Self.insert("insert", " "*index)
return "break"
class FileHandler:
def __init__(Self, progs_path, filetabs):
Self.files = {}
Self.progs_path = progs_path
Self.filetabs = filetabs
def askopen(Self):
v = tk.Toplevel()
v.transient()
v.resizable(0, 0)
prog = ttk.Entry(v)
prog.pack(padx=10, pady=10)
prog.bind("<Return>", lambda Event:(Self.open(prog.get()), v.destroy()))
def open(Self, prog):
progfile = str(prog)[0]
progfile = f"prog{progfile}00A{progfile}99.py"
if(progfile in Self.files):
text = Self.files[progfile][prog]
else:
functions = {}
name = None
with open(f"{Self.progs_path}/{progfile}") as file:
for line in file:
match = re.match("(def|class) prog(\w+)", line)
if(match):
name = match[2]
functions[name] = line
if(line.startswith(" ") and name):
functions[name] += line
Self.files[progfile] = functions
text = functions[prog]
frame = ttk.Frame(Self.filetabs)
code_editor = CodeEditor(frame, language="python", highlighter="mariana", font="TkFixedFont", autofocus=True, padx=10, pady=10)
code_editor.pack(fill="both", expand=True)
code_editor.content = text
Self.filetabs.add(frame, text="prog"+prog)
v = tk.Tk()
filetabs = ttk.Notebook()
fh = FileHandler(".", filetabs)
menubar = tk.Menu(tearoff=0)
file = tk.Menu(tearoff=0)
menubar.add_cascade(label="Archivo", menu=file)
file.add_command(label="Abrir prog", command=fh.askopen)
v["menu"] = menubar
filetabs.pack(fill="both", expand=True)
fh.open("833")
In the end I was able to fix it. I was able to recreate almost all but one of the functions. For the last one, I made an impersonator class for idlelib.editor.EditorWindow to be able to do the automatic indentation, in addition to adding two new functions to the tkcode.CodeEditor.
However, I find this solution to be very unstable. Any better answer is still appreciated c:
This is the code:
from tkcode import CodeEditor
from tkinter import ttk
from idlelib.editor import EditorWindow
import tkinter as tk
import re
class FakeEditorWindow(EditorWindow):
def __init__(Self, text):
Self.text = text
Self.indentwidth = 4
Self.tabwidth = 4
Self.prompt_last_line = ''
Self.num_context_lines = 50, 500, 5000000
Self.usetabs = False
def is_char_in_string(Self, text_index):
return 1
class CodeEditor(CodeEditor):
def __init__(Self, *args, **kargs):
super().__init__(*args, **kargs)
Self.fake_editor_window = FakeEditorWindow(Self)
Self.bind("<Tab>", Self.tab)
Self.bind("<Control-Shift_L>", Self.dedent)
Self.bind("<BackSpace>", Self.backspace)
Self.bind("<Home>", Self.inicio)
Self.bind("<Return>", Self.enter)
def undo_block_start(Self):
pass
def undo_block_stop(Self):
pass
def get_current_line(Self):
return Self.get("insert linestart", "insert lineend")
def selection_get(Self):
if(Self.tag_ranges("sel")):
return Self.get("sel.first", "sel.last")
else:
return ""
def get_selection_zone(Self):
return (map(int, Self.index('sel.first').split(".", 1)),
map(int, Self.index('sel.last').split(".", 1)))
def tab(Self, event):
selection = Self.selection_get()
if(selection):
(startline, startcolumn), (endline, endcolumn) = Self.get_selection_zone()
if(startcolumn == 0):
for line in range(startline, endline+1):
Self.insert(f"{line}.0", " "*4)
Self.tag_add("sel", f"{startline}.0", "sel.last")
Self.mark_set("insert", f"{endline+1}.0")
else:
Self.insert("insert", " "*4)
return "break"
def dedent(Self, event):
if(Self.tag_ranges("sel")):
(startline, startcolumn), (endline, endcolumn) = Self.get_selection_zone()
if(startcolumn == 0):
for line in range(startline, endline+1):
if(Self.get(f"{line}.0", f"{line}.4") == " "*4):
Self.delete(f"{line}.0", f"{line}.4")
def backspace(Self, event):
if(not Self.tag_ranges("sel") and Self.get("insert linestart", "insert").isspace()):
cursor_line, cursor_col = map(int, Self.index("insert").split(".", 1))
Self.delete(f"{cursor_line}.{cursor_col-4}", "insert")
return "break"
def inicio(Self, event):
cursor_line, cursor_column = map(int, Self.index('insert').split(".", 1))
if(not Self.get("insert linestart", f"{cursor_line}.{cursor_column}").isspace()):
for i in range(cursor_column, -1, -1):
if(Self.get("insert linestart", f"{cursor_line}.{i}").isspace()):
Self.mark_set("insert", f"{cursor_line}.{i}")
return "break"
def enter(Self, event):
return EditorWindow.newline_and_indent_event(Self.fake_editor_window, event)
class FileHandler:
def __init__(Self, progs_path, filetabs):
Self.files = {}
Self.progs_path = progs_path
Self.filetabs = filetabs
def askopen(Self):
v = tk.Toplevel()
v.transient()
v.resizable(0, 0)
prog = ttk.Entry(v)
prog.pack(padx=10, pady=10)
prog.bind("<Return>", lambda Event:(Self.open(prog.get()), v.destroy()))
def open(Self, prog):
progfile = str(prog)[0]
progfile = f"prog{progfile}00A{progfile}99.py"
if(progfile in Self.files):
text = Self.files[progfile][prog]
else:
functions = {}
name = None
with open(f"{Self.progs_path}/{progfile}") as file:
for line in file:
match = re.match("(def|class) prog(\w+)", line)
if(match):
name = match[2]
functions[name] = line
if(line.startswith(" ") and name):
functions[name] += line
Self.files[progfile] = functions
text = functions[prog]
frame = ttk.Frame(Self.filetabs)
code_editor = CodeEditor(frame, language="python", highlighter="mariana", font="TkFixedFont", autofocus=True, padx=10, pady=10)
code_editor.pack(fill="both", expand=True)
code_editor.content = text
Self.filetabs.add(frame, text="prog"+prog)
v = tk.Tk()
filetabs = ttk.Notebook()
fh = FileHandler(".", filetabs)
menubar = tk.Menu(tearoff=0)
file = tk.Menu(tearoff=0)
menubar.add_cascade(label="Archivo", menu=file)
file.add_command(label="Abrir prog", command=fh.askopen)
v["menu"] = menubar
filetabs.pack(fill="both", expand=True)
fh.open("833")
I have two python files gui.py, student.py. i have imported tkinter, i will ask the user to enter their name, id, email, and address, Using tkinter widget i will display all in a list. How to do this using class ?
this is gui.py
import tkinter
import student
class MyGUI:
def __init__(self):
self.__students = []
# Create the main window widget
self.main_window = tkinter.Tk()
self.name_f = tkinter.Frame(self.main_window)
self.id_f = tkinter.Frame(self.main_window)
self.email_f = tkinter.Frame(self.main_window)
self.addy_f = tkinter.Frame(self.main_window)
self.buttons_f = tkinter.Frame(self.main_window)
# Create a Label and Entry widget for each item in
# the Student class
self.name_l = tkinter.Label(self.name_f, text='Name: ')
self.name_e = tkinter.Entry(self.name_f, width=10)
self.id_l = tkinter.Label(self.id_f, text='ID: ')
self.id_e = tkinter.Entry(self.id_f, width=10)
self.email_l = tkinter.Label(self.email_f, text='Email: ')
self.email_e = tkinter.Entry(self.email_f, width=10)
self.addy_l = tkinter.Label(self.addy_f, text='Address: ')
self.addy_e = tkinter.Entry(self.addy_f, width=10)
self.add_b = tkinter.Button(self.buttons_f, text='Add Current Data', command=self.add)
self.display_b = tkinter.Button(self.buttons_f, text='List All', command=self.display)
self.quit_b = tkinter.Button(self.buttons_f, text='Quit', command=self.main_window.destroy)
self.name_l.pack(side='left')
self.name_e.pack(side='left')
self.id_l.pack(side='left')
self.id_e.pack(side='left')
self.email_l.pack(side='left')
self.email_e.pack(side='left')
self.addy_l.pack(side='left')
self.addy_e.pack(side='left')
self.add_b.pack(side='left')
self.display_b.pack(side='left')
self.quit_b.pack(side='left')
self.name_f.pack()
self.id_f.pack()
self.email_f.pack()
self.addy_f.pack()
self.buttons_f.pack()
#Enter the tkinter main loop
tkinter.mainloop()
def add(self):
# we will do this in class
pass
def display(self):
# we will do this in class
pass
# Create an instance of the MyGUI class
my_gui = MyGUI()
and this is the student.py
class Student:
# this a comment
# most languages define attributes sep
# Declare String name
def setName(self, n):
self.name = n
def setId(self, i):
self.sid = i
def setEmail(self, e):
# check to see if e has an # sign
self.email = e
def setAddy(self, a):
self.addy = a
def getName(self):
return self.name
def getId(self):
return self.sid
def getEmail(self):
return self.email
def getAddy(self):
return self.addy
def printInfo(self):
info = "Name: "
info += self.name
info += '\nID: '
info += self.sid
info += '\nEmail: '
info += self.email
info += '\nAddress: '
info += self.addy
info += '\n'
return info
Asking for code solutions to something you should be learning yourself probably isn't a good idea.
Just look up the documentation for TKinter here: https://docs.python.org/3/library/tkinter.html
As a note, you may want to consider opening separate windows when displaying the information. When I first learned TKinter, I first practiced by printing all my data to the console with the print command before trying to force them into tables.
Also, consider fleshing out the GUI and make it look like a table. Give each label a fixed length and each box a fixed length, this will make it look better.
A good example of this in action is on this amazing website for learning TKinter: http://www.tkdocs.com/tutorial/firstexample.html
Just scroll down until you find the Python implementation of the code :)
I made this simple program that translates from English to a completely different one (randomized English), when it displays the translation it shows spaces as { }. Any suggestions?
from tkinter import *
english = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t',
'u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','!',
'\"','#','$','%','&','\'','\'','(',')','*','+',',','-','.','/',':',';','?','#','[','\\',']','^','_','`','{','|','}','~',' ', ',','\t','\n','\r','\x0b','\x0c']
potatish =['0','1','2','3','4','5','6','7','8','9','a','v','l','d','e','z','j','s','i','x','q','u','f','b','o','y','c','m','t',
'k','p','g','h','n','r','w','A','V','L','D','E','Z','J','S','I','X','Q','U','F','B','O','Y','C','M','T','K','P','G','H','N','R','W','!',
'\"','#','$','%','&','\'','\'','(',')','*','+',',','-','.','/',':',';','?','#','[','\\',']','^','_','`','{','|','}','~',' ', ',','\t','\n','\r','\x0b','\x0c']
class Program(Frame):
""" A Program to translate """
def __init__ (self, master):
"""Initialise the frame"""
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""Buttons!!!"""
#Text
self.text = Label(self, text = "Please enter some text:")
self.text.grid()
#Field
self.user = Entry(self)
self.user.grid()
#Button
self.translate = Button(self, text = "Translate")
self.translate.grid()
self.translate["command"] = self.update_console
#Output
self.output = Label(self, text = "Output:\n")
self.output.grid()
#finished
self.finished = Label(self, text = "")
self.finished.grid()
def update_console(self):
"""Updates output"""
self.trans = self.translatedef()
self.finished["text"] = self.trans
def translatedef(self):
f = []
i = -1
j = -1
text = self.user.get()
while i != -2:
i+=1
try:
l = english.index(text[i])
f.append(potatish[l])
except:
while j != -2:
j+=1
try:
return f
except:
break
break
root = Tk()
root.title("Potatish")
root.geometry("500x300")
app = Program(root)
root.mainloop()
You are setting the text of the Label to a list, not a string. The empty element of that list is being displayed as {} by Tkinter.
To correct it, form a string from your list before you send it to the Label:
def update_console(self):
"""Updates output"""
self.trans = ''.join(self.translatedef())
self.finished["text"] = self.trans
I am currently trying to implement a GUI for a task at work. I have found some open source code (see below) where we make a GUI having 3 pages where one can go between the pages using next/previous buttons. If you run the code you'll see what each button and so on is indended to do.
However, when you run the code and click the "count++" button, the overall count increases by one and not the count for the individual page (e.g. being on page 1 and clicking the count++ 4 times, still makes the count for page 2 or 3, 4 as well, and not zero). The same problem occurs when I try to update the text in each of the textboxes on each page (supposed to be number of clicks), as it won't update. I am not sure how to actually get to the textframe for each individual page.
Any suggestions on where to go from here? In the long run I would like to have scroll-down menus where the selections will be put onto each individual text-frame.
Thanks,
import ttk
from Tkinter import *
import tkMessageBox
class Wizard(object, ttk.Notebook):
def __init__(self, master=None, **kw):
npages = kw.pop('npages', 3)
kw['style'] = 'Wizard.TNotebook'
ttk.Style(master).layout('Wizard.TNotebook.Tab', '')
ttk.Notebook.__init__(self, master, **kw)
self._children = {}
self.click_count = 0
self.txt_var = "Default"
for page in range(npages):
self.add_empty_page()
self.current = 0
self._wizard_buttons()
def _wizard_buttons(self):
"""Place wizard buttons in the pages."""
for indx, child in self._children.iteritems():
btnframe = ttk.Frame(child)
btnframe.pack(side='left', fill='x', padx=6, pady=4)
txtframe = ttk.Frame(child)
txtframe.pack(side='right', fill='x', padx=6, pady=4)
nextbtn = ttk.Button(btnframe, text="Next", command=self.next_page)
nextbtn.pack(side='top', padx=6)
countbtn = ttk.Button(txtframe, text="Count++..", command=self.update_click)
countbtn.grid(column=0,row=0)
txtBox = Text(txtframe,width = 50, height = 20, wrap = WORD)
txtBox.grid(column=1,row=0)
txtBox.insert(0.0, self.txt_var)
rstbtn = ttk.Button(btnframe, text="Reset count!", command=self.reset_count)
rstbtn.pack(side='top', padx=6)
if indx != 0:
prevbtn = ttk.Button(btnframe, text="Previous",
command=self.prev_page)
prevbtn.pack(side='right', anchor='e', padx=6)
if indx == len(self._children) - 1:
nextbtn.configure(text="Finish", command=self.close)
def next_page(self):
self.current += 1
def prev_page(self):
self.current -= 1
def close(self):
self.master.destroy()
def add_empty_page(self):
child = ttk.Frame(self)
self._children[len(self._children)] = child
self.add(child)
def add_page_body(self, body):
body.pack(side='top', fill='both', padx=6, pady=12)
def page_container(self, page_num):
if page_num in self._children:
return self._children[page_num]
else:
raise KeyError("Invalid page: %s" % page_num)
def _get_current(self):
return self._current
def _set_current(self, curr):
if curr not in self._children:
raise KeyError("Invalid page: %s" % curr)
self._current = curr
self.select(self._children[self._current])
current = property(_get_current, _set_current)
def update_click(self):
self.click_count += 1
message = "You have clicked %s times now!" % str(self.click_count)
tkMessageBox.showinfo("monkeybar", message)
self.txt_var = "Number of clicks: %s" % str(self.click_count) #this will not change the text in the textbox!
def reset_count(self):
message = "Count is now 0."
#ctypes.windll.user32.MessageBoxA(0, message, "monkeybar", 1)
tkMessageBox.showinfo("monkeybar", message)
self.click_count = 0
def combine_funcs(*funcs):
def combined_func(*args, **kwargs):
for f in funcs:
f(*args, **kwargs)
return combined_func
def demo():
root = Tk()
nbrpages = 7
wizard = Wizard(npages=nbrpages)
wizard.master.minsize(400, 350)
wizard.master.title("test of GUI")
pages = range(nbrpages)
for p in pages:
pages[p] = ttk.Label(wizard.page_container(p), text='Page %s'%str(p+1))
wizard.add_page_body(pages[p])
wizard.pack(fill='both', expand=True)
root.mainloop()
if __name__ == "__main__":
demo()
Your update_click method operate on the attribute click_count of your wizard. If you want different count, you could either create a class for your pages and thus, each object would manage its own count, or manage several counter, for instance in a list, the same way you handle your _children list.
For the former case, you can create a page class inheriting ttk.Frame with the body of your _wizard_buttons loop as constructor. In the later case, you could try something like this
class Wizard(object, ttk.Notebook):
def __init__(self, master=None, **kw):
[...]
#replace self.click_count = 0 with
self.click_counters = [0 for i in range(npages)]
def update_click(self):
self.click_counters[self.current] += 1
# and so on...
Regarding the Text widget update, you can not handle it though a variable, it works with Entry(one line text field) but not on Text (multiline, rich text field). If you continue with Text, the usual recipe to what you seems to want is
text.delete(1.0, END)
text.insert(END, content)
So I am trying to build a GUI where I enter some information, clear the entry fields, and then add new entry fields. However, when I try to clear the frame from the root via grid_remove, the application freezes. The relevant code is below.
import tkinter
from threading import Thread
class PinGui(tkinter.Frame):
def __init__(self, client):
self.client = client
self.root = client.root
self.add_pin = client.add_pin
self.end = client.end
tkinter.Frame.__init__(self, self.root)
self.grid_widgets()
self.grid_buttons()
self.bind_keys()
self.grid(padx=32, pady=32)
def grid_buttons(self, b1='Add', b2='Reset', b3='Quit'):
self.addButton = tkinter.Button(self, text=b1, command=self.validate)
self.resetButton = tkinter.Button(self, text=b2, command=self.reset)
self.quitButton = tkinter.Button(self, text=b3, command=self.end)
self.buttons = [self.addButton, self.resetButton, self.quitButton]
for i in range(3): self.buttons[i].grid(row=i, column=11)
def grid_widgets(self):
widths = [3,3,4,4,6]
self.pin_vars = []
self.pin_fields = []
for i in range(5):
self.pin_vars.append(tkinter.StringVar())
self.pin_fields.append(
tkinter.Entry(self,width=widths[i], textvariable=self.pin_vars[i])
)
self.pin_fields[i].grid(row=0, column=2*i, padx=3)
self.pin_fields[0].focus_set()
def bind_keys(self):
self.root.bind_all("<Return>", self.validate)
self.root.bind_all("<Escape>", self.end)
def validate(self, args=None):
self.client.pin = []
for field in self.pin_fields:
self.client.pin.append(field.get())
Thread(target=self.add_pin).start()
def ungrid(self):
for field in self.pin_fields: field.grid_remove()
for button in self.buttons: button.grid_remove()
self.display.grid_remove()
And:
class PinClient:
def __init__(self):
self.root = tkinter.Tk()
self.gui = PinGui(self)
self.pins = []
def add_pin(self):
self.gui.reset()
if 'display' in self.__dict__:
self.pins.append(self.pin)
self.display.add_pin(self.pin)
self.ping("Enter PIN for Comp %s:" % len(self.display.col1))
if len(self.display.col1) > 5:
self.end() # THIS IS WHERE IT FREEZES
else:
self.subject = self.pin
self.display = Display(self.root, self.pin)
self.display.grid(row=1, padx=32, pady=32)
self.ping("Enter PIN for Comp 1:")
def ping(self, msg):
self.gui.d_var.set(msg)
def end(self, args=None):
self.gui.ungrid()
class Display(tkinter.Frame):
def __init__(self, master, pin):
tkinter.Frame.__init__(self, master)
self.pin = pin
self.col1 = []
self.col2 = []
self.col1.append(tkinter.Label(self, text="Subject:"))
self.col2.append(tkinter.Label(self, text=self.pin))
self.grid_widgets()
def grid_widgets(self):
self.ungrid()
for i in range(len(self.col1)):
self.col1[i].grid(row=i, column=0)
self.col2[i].grid(row=i, column=1)
def ungrid(self):
for i in range(len(self.col1)):
self.col1[i].grid_remove()
self.col2[i].grid_remove()
def add_pin(self, pin):
self.col1.append(tkinter.Label(self, text="Comp %s:" % len(self.col1)))
self.col2.append(tkinter.Label(self, text=pin))
i = len(self.col1)
self.col1[i-1].grid(row=i, column=0)
self.col2[i-1].grid(row=i, column=1)
It seems to be somehow related to the threading, but I haven't been able to find any reason this should freeze. Any help is greatly appreciated!
Tkinter is not thread safe. If you do anything in a thread other than the main thread that touches a GUI object then you will get unpredictable results. Almost certainly, it is threading that is causing your problem, since you are trying to access widgets from the worker thread.