Unable to increment questions from sqlite database in quiz using tkinter - python

I'm still working on my quiz program but I'm currently having an issue with getting the program to increment the questions which are retrieved from a database that I also have. When I try to move to the next record in my database I haven't been able to actually change the contents of the page, everything stays as it is and I have to this point not been able to rectify the issue. I feel as though it's an issue with my use of variable but I cant think of any way around this. Here's the section of my code where I'm having this issue:
class ques(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
fetchrecNum = "SELECT MAX(qnumber) FROM questions"
cursor.execute(fetchrecNum)
self.recNum=str(cursor.fetchall())
self.recNum=self.recNum.strip("[('")
self.recNum=self.recNum.strip("',)]")
self.recNum=int(self.recNum)
recordNum = tk.Label(self, text = self.recNum)
recordNum.pack()
self.Qn = 1
self.quizScore = 0
fetchQ = "SELECT questioncontent FROM questions WHERE qnumber=?"
cursor.execute(fetchQ, [self.Qn])
Q=str(cursor.fetchall())
Q=Q.strip("[('")
Q=Q.strip("',)]")
question = tk.Label(self, text = Q)
question.pack()
fetchA1 = "SELECT qanswer1 FROM questions WHERE qnumber=?"
cursor.execute(fetchA1, [self.Qn])
A1=str(cursor.fetchall())
A1=A1.strip("[('")
A1=A1.strip("',)]")
answer1 = tk.Label(self, text = A1)
answer1.pack()
fetchA2 = "SELECT qanswer2 FROM questions WHERE qnumber=?"
cursor.execute(fetchA2, [self.Qn])
A2=str(cursor.fetchall())
A2=A2.strip("[('")
A2=A2.strip("',)]")
answer2 = tk.Label(self, text = A2)
answer2.pack()
fetchA3 = "SELECT qanswer3 FROM questions WHERE qnumber=?"
cursor.execute(fetchA3, [self.Qn])
A3=str(cursor.fetchall())
A3=A3.strip("[('")
A3=A3.strip("',)]")
answer3 = tk.Label(self, text = A3)
answer3.pack()
fetchA4 ="SELECT qanswer4 FROM questions WHERE qnumber=?"
cursor.execute(fetchA4, [self.Qn])
A4=str(cursor.fetchall())
A4=A4.strip("[('")
A4=A4.strip("',)]")
answer4 = tk.Label(self, text = A4)
answer4.pack()
fetchcA ="SELECT correctans FROM questions WHERE qnumber=?"
cursor.execute(fetchcA, [self.Qn])
self.cA=str(cursor.fetchall())
self.cA=self.cA.strip("[('")
self.cA=self.cA.strip("',)]")
def confirmAnswer(self):
answerGiven = self.enterAnswer
correctAnswer = self.cA
if answerGiven == correctAnswer:
self.rightOrWrong.configure(text ="Correct")
self.quizScore = (self.quizScore + 1)
else:
self.rightOrWrong.configure(text="Incorrect")
if self.Qn < self.recNum:
self.Qn = (self.Qn+1)
lambda: controller.show_frame(ques)
else:
self.rightOrWrong.configure(text="Quiz Complete! Your score was: " + str(self.quizScore))
I'm not sure how else i could go about trying to get the contents of the page to change but i hope i can learn from someone else here as nobody around me is very helpful at all (including teachers) and this is the best option I have. Thanks in advance for any help.

I can't test it but I would do something like in code.
In __init__ I create empty labels and execute separated method which reads data from database and puts them in labels. later I can use this method to get next question.
To get one row from database you can use fetchone(). To get data from row you don't have to use str() and strip() but index row[0], row[1], etc. You may have to change indexes if you have columns in different order in database.
class ques(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.Qn = 1
self.quizScore = 0
self.correctAnswer = '' # <-- create it at start (and use better name)
# v-- create empty labels
self.recordNum = tk.Label(self, text='')
self.recordNum.pack()
self.question = tk.Label(self, text='')
self.question.pack()
self.answer1 = tk.Label(self, text='')
self.answer1.pack()
self.answer2 = tk.Label(self, text='')
self.answer2.pack()
self.answer3 = tk.Label(self, text='')
self.answer3.pack()
self.answer4 = tk.Label(self, text='')
self.answer4.pack()
self.update_question_number() # <-- get question number
self.update_question() # <-- get new question
def update_question_number(self)
# Get question's number
query = "SELECT MAX(qnumber) FROM questions"
cursor.execute(query)
row = cursor.fetchone()
self.recordNum['text'] = row[0]
def update_question(self):
# Get new question
query = "SELECT * FROM questions WHERE qnumber=?"
cursor.execute(query, (self.Qn,))
row = cursor.fetchone()
self.question['text'] = row[0]
self.answer1['text'] = row[1]
self.answer2['text'] = row[2]
self.answer3['text'] = row[3]
self.answer4['text'] = row[4]
self.correctAnswer = row[5]
def confirmAnswer(self):
if self.enterAnswer == self.correctAnswer:
self.rightOrWrong['text'] = "Correct"
self.quizScore += 1
else:
self.rightOrWrong['text'] = "Incorrect"
if self.Qn < self.recNum:
self.Qn += 1 # <-- get new question
self.update_question() # <-- get new question
#lambda: controller.show_frame(ques) # ??? do you have to change frame ???
else:
self.rightOrWrong.['text'] = "Quiz Complete! Your score was: {}".format(self.quizScore)

Related

Problem printing the contents of a text box in another textbox multiline

I am making a small app with Tkinter, for educational purposes, which consists of pressing a button and displaying the contents of a textobox ... in another multiline textbox.
The problem is that you see this:
<bound method Text.get of <tkinter.Text object.! Text2 >>
and not the content that I manually write of the textobox. The textbox that I would like to print in the multiline textobox (called text) is called textbox_test. Textbox_test is called
A = f "{test_textbox.get} {'' .join (word2)} {abitanti} abitanti su un'area di {superficie}".
Questo è il textobox
test_textbox = Text(window,width=10,height=1)
test_textbox.pack()
test_textbox.place(x=5, y=100)
How can I remove the error above and correctly display the text of a textbox? I attach complete code. Thank you
from tkinter import *
from tkinter import ttk
import tkinter as tk
import sqlite3
import random
window=Tk()
window.title("xxxxxxxx")
window.geometry("750x750")
window.configure(bg='#78c030')
con = sqlite3.connect('/home/xxxxxxxxxxx/Database.db')
cursor = con.cursor()
# Search Data
def city(name_city):
name_city = city.get()
cursor.execute('SELECT * FROM Info WHERE City =?',(name_city,))
results = cursor.fetchone()
return results
# Print Data in textbox multiline
def write():
name_city = city.get
results = city(name_city)
inhabitants = results[2]
surface = results[3]
if categoria.get() == "Test 1" and sottocategoria.get() == "Test 1.1":
cursor.execute('SELECT xxxxxxxx FROM TableExample ORDER BY RANDOM() LIMIT 1')
word2 = cursor.fetchone()
text.delete(1.0,END)
A= f"{test_textbox.get} {''.join(word2)} {inhabitants} inhabitants on an area of {surface}"
B= f"Che sale a"
text.insert(tk.END, random.choice([A, B]))
button2 = Button(window, text="Button2", bg='white', command = write)
button2.pack()
button2.place(x=5, y=330)
### TEXTBOX MULTILINE ###
text = Text(window,width=63,height=38)
text.pack()
text.place(x=180, y=24)
### TEXTBOX ###
test_textbox = Text(window,width=10,height=1)
test_textbox.pack()
test_textbox.place(x=5, y=100)
### CATEGORIA E SOTTO CATEGORIA ###
cat=StringVar()
sub_cat=StringVar()
def change_val(*args):
if cat.get() == "Test 1":
sottocategorias = ["Test 1.1", "Test 1.2", "Test 1.3"]
sottocategoria.config(values=sottocategorias)
else:
sottocategorias = ["aaaa"]
sottocategoria.config(values=sottocategorias)
categorias=["Test 1", "Test 2", "Test 3"]
categoria=ttk.Combobox(window,value=categorias,textvariable=cat,width=16)
categoria.place(x=5, y=25)
cat.set("Scegliere categoria")
sottocategorias=["aaaa"]
sottocategoria=ttk.Combobox(window,textvariable=sub_cat,value=sottocategorias,
width=16)
sottocategoria.place(x=5, y=55)
cat.trace("w",change_val)
### COMBOBOX ###
def combo_nation():
cursor.execute('SELECT DISTINCT Nation FROM Info')
result=[row[0] for row in cursor]
return result
def combo_city(event=None):
val = city.get()
cursor.execute('SELECT City FROM Info WHERE Nation = ?', (val,))
result = [row[0] for row in cursor]
city['value'] = result
city.current(0)
return result
nation=ttk.Combobox(window,state="readonly")
nation['value'] = combo_nation()
nation.bind('<<ComboboxSelected>>', combo_city)
nation.place(x=5, y=150,height = 25, width = 180)
city=ttk.Combobox(window,state="readonly")
city.place(x=5, y=180, height = 25, width = 180)
window.mainloop()
IMPORTANT: If you try to change to A = f "{test_textbox.get (" 1.0 "," end-1c ")} {'' .join (word2)}, that's not good. The app won't open. Without this code instead opens
As #BryanOakley said in comment you need get with () to run it and widget Text needs it with arguments like
A = f"{test_textbox.get('1.0','end-1c')} ...
It didn't work because it was only part which you would have to replace in full text, but it seems you replaced all text. Because you didn't run code in console so you couldn't see error message which could explain problem
Full line should be
A = f"{test_textbox.get('1.0','end-1c')} {''.join(word2)} {inhabitants} inhabitants on an area of {surface}"

Why wont my code return a value for the data input into a tkinter text box

I have written this code and for some reason it refuses to return any sort of value or input for slef.REV when used in the function post(self) however it will return a value when I try and return a value in the getlen() function which is used to reurn the number of characters in the review.I dont have this problem for any other variables that I retrieve data from within this class. Below is the relevant code, any help would be appreciated. the lines where this problem occures is the first functio calld post(lines 1-5) and 4 lines up from the bottom
def post(self):
MovieID = self.MovID
REV = self.REV
AddReview(conn,cursor,Add_Review,MovieID,REV)
print(REV)
def shrek_film(self):
self.title = "Shrek"
self.MovID = 1
self.root4 = tk.Toplevel()
self.root4.title("Watch Shreck")
self.root4.geometry("1400x800")
frame_4 = tk.Frame(self.root4, bg = "black")
frame_4.pack(fill = tk.BOTH, expand = True, padx=0 , pady=0)
frame_4.grid_columnconfigure(1,weight=1)
self.Create_canvas = tk.Canvas(frame_4, width=2000, height=1080)
self.Create_canvas.place(x=-50, y=-50)
self.Create_img = PhotoImage(file="shrek-landscape.gif")
self.Create_canvas.create_image(20, 20, anchor = NW, image=self.Create_img)
play_button= tk.Button(frame_4,bg="orange",text="play", command = self.addHistory)
play_button.place(x=700,y=400)
play_button.config(font=("Ariel","30"))
def gtelen():
Review = reviewbox.get('1.0',END)
REVLEN = len(Review)
REVLENLEFT = (231-len(Review))
if REVLEN >=230:
lenbox = tk.Label(frame_4 ,text="No words left",bg="orange")
lenbox.place(x=360,y=460)
lenbox.config(font=("Ariel","15"))
else:
lenbox = tk.Label(frame_4 ,text=REVLENLEFT,bg="orange")
lenbox.place(x=360,y=460)
lenbox.config(font=("Ariel","15"))
print(Review)
Words_button = tk.Button(frame_4, bg="orange",text="check number of words remaining", command=gtelen)
Words_button.place(x=150,y=460)
Words_button.config(font=("Ariel","10"))
reviewlable=tk.Label(frame_4,text="Write a review",bg="orange")
reviewlable.place(x=10,y=460)
reviewlable.config(font=("ariel","15"))
Review_button= tk.Button(frame_4,bg="orange",text="See Reviews")#, command = self.ViewReviews)
Review_button.place(x=490,y=450)
Review_button.config(font=("Ariel","15"))
reviewbox= Text(frame_4,width=100,height=12)
reviewbox.place(x=10,y=500)
self.REV = reviewbox.get('1.0',END)
post_button = tk.Button(frame_4,bg="orange",text="Post Review", command = self.post)
post_button.place(x=830,y=650)
post_button.config(font=("Ariel","15"))
You can use Entry instead and use a StringVar
v = StringVar() # Create StringVar
reviewbox = Entry(frame_4, width = 100, height = 12, textvariable = v) # Create Entry widget
reviewbox.place(x = 10, y = 500) # Place Entry widget
self.REV = v.get() # Get contents of StringVar
The line self.REV = reviewbox.get('1.0',END) is being called about a millisecond after creating the text widget. The user will not even have seen the widget yet, much less have had time to type in it.
You can't call the get() method until after the user has had a chance to enter data, such as inside the post method.
def post(self):
MovieID = self.MovID
REV = reviewbox.get("1.0", "end")
AddReview(conn,cursor,Add_Review,MovieID,REV)
print(REV)

How to compare the inputs of two entries using single tkinter function for a bunch of such pairs of entries?

I want to validate two tkinter entries. One called minimum and the other called maximum. Of course, I want to make sure that minimum does not exceed maximum. And there is a third entry called increment which has to be lesser than maximum. There are a set of 15 such entries which I am trying to validate.
I have tried using for loop and tracing the textvariable of each entry. But inside the for loop, I am able to validate only a single entry box. Also, when I skip the validation for that specific one entry called the txtCab, it throws the following exception: If I do it for all the widgets, it does work, but fails some times.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\beejb\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\PROSAIL_5B_Fortran\PROSAIL_5B_FORTRAN\PROSAIL.py", line 191, in min_max
minVar = eval("self.txtVar_"+ str(wid)+ "_min.get()")
File "<string>", line 1, in <module>
NameError: name 'self' is not defined
The validation function I have used is:
def min_max(*args):
alltextFields = ["N","Cab","Car","Cw","Cm","Cbrown", "rsoil0","LIDFa","LIDFb","TypeLIDF","LAI","hspot","tts","tto","psi" ]
for wid in alltextFields:
if eval("self." + wid + "_variable.get()"):
minVar = eval("self.txtVar_"+ str(wid)+ "_min.get()")
maxVar = eval("self.txtVar_"+ str(wid) + "_max.get()")
rangeVar = eval("self.txtVar_"+ str(wid) + "_range.get()")
##
## print((minVar))
## print((maxVar))
## print((rangeVar))
if len(minVar) > 0 and len(maxVar):
if (minVar) > (maxVar):
messagebox.showinfo("Input Error", "Minimum should not be greater than maximum")
if len(rangeVar) > 0 and len(maxVar) > 0:
if (rangeVar) > (maxVar) :
messagebox.showinfo("Input Error", "Increment cannot exceed maximum limit")
## print(self.txtVar_Cab_min.get()); print(self.txtVar_Cab_max.get());
## print(self.txtVar_N_min.get()); print(self.txtVar_N_max.get());
if len(self.txtVar_Cab_min.get()) > 0 and len(self.txtVar_Cab_max.get()) > 0 and len(self.txtVar_Cab_range.get()) > 0:
if (self.txtVar_Cab_min.get()) > (self.txtVar_Cab_max.get()):
messagebox.showinfo("Input Data Error", "Minimum should not be greater than maximum!!")
if (self.txtVar_Cab_range.get()) > (self.txtVar_Cab_max.get()):
messagebox.showinfo("Error", "Increment cannot exceed maximum!!")
Another validation function I have tried is:
def validateMRM(self,value, text,W):
vMin,vMax,vRange;
entry = self.controller.nametowidget(W)
print(entry)
if entry == self.txt_N_min:
print(entry.get())
print(self.txtVar_N_max.get())
print(self.txtVar_N_range.get())
alltextFields = ["txt_N","txt_Cab","txt_Car","txt_Cab","txt_Cw","txt_Cw","txt_Cm","txt_Cbrown","txt_Cm", "txt_rsoil0",
"txt_LIDFa","txt_LIDFb","txt_TypeLIDF","txt_LAI","txt_hspot","txt_hspot","txt_tts","txt_tto","txt_psi"
]
for wid in alltextFields:
typeOfVar = wid.split("_")
if entry == eval("self.txt_" + str(typeOfVar[1])+ "_min"):
vMin = eval("self.txtVar_" + str(typeOfVar[1])+ "_min.get()")
print(eval("self.txtVar_" + str(typeOfVar[1])+ "_min.get()"))
vMax = eval("self.txtVar_" + str(typeOfVar[1])+ "_max.get()")
print(eval("self.txtVar_" + str(typeOfVar[1])+ "_max.get()"))
vRange = eval("self.txtVar_" + str(typeOfVar[1])+ "_range.get()")
print(eval("self.txtVar_" + str(typeOfVar[1])+ "_range.get()"))
print(vMin); print(vMax); print(vRange)
if len(vMin) > 0 and len(vMax) > 0 and len(vRange) > 0:
if (vMin) > (vMax):
messagebox.showinfo("Error", "Minimum cannot be greater than maximum")
if (vRange) > (vMax) :
messagebox.showinfo("Error", "Increment cannot exceed the maximum limit")
print(len(entry.get()))
if len(entry.get())>2:
And here is how all the entries are created:
self.lbl_N = tk.Label(self,text="Structure Coefficient(N)",anchor="w",width=40,bg='white'); self.lbl_N.grid(row=3,column=4,padx=4,pady=4);
self.N_variable = tk.BooleanVar()
self.chk_N = tk.Checkbutton(self,variable=self.N_variable, command=lambda:self.show_hide()); self.chk_N.grid(row=3,column=6,padx=4,pady=4);
self.txt_N = tk.Entry(self,width=10,validate = 'key', validatecommand = vcmd); self.txt_N.grid(row=3,column=7,padx=4,pady=4);
self.txtVar_N_min = tk.StringVar(); self.txtVar_N_max = tk.StringVar(); self.txtVar_N_range = tk.StringVar();
self.txtVar_N_min.trace("w", min_max); self.txtVar_N_max.trace("w", min_max); self.txtVar_N_range.trace("w", min_max);
self.txt_N_min = tk.Entry(self,width=5,validate = 'key',textvariable=self.txtVar_N_min, validatecommand = vcmd_min_max);
self.txt_N_max = tk.Entry(self,width=5,validate = 'key', textvariable=self.txtVar_N_max,validatecommand = vcmd_min_max);
self.txt_N_range = tk.Entry(self,width=5,validate = 'key', textvariable=self.txtVar_N_range,validatecommand = vcmd_min_max);
There are a set of fourteen such entries and I need to validate each of them.
But none of this gives the actual output I want. It works some time and fails some other times.
I am not sure why is that happening and I have spent a hell of time with this validation.
I'm not sure whether this answers your question but it should point you in the right direction.
I couldn't make much sense of your code. I've produced a 15 row x 4 column grid.
The 4th column is a message that the 3 fields next to it are 'OK' or if not indicate the problem. The validation is run on the whole grid for each keypress. If this is too slow a validate button could launch the validation instead.
import tkinter as tk
from tkinter import ttk
def rec(): return {'lo': 0, 'hi': 0, 'step': 0, 'ok': '' }
root = tk.Tk()
root.title('SO Question')
def entry(id, ent_dict, var_dict, v=0):
""" Add an Entry Widget to the root, with associated StringVar."""
var_dict[id] = tk.StringVar()
var_dict[id].set(str(v))
ent_dict[id] = ttk.Entry(root, textvariable= var_dict[id], width = 10 )
return ent_dict[id]
def do_validate(lo, hi, step):
""" Return OK if lo, hi and step are consistent else an error string. """
if lo < hi and step < hi: return 'OK'
txt = ''
if lo >= hi:
txt = 'lo >= hi. '
if step >= hi:
txt += 'step >= hi.'
return txt
def conv(txt):
""" Convert text to float. Return 0.0 if not valid float e.g "" or 'a' """
try:
return float(txt)
except ValueError:
return 0.0
def oklabel(ent_dict, var_dict):
""" Add an OK Label to a row. """
lo = conv(var_dict['lo'].get())
hi = conv(var_dict['hi'].get())
step = conv(var_dict['step'].get())
var_dict['ok'] = tk.StringVar()
var_dict['ok'].set(do_validate(lo, hi, step))
ent_dict['ok'] = ttk.Label(root, textvariable = var_dict['ok'], width = -17)
return ent_dict['ok'] # Return the Label object for gridding.
def do_check(*args):
""" Loop through the rows setting the validation string in each one. """
for var_dict in stringvars:
lo = conv(var_dict['lo'].get())
hi = conv(var_dict['hi'].get())
step = conv(var_dict['step'].get())
var_dict['ok'].set(do_validate(lo, hi, step))
# Add column labels
ttk.Label(root, text='Minimums').grid(row=0, column=0)
ttk.Label(root, text =' Maximums').grid(row=0, column=1)
ttk.Label(root, text='Increment').grid(row=0, column=2)
ttk.Label(root, text='Valid').grid(row=0, column=3)
# Create containers for he Entries and Stringvars
entries =[]
stringvars = []
# Add 15 rows of Entries / Validation Labels to the UI.
for row in range(1, 16):
tempe=rec()
tempv=rec()
entry('lo', tempe, tempv, 0).grid(row = row, column=0)
entry('hi', tempe, tempv, 0).grid(row = row, column=1)
entry('step', tempe, tempv, 0).grid(row = row, column=2)
oklabel(tempe, tempv).grid(row = row, column = 3)
entries.append(tempe)
stringvars.append(tempv)
# Bind do_check to all Entry widgets.
root.bind_class('TEntry', '<KeyPress>', do_check, add='+')
root.bind_class('TEntry', '<BackSpace>', do_check, add='+')
root.bind_class('TEntry', '<Delete>', do_check, add='+')
root.mainloop()
In the past I've got stuck trying to validate multiple fields by not allowing inconsistent entries. It is difficult for users to follow what is required to correct fields. They have to work in the correct order. e.g. lo = 100, hi = 9, and step = 1. Should the UI allow the last zero in 100 to be deleted, leaving 10 which is gt 9?
This could be extended to activate a 'Next' button only if all rows are OK.
Edit 1 - Response to Comment
This has a function to create and activate each row of the display. Each row has it's own variables and checking function. They are triggered by the trace on the three Entry StringVars, there's no need to use validate.
import tkinter as tk
from tkinter import ttk
def to_float(txt):
""" Safely convert any string to a float. Invalid strings return 0.0 """
try:
return float(txt)
except ValueError:
return 0.0
def row_n( parent, n, init_show = 0 ):
""" Create one row of the display. """
# tk.Variables
v_show = tk.IntVar()
v_min = tk.StringVar()
v_max = tk.StringVar()
v_incr = tk.StringVar()
v_message = tk.StringVar()
# Initialise variables
v_min.set('0')
v_max.set('1')
v_incr.set('1') # Can the increment be zero?
v_show.set(init_show)
v_message.set("OK")
def do_trace(*args):
""" Runs every time any of the three Entries change value.
Sets the message to the appropriate text.
"""
lo = to_float(v_min.get())
hi = to_float(v_max.get())
inc = to_float(v_incr.get())
if lo < hi and inc <=hi:
v_message.set('OK')
else:
txt = ''
if lo >= hi:
txt += 'Min >= Max'
if inc > hi:
if len(txt): txt += ' & '
txt += 'Incr > Max'
v_message.set(txt)
# Set trace callback for changes to the three StringVars
v_min.trace('w', do_trace)
v_max.trace('w', do_trace)
v_incr.trace('w', do_trace)
def activation(*args):
""" Runs when the tickbox changes state """
if v_show.get():
e_min.grid(row = n, column = 1)
e_max.grid(row = n, column = 2)
e_inc.grid(row = n, column = 3)
message.grid(row = n, column = 4)
else:
e_min.grid_remove()
e_max.grid_remove()
e_inc.grid_remove()
message.grid_remove()
tk.Checkbutton(parent,
text = 'Structure Coefficient {} :'.format(n),
variable = v_show, command = activation ).grid(row = n, column = 0)
e_min = tk.Entry(parent, width=5, textvariable = v_min)
e_max =tk.Entry(parent, width=5, textvariable = v_max)
e_inc = tk.Entry(parent, width=5, textvariable = v_incr)
message = tk.Label(parent, width=-15, textvariable = v_message)
activation()
return { 'Min': v_min, 'Max': v_max, 'Inc': v_incr }
def show_results():
print('Min Max Inc')
for row in rows:
res = '{} {} {}'.format(row['Min'].get(), row['Max'].get(), row['Inc'].get())
print( res )
root = tk.Tk()
root.title('SO Question')
ttk.Label(root, text='Minimums').grid(row=0, column=1)
ttk.Label(root, text =' Maximums').grid(row=0, column=2)
ttk.Label(root, text='Step', width = 5 ).grid(row=0, column=3)
ttk.Label(root, text='Valid', width = 15 ).grid(row=0, column=4)
rows = []
for r in range(1,16):
rows.append(row_n(root, r, init_show=r%3 == 0 ))
tk.Button(root, command=show_results, text = ' Show Results ').grid(column=1, pady = 5)
root.mainloop()
This is another approach. Does this help.
Here's another suggestion. Incorporate the Label and Entry in the row-n function. Include activating / disabling the Entry in the activate function. The row_n function is executed in a loop through a list of the descriptions you want.
import tkinter as tk
row_names = [ "Structure Coefficient(N)", "Chlorophyll Content(Cab) (µg.cm-2)",
"Carotenoid content(Car) (µg.cm-2)", "Brown pigment content(Cbrown)(arbitrary units)"]
def row_n(parent, desc, n, init_show = 0 ):
""" Create one row of the display. """
# tk.Variables
v_show = tk.IntVar()
v_min = tk.StringVar()
v_max = tk.StringVar()
v_incr = tk.StringVar()
v_fixed = tk.StringVar() # New StringVar
v_message = tk.StringVar()
v_show.set(init_show)
v_message.set("OK")
def do_trace(*args):
""" Runs every time any of the three Entries change value.
Sets the message to the appropriate text.
"""
lo = to_float(v_min.get())
hi = to_float(v_max.get())
inc = to_float(v_incr.get())
if lo < hi and inc <=hi:
v_message.set('OK')
else:
txt = ''
if lo >= hi:
txt += 'Min >= Max'
if inc > hi:
if len(txt): txt += ' & '
txt += 'Incr > Max'
v_message.set(txt)
# Set trace callback for changes to the three StringVars
v_min.trace('w', do_trace)
v_max.trace('w', do_trace)
v_incr.trace('w', do_trace)
def activation(*args):
""" Runs when the tickbox changes state """
if v_show.get():
e_min.grid(row = n, column = 8)
e_max.grid(row = n, column = 9)
e_inc.grid(row = n, column = 10)
message.grid(row = n, column = 11)
e_fixed.config(state = 'disabled') # Disable the base Entry
else:
e_min.grid_remove()
e_max.grid_remove()
e_inc.grid_remove()
message.grid_remove()
e_fixed.config(state = 'normal') # Enable the base Entry Widget
tk.Label(parent, text = desc ).grid(row = r+1, column = 4 ) # Add the desc. Label
e_fixed = tk.Entry(parent, textvariable = v_fixed) # Add the new Entry widget
e_fixed.grid(row = r+1, column = 5)
tk.Checkbutton(parent,
text = ' '.format(n),
variable = v_show, command = activation ).grid(row = n, column = 6)
e_min = tk.Entry(parent, width=5, textvariable = v_min)
e_min.config(font=('Candara', 15))
e_max =tk.Entry(parent, width=5, textvariable = v_max)
e_max.config(font=('Candara', 15))
e_inc = tk.Entry(parent, width=5, textvariable = v_incr)
e_inc.config(font=('Candara', 15))
message = tk.Label(parent, width=-15, textvariable = v_message)
message.config(font=('Candara', 15))
activation()
return { 'Min': v_min, 'Max': v_max, 'Inc': v_incr, 'Fixed': v_fixed }
# The 'Fixed' field added to the dictionary to return
def print_row(row):
fmt = 'Min: {}, Max: {}, Inc: {}, Fixed: {}'
print(fmt.format(
row['Min'].get(), row['Max'].get(), row['Inc'].get(), row['Fixed'].get()
))
def to_float(txt):
""" Safely convert any string to a float. Invalid strings return 0.0 """
try:
return float(txt)
except ValueError:
return 0.0
# GUI Start
root = tk.Tk()
root.title('Validation wth Trace')
# Header Labels
tk.Label(root,text="Min").grid(row=0,column=8,padx=4,pady=4)
tk.Label(root,text="Max").grid(row=0,column=9,padx=4,pady=4)
tk.Label(root,text="Inc").grid(row=0,column=10,padx=4,pady=4)
# Body of rows
rows = []
for r, r_text in enumerate(row_names):
rows.append(row_n( root, r_text, r+1))
root.mainloop()
print("Strings in the Entry fields")
for r, row in enumerate(rows):
print('Row: ', r, 'Data:', end=' ')
print_row(row)
HTH. Seeing your code in the inked question you may prefer to make row_n a class.

How to get Entry value to not be a string variable for Mysql query = Tkinter

The query seems to work but the 'Selected Entry' turns into a string of numbers which messes up my query.
def find_roster(n=""):
global cursor
cursor.execute("""SELECT num, firstname, surname, assign FROM active WHERE num='%s'"""%(n))
rows = cursor.fetchall()
for results in rows:
rosterList.insert("end", results)
cursor.close()
print(n)
print(rows)
return rows
numLabel=Label(root, text="Employee #")
numLabel.grid(row=0,column=0)
findButt=Button(root, text="Find", width=12, command=find_roster)
findButt.grid(row=1, column=5)
num_input=StringVar()
num_input=Entry(root,textvariable=num_input)
num_input.grid(row=0,column=1)
-----
findButt=Button(root, text="Find", width=12, command=lambda: find_roster(num_input))
findButt.grid(row=1, column=5)
CONSOLE PRINT RESULT
.140526443864584
() #QUERY RESULT
NEEDS TO BE
1-214
(1-214, JOE,HOEY,OFF) #QUERY RESULT
Notice that:
num_input=StringVar()
num_input=Entry(root,textvariable=num_input)
which is very much the same thing as:
a = 3
a = -4
but further add:
a = 3
a = -4
print(a)
What do you think this will print?
Replace:
num_input=StringVar()
num_input=Entry(root,textvariable=num_input)
with:
anything_but = StringVar()
num_input = Entry(root, textvariable=anything_but)
as you're later on assigning an entire Entry widget as num_input so it gets overwritten. Also to get its content as a string you have to use get method:
findButt=Button(root, text="Find", width=12,
command=lambda arg=anything_but.get(): find_roster(arg))

Examining program

At first I thought this would be an easy program where I could learn a lot. But I'm stuck.
How can I ask diffrent questions all after eachother. I have tried some things I came up with but none of those work.
This is the first one, where I use a variable x to re-generate the question. This simply doesn't work.
# Laad de database
cnx = mysql.connector.connect(user='FransSchool', password='RandomPass',host='10.0.0.25', database='Overhoor')
cursor = cnx.cursor()
# Maak een grafische interface
gui = Tk()
gui.resizable(width=FALSE, height=FALSE)
# Verklaringen
def verify():
overify = antwoord.get()
if overify == Nederlandsevertaling:
oentry.delete(0,END)
x=0
else:
oentry.delete(0,END)
x = 0
antwoord = StringVar()
willekeurig = random.randint(0,9)
# Indexeer de database
query = "SELECT FRwoord, NLwoord FROM unite8app1 WHERE id=%s"
cursor.execute(query, (willekeurig,))
while x < 1:
for (FRwoord, NLwoord) in cursor:
Fransevertaling = FRwoord
Nederlandsevertaling = NLwoord
x+=1
And this is the second one which gave me an error. It didn't really came as a surprise that this one didn't work. On button press it tries to recieve a new FR and NLwoord.
# Laad de database
cnx = mysql.connector.connect(user='FransSchool', password='RandomPass', host='10.0.0.25', database='Overhoor')
cursor = cnx.cursor()
# Maak een grafische interface
gui = Tk()
gui.resizable(width=FALSE, height=FALSE)
# Verklaringen
def verify():
overify = antwoord.get()
if overify == Nederlandsevertaling:
oentry.delete(0,END)
willekeurig = random.randint(0,9)
for (FRwoord, NLwoord) in cursor:
Fransevertaling = FRwoord
Nederlandsevertaling = NLwoord
else:
oentry.delete(0,END)
#Save the wrong answer aswell as the right answer to print out at the end
antwoord = StringVar()
willekeurig = random.randint(0,9)
# Indexeer de database
query = "SELECT FRwoord, NLwoord FROM unite8app1 WHERE id=%s"
cursor.execute(query, (willekeurig,))
for (FRwoord, NLwoord) in cursor:
Fransevertaling = FRwoord
Nederlandsevertaling = NLwoord
# Uiterlijk van het venster
gui.configure(background="white")
gui.title("Overhoorprogramma - Bryan")
# Grafische objecten
style = ttk.Style()
olabel = ttk.Label(gui,text=Fransevertaling,font=("Times", 18), background="white")
olabel.grid(row=0, column=0,padx=5, pady=5, sticky="W")
oentry = ttk.Entry(gui,textvariable=antwoord, font=("Times", 18))
oentry.grid(row=1, column=0,padx=5, pady=5)
obutton = ttk.Button(gui,text="Suivant", command = verify)
obutton.grid(row=1, column=1,padx=5, pady=5)
At the moment it just clears the entry box on button press. The goal is that everytime an answer has been typed in right it should skip that and if it is typed wrong it has to save it. Either way it has to create a new question what means a new Frword and NLword.
Ideally I am looking for a push in the right direction, the mechanism behind it or a small snippet of code.

Categories