Differences in tkinter Window between normal and debugging mode - python

Code:
fields = ['Label1','Label2','Label3','Label4','Label5','Label6']
selected_item = ['Entry1','Entry2','Entry3','Entry4','Entry5','Label6']
stringvar_list = [tk.StringVar() for s in range(len(selected_item))]
for var in range(len(stringvar_list)):
stringvar_list[var].set(selected_item[var])
for i in range(len(fields)):
lbl = ttk.Label(root,text=fields[i])
ent = ttk.Entry(root,textvariable=stringvar_list[i])
lbl.grid(row=row,column=col,padx=2,pady=2)
ent.grid(row=row,column=col+1,padx=2,pady=2)
row+=1
When I run this code, I get this(the entries are not filled):
But when I run the same code in debugging mode,no changes - I just skip through the breakpoint, I get this(Entries are filled):
I'm using VS Code, if it matters.
Extended Code:
def modify(fields):
# fields = fields[1:] #Original
fields = ['Label1','Label2','Label3','Label4','Label5','Label6'] # For Simplicity and Underestanding
# selected_item = tree.item(tree.selection()[0])['values'][1:] #Original
selected_item = ['Entry1','Entry2','Entry3','Entry4','Entry5','Label6'] # For Simplicity and Underestanding
modify_top = tk.Toplevel(root)
stringvar_list = [tk.StringVar() for s in range(len(selected_item))]
for var in range(len(stringvar_list)):
stringvar_list[var].set(selected_item[var])
row = 0
col = 0
frm = ttk.Frame(modify_top)
for i in range(len(fields)):
lbl = ttk.Label(frm,text=fields[i])
ent = ttk.Entry(frm,textvariable=stringvar_list[i])
lbl.grid(row=row,column=col,padx=2,pady=2)
ent.grid(row=row,column=col+1,padx=2,pady=2)
row+=1
frm.grid(sticky='nsew',row=0,column=0,padx=30,pady=20)
make_changes_btn = ttk.Button(modify_top,text='Make Changes',command = lambda : make_changes())
make_changes_btn.grid(row=1,column=0)
Issues:
As #acw1668 commented, making stringvar_list global did the job, but I'm referencing it's values in the same function, so that shouldn't be a problem.
Even if the issue is with the scope, then why does the program work fine in debugging mode?

Related

Is there a way of getting data from entries by rows from a table of entries in Tkinter?

So far I have a portion of code for a function that works fine as is for generating a table off of user input and then getting data from the table generated to be used in a line graph. However, the solution as it stands creates one massive list by iterating through every entry's data and is then graphed as one massive line graph. I intended for the function to create lists from each row of the table which is then inserted into a master list for pyplot to then graph as multiple lines on the same graph. Is there a way to achieve this? This is the code I am using:
import tkinter as tk
import matplotlib.pyplot as plt
graphinput = tk.Tk()
def opentable():
global total_rows
global total_columns
total_rows = int(yaxis.get())
total_columns = int(xaxis.get())
table = tk.Toplevel(graphinput)
table.resizable(0,0)
table.title("Table")
def tcompile():
masterlines = []
for cell in my_entries:
print(cell.get())
masterlines.append(int(cell.get()))
plt.plot(masterlines)
plt.show()
my_entries = []
for i in range(total_rows):
for j in range(total_columns):
cell = tk.Entry(table,width=20,font=('Agency FB',15))
cell.grid(row=i,column=j)
my_entries.append(cell)
tblframe = tk.Frame(table,bd=4)
tblframe.grid(row=i+1,column=j)
compbtn = tk.Button(tblframe,font=("Agency FB",20),text="Compile",command=tcompile)
compbtn.grid(row=0,column=0)
tablegrid = tk.Frame(graphinput,bd=4)
tablegrid.pack()
xlabel = tk.Label(tablegrid,text="Column Entry")
xlabel.grid(row=0,column=0)
ylabel = tk.Label(tablegrid,text="Row Entry")
ylabel.grid(row=0,column=1)
xaxis = tk.Entry(tablegrid)
xaxis.grid(row=1,column=0)
yaxis = tk.Entry(tablegrid)
yaxis.grid(row=1,column=1)
framebtn = tk.Button(tablegrid,text="Create",command=opentable)
framebtn.grid(row=3,column=0)
graphinput.mainloop()
Try something like this:
import tkinter as tk
def tcompile():
masterlines = []
for i in range(total_rows):
row = []
for j in range(total_columns):
data = my_entries[i*total_columns+j].get()
# data = int(data) # Removed for testing purposes
row.append(data)
masterlines.append(row)
print(masterlines)
root = tk.Tk()
total_rows = 3
total_columns = 4
my_entries = []
for i in range(total_rows):
for j in range(total_columns):
cell = tk.Entry(root)
cell.grid(row=i, column=j)
my_entries.append(cell)
# Add a button for testing purposes
button = tk.Button(root, text="Click me", command=tcompile)
button.grid(row=1000, columnspan=total_columns)
root.mainloop()
The key is to use my_entries[i*total_columns+j] to get the entry in row i and column j.
Note: I didn't add the matplotlib stuff because I don't really know how it works.

UnboundLocalError: local variable 'qn' referenced before assignment

I'm getting the error "UnboundLocalError: local variable 'qn' referenced before assignment" on running the code. Why is that? How can I correct it? I'm new to tkinter so please try to keep it simple. This is part of the code for a game I was writing. It would be a great help if I could get an answer soon
from tkinter import *
from tkinter import messagebox
from io import StringIO
root = Tk()
root.title("Captain!")
root.geometry("660x560")
qn = '''1$who are you?$char1$i am joe$3$i am ben$2
2$what are you?$char2$i am a person$1$i am nobody$3
3$how are you?$char3$i am fine$2$i'm alright$1'''
var = '''1$10$-35$20$15$-20
2$9$7$30$-5$-15
3$10$-25$-15$10$5'''
class Game :
def __init__(self):
self.m_cur = {1:["Military",50]}
self.c_cur = {1:["People's",50]}
self.r_cur = {1:["Research",50]}
self.i_cur = {1:["Industrial",50]}
self.p_cur = {1:["Research",50]}
#function to clear all widgets on screen when called
def clear(self):
for widget in root.winfo_children():
widget.destroy()
#function to quit the window
def exit(self):
msg = messagebox.askquestion("Thank you for playing","Are you sure you want to exit?")
if msg == "yes" :
root.destroy()
else:
Game.main(self)
#start function
def start(self):
Label(root,text="Hello, what should we call you?",font=("segoe print",20)).grid(row=0,column=0)
name = Entry(root,width=20)
name.grid(row=1,column=0)
Button(root,text="Enter",font=("segoe print",20),command=lambda: Game.main(self)).grid(row=1,column=1)
self.name=name.get()
#main function
def main(self):
Game.clear(self)
Label(root,text="Welcome to the game",font=("segoe print",20)).grid(row=0,column=0)
Label(root,text='What do you want to do?',font=("segoe print",20)).grid(row=1,column=0)
Button(root,text="Start Game",font=("segoe print",20),command=lambda: Game.qn_func(self,1)).grid(row=2,column=0)
Button(root,text="Exit Game",font=("segoe print",20),command=lambda: Game.exit(self)).grid(row=3,column=0)
#function to check variables and display game over
def game_over(self,x_cur):
if x_cur[1][1]<=0 or x_cur[1][1]>=100 : #condition to check game over
Game.clear(self)
Label(root,text=x_cur)
Label(root,text="GAME OVER",font=("ariel",20)).place(relx=0.5,rely=0.5,anchor=CENTER)
Button(root,text="Continue",font=("segoe print",20),command=lambda: Game.main(self)).place(relx=0.5,rely=0.6)
#function to display question and variables
def qn_func(self,qn_num) :
Game.clear(self)
#accessing the questions
q_file = StringIO(qn)
#reading the question, options, next qn numbers and the character name from the file
qn_list = q_file.readlines()
qn = qn_list[qn_num-1].strip().split("$")[1]
char_name = qn_list[qn_num-1].strip().split("$")[2]
qn1 = qn_list[qn_num-1].strip().split("$")[3]
qn2 = qn_list[qn_num-1].strip().split("$")[5]
n_qn1 = int(qn_list[qn_num-1].strip().split("$")[4])
n_qn2 = int(qn_list[qn_num-1].strip().split("$")[6])
#displaying the character name and the question as a label frame widget with character name as parent
label_frame = LabelFrame(root,text = char_name,font = ("segoe print",20))
label = Label(label_frame,text = qn,font = ("segoe print",20))
label_frame.place(relx=0.5,rely=0.5,anchor=CENTER)
label.pack()
q_file.close()
#accessing variables
v_file = StringIO(var)
#reading values of variables from file
v_list = v_file.readlines()
self.r_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[1])
self.c_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[2])
self.i_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[3])
self.m_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[4])
self.p_cur[1][1] += int(v_list[qn_num-1].strip().split("$")[5])
#running each variable through game_over to see if you are dead
Game.game_over(self,self.r_cur)
Game.game_over(self,self.c_cur)
Game.game_over(self,self.i_cur)
Game.game_over(self,self.m_cur)
Game.game_over(self,self.p_cur)
#defining the Doublevar variables
s_var1 = DoubleVar()
s_var2 = DoubleVar()
s_var3 = DoubleVar()
s_var4 = DoubleVar()
s_var5 = DoubleVar()
#setting the values in the scales
s_var1.set(self.r_cur[1][1])
s_var2.set(self.c_cur[1][1])
s_var3.set(self.i_cur[1][1])
s_var4.set(self.m_cur[1][1])
s_var5.set(self.p_cur[1][1])
#variables as scale widgets
scale1 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var1)
scale2 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var2)
scale3 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var3)
scale4 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var4)
scale5 = Scale(root,from_=100,to=0,orient=VERTICAL,sliderlength=10,variable=s_var5)
#displaying the scale widgets on the screen
scale1.grid(row=0,column=0)
scale2.grid(row=0,column=1)
scale3.grid(row=0,column=2)
scale4.grid(row=0,column=3)
scale5.grid(row=0,column=4)
#disabling the scales
scale1.config(state=DISABLED)
scale2.config(state=DISABLED)
scale3.config(state=DISABLED)
scale4.config(state=DISABLED)
scale5.config(state=DISABLED)
v_file.close()
#displaying the buttons on the screen
Button(root,text=qn1,command=lambda: Game.qn_func(self,n_qn1)).place(relx=0.2,rely=0.7,anchor=W,width=200,height=50)
Button(root,text=qn2,command=lambda: Game.qn_func(self,n_qn2)).place(relx=0.8,rely=0.7,anchor=E,width=200,height=50)
game = Game()
game.start()
root.mainloop()
You can see in this particular section that you have called on 'qn' before it was even defined:
#function to display question and variables
def qn_func(self,qn_num) :
Game.clear(self)
#accessing the questions
q_file = StringIO(qn)
#reading the question, options, next qn numbers and the character name from the file
qn_list = q_file.readlines()
qn = qn_list[qn_num-1].strip().split("$")[1]
The variable needs to be assigned a value before being used. Here, you call q_file = StringIO(qn) before you have defined qn = qn_list....

How do I determine what checkbuttons selected when created dynamically?

I am creating a custom file chooser in tkinter. I am creating a grid of checkbuttons representing files in a directory. Right now all i want to do is get a list of the file names a user chooses. As of now my code displays the gui nicely but when I try to determine what boxes the user checked it's not working. I'm not sure what I'm doing wrong. Most likely in the way i'm setting the variable for the checkbutton. I know this would be easy for a python pro but i'm not a pro so any help would be greatly appreciated. See my code below. Apologies ahead of time for the huge amount of code but i'm not sure where i'm going wrong so i put it all in.
Mark
class scareGUI:
def __init__(self, master):
self.selectedFileName = StringVar()
#filter non video file types
includes = ['*.mp4','*.py']
includes = r'|'.join([fnmatch.translate(x) for x in includes])
#master.attributes('-zoomed', True)
self.frame_header = ttk.Frame(master)
self.frame_header.pack()
ttk.Label(self.frame_header, text="TerrorForm ScareBox").grid(row=0, column = 0, rowspan = 2)
self.frame_files = ttk.Frame(master)
self.frame_files.pack()
self.frame_footer = ttk.Frame(master)
self.frame_footer.pack()
#pull file names from file system
for root, dirs, self.files in os.walk('./movies'):
self.files = [os.path.join(root, f) for f in self.files]
self.files = [f for f in self.files if re.match(includes, f)]
#Determine number of rows in grid
numfiles = len(self.files)
dividesBy = False
numRows = IntVar()
numColumns = 4
while (dividesBy == False):
if(numfiles % numColumns == 0):
numRows=int(numfiles/numColumns)
dividesBy = True
else:
numfiles+=1
#Print Check Boxes in Grid layout
filmIcon = PhotoImage(file='tf_film_icon.gif')
i=0
self.checkedFiles=[None]*len(self.files)
for r in range(numRows):
for c in range(4):
if (i<len(self.files)):
self.checkedFiles[i] = IntVar()
checkbutton = ttk.Checkbutton(self.frame_files, text=self.files[i], variable=self.checkedFiles[i])
checkbutton.config(image = filmIcon,compound = TOP)
checkbutton.image = filmIcon
checkbutton.grid(row = r, column = c)
i += 1
def getChosenFiles(self):
self.chosenFiles=[]
for x in range(len(self.files)):
if(self.checkedFiles[x].get()):
self.chosenFiles.append(self.files[x])
print (self.chosenFiles[0])
return self.chosenFiles
def main():
root = Tk()
scaregui = scareGUI(root)
root.mainloop()
if __name__ == "__main__": main()

Entries in Tkinter

I'd like to make a program which takes an integer from user and makes as many entries in a Tkinkter window. Then It'll make a graph base on them but for now I do not know how to make as many entries in my window. I tried something like this below but It does not work. Please help.. edit: oh and It's PyDev for Eclipse python 2.75
# -*- coding: utf-8 -*-
#import matplotlib.pyplot as mp
import Tkinter as T, sys
def end():
sys.exit()
def check():
z = e.get()
try:
z = int(z)
e.config(bg = 'green')
e.after(1000, lambda: e.config(bg = 'white'))
x = []
for i in (0,z):
x.append(e = T.Entry(main, justify = 'center'))
x[i].pack()
except:
e.config(bg = 'red')
e.after(1000, lambda: e.config(bg = 'white'))
z = 0
main = T.Tk()
main.title('something')
main.geometry('600x600')
main.config(bg = "#3366ff")
e = T.Entry(main,justify = 'center')
l = T.Label(main,text = 'Give me an N =',bg = '#3366ff')
b1 = T.Button(main, text = 'OK', command = check)
b = T.Button(main,text = 'Zakończ', command = end)
l.pack()
e.pack()
b1.pack()
b.pack()
main.mainloop()
Make youre for-loop look like this:
for i in range(0,z):
x.append( T.Entry(main, justify = 'center'))
x[i].pack()
you need to use range because when you dont it is only iterating through twice because it thinks its iterationg through a 2 item tuple instead of a list of numbers
also get rid of the e = so that it is just appending a new entry each time

Python sqlite3, tkinter display multible rows

I am new to python and recently i make dictionary using Python and Sqlite3 with tkinter.
When I run the code it returns multiple line in IDLE but in the GUI its only display the last result. I would like to display all the information in the GUI. Thanks you for any help and suggestion.
import tkinter
import sqlite3
class Dictionary:
def __init__(self,master =None):
self.main_window = tkinter.Tk()
self.main_window.title("Lai Mirang Dictionary")
self.main_window.minsize( 600,400)
self.main_window.configure(background = 'paleturquoise')
self.frame1 = tkinter.Frame()
self.frame2= tkinter.Frame(bg = 'red')
self.frame3 =tkinter.Text( foreground = 'green')
self.frame4 = tkinter.Text()
self.lai_label = tkinter.Label(self.frame1,anchor ='nw',font = 'Times:12', text = 'Lai',width =25,borderwidth ='3',fg='blue')
self.mirang_label = tkinter.Label(self.frame1,anchor ='ne',font = 'Times:12', text = 'Mirang',borderwidth ='3',fg ='blue')
self.lai_label.pack(side='left')
self.mirang_label.pack(side = 'left')
self.kawl_buttom= tkinter.Button(self.frame2 ,fg = 'red',font = 'Times:12',text ='Kawl',command=self.dic,borderwidth ='3',)
self.lai_entry = tkinter.Entry(self.frame2, width= 28, borderwidth ='3',)
self.lai_entry.focus_force()
self.lai_entry.bind('<Return>', self.dic,)
self.lai_entry.configure(background = 'khaki')
self.lai_entry.pack(side='left')
self.kawl_buttom.pack(side = 'left')
self.value = tkinter.StringVar()
self.mirang_label= tkinter.Label(self.frame3,font = 'Times:12',fg = 'blue',textvariable = self.value,justify = 'left',wraplength ='260',width = 30, height = 15,anchor = 'nw')
self.mirang_label.pack()
self.mirang_label.configure(background = 'seashell')
self.copyright_label = tkinter.Label(self.frame4,anchor ='nw',font = 'Times:12:bold',text = "copyright # cchristoe#gmail.com",width = 30,borderwidth = 3, fg = 'purple',)
self.copyright_label.pack()
self.frame1.pack()
self.frame2.pack()
self.frame3.pack()
self.frame4.pack()
tkinter.mainloop()
self.main_window.quit()
def dic(self, event = None):
conn = sqlite3.connect('C:/users/christoe/documents/sqlite/laimirangdictionary.sqlite')
c = conn.cursor()
kawl = self.lai_entry.get()
kawl = kawl + '%'
c.execute("SELECT * FROM laimirang WHERE lai LIKE ?", (kawl,))
c.fetchall
for member in c:
out = (member)
self.value.set(out)
print(out, )
dic=Dictionary()
You need to change:
c.execute("SELECT * FROM laimirang WHERE lai LIKE ?", (kawl,))
c.fetchall
for member in c:
out = (member)
self.value.set(out)
print(out, )
To:
for member in c.execute("SELECT * FROM laimirang WHERE lai LIKE ?", (kawl,)):
current_text = self.value.get()
new_text = current_text +( "\n" if current_text else "") +" ".join(member)
self.value.set(new_text)
The new version gets the current value of the StringVar value and then appends the results returned with a space inbetween for each row returned with each row on its own line. What you were doing however involved just updating the StringVar to be the current member object, and therefore it only ever had the last values.
This is how it looks with more than one line:

Categories

Resources