I am trying to get input from an entry widget using Python Tkinter using Notebook. I have managed to get it to work on my main canvas but as soon as I introduced tabs, it would not work. I am clearly missing something linking the .get function to the correct location but I can't work out what. Any ideas?
import tkinter
import win32api
from tkinter import ttk
checklist = tkinter.Tk()
checklist.title("My Checklist")
ScreenWidth=checklist.winfo_screenwidth()
ScreenHeight=checklist.winfo_screenheight()
checklist.geometry("%dx%d+0+0" % (ScreenWidth, ScreenHeight))
count = 0
tasks = []
tabcontrol = ttk.Notebook(checklist, width = 500, height = 500)
tab = ttk.Frame(tabcontrol)
tabcontrol.add(tab, text = "Checklist Home Page")
tabcontrol.grid(row = 0, column = 0)
main_canvas = tkinter.Canvas(checklist, width = 1000, height = 1000, highlightbackground="green")
main_canvas.grid(row=1, column = 0)
main_canvas.columnconfigure(3)
main_canvas.rowconfigure(6)
def create_checklist():
global count
count += 1
if count > 10:
win32api.MessageBox(0, 'Maximum number of checklists made!')
else:
tab = ttk.Frame(checklist, width = 500, height = 500)
tabcontrol.add(tab, text = count)
tabcontrol.grid(row = 0, column = 0)
button_add_task = tkinter.Button(tab, text="Add task", width=20, height=1, bg="purple", command=add_task).grid(row = 2, column= 2, pady = (100, 1))
item_entry = tkinter.Entry(tab).grid(row=6, column =2)
list_items = tkinter.Listbox(tab)
list_items.grid(row =7, column =2, pady=10)
def add_task():
task = item_entry.get()
if task !="":
tasks.append('- ' + task)
update_listbox()
button_create_checklist = tkinter.Button(main_canvas, text="New Checklist", width=20, height=1, bg = "purple", command=create_checklist).grid(row = 3, column = 2, pady = 1 )
checklist.mainloop()
My error is currently:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\lucas\anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\lucas\OneDrive\Documents\Employability\untitled0999py.py", line 40, in add_task
task = item_entry.get()
NameError: name 'item_entry' is not defined
Since item_entry is local variable of function create checklist(), it can't be used in add_task() function. So, we'll pass value of Entry field whenever Add Task button is pressed. To do so, we can use lambda expression in command option of Button. There are some minor changes in add_task() function.
Remember: grid is used to organize widgets and it returns None, so item_entry will be a NoneType object in your code and using get() with it will raise AttributeError.
So, we need to replace
item_entry = tkinter.Entry(tab).grid(row=6, column =2)
with
item_entry = tkinter.Entry(master=tab)
item_entry.grid(row=6, column =2)
This code works Fine:
def create_checklist():
global count
count += 1
if count > 10:
win32api.MessageBox(0, 'Maximum number of checklists made!')
else:
tab = ttk.Frame(checklist, width = 500, height = 500)
tabcontrol.add(tab, text = count)
tabcontrol.grid(row = 0, column = 0)
item_entry = tkinter.Entry(master=tab) # Changes in
item_entry.grid(row=6, column =2) # these lines
button_add_task = tkinter.Button(tab, text="Add task", width=20, height=1, bg="purple", command=lambda :add_task(item_entry.get())).grid(row = 2, column= 2, pady = (100, 1))
list_items = tkinter.Listbox(tab)
list_items.grid(row =7, column =2, pady=10)
def add_task(task):
if task !="":
tasks.append('- ' + task)
update_listbox()
Hope this helps.
Related
Application: Building a notes application (as an intro to GUI development in Python) which includes feature of a scrollbar to scroll through a textbox
Problem: I can't actually seem to scroll down through the textbox. I don't seem to get the grayed rectangle which lets me control the scrollbar and scroll up/down through the textbox
#importing necessary packages
from tkinter import *
from tkinter import font
from tkinter import ttk
#set up main window
root = Tk()
root.title("Notes")
root.geometry("400x650")
#functions
#functions to change all widget button's backgrounds when user hovers over it and leaves it
def enter_button(e):
e.widget.config(background = "#D4D4D4")
#SystemButtonFace is default colour
def leave_button(e):
e.widget.config(background = "SystemButtonFace")
#clear text in text-box
def clear():
#delete all text from text_box
text_box.delete(1.0,END)
def bold_it():
#create font
try:
bold_font = font.Font(text_box, text_box.cget("font"))
bold_font.configure(weight = "bold")
#creating tag called "bold" which bolds textll upon condition
text_box.tag_configure("bold", font = bold_font)
#creating a bold tag which highlights first character
bold_tag = text_box.tag_names("sel.first")
#condition for checking to see if tag is applied or not
#in the first highlighted character
#if tag is applied, remove the bold from first-highlighted text
#- last highlighted text
#"bold" needs to be matched in the tag
if "bold" in bold_tag:
text_box.tag_remove("bold","sel.first","sel.last")
else:
text_box.tag_add("bold","sel.first", "sel.last")
except TclError:
pass
def italics_it():
try:
#create a font
italics_font = font.Font(text_box, text_box.cget("font"))
italics_font.configure(slant = "italic")
#create a tag called "italic"
text_box.tag_configure("italics", font = italics_font)
italics_tag = text_box.tag_names("sel.first")
#condition to see whether tag has been applies or not
if "italics" in italics_tag:
text_box.tag_remove("italics", "sel.first","sel.last")
else:
text_box.tag_add("italics", "sel.first", "sel.last")
except TclError:
pass
#frames
top_frame = LabelFrame(root, padx = 30, pady = 10)
button_frame = LabelFrame(root, padx = 30, pady = 10)
text_frame = LabelFrame(root, padx = 10, pady = 10)
bottom_frame = LabelFrame(root, borderwidth = 0, highlightthickness = 5)
top_frame.grid(row = 0 , column = 0)
button_frame.grid(row = 1, column = 0, pady = 10)
text_frame.grid(row = 2, column = 0, pady = 1)
bottom_frame.grid(row = 3, column = 0, pady = 3)
#labels, textboxes, buttons
#top_frame content
Notes_label = Label(top_frame, text = "Notes", fg = "black", font = 1, padx = 141)
Notes_label.grid(row = 0 , column = 0)
save_button = Button(top_frame, text = "save")
#padx increases distance between buttons
#button_frame content
#bold button
#the ideal is that if u press ctrl + b, the bold_button is pressed by itself
#rn, it's gonna be a highlight technique
bold_button = Button(button_frame, text = "B", padx = 4, pady = 2, command = bold_it)
bold_button.grid(row = 0, column = 0)
#italicsize button
italics_button = Button(button_frame, text = "I", padx = 4, pady = 2, command = italics_it)
italics_button.grid(row = 0, column = 2, padx = 15)
#text_box frame button
text_box = Text(text_frame, width = 45, height = 27)
text_box.grid(row = 0, column = 0)
#text_box frame content
main_scrollbar = ttk.Scrollbar(text_frame, orient = "vertical", command = text_box.yview)
main_scrollbar.grid(row = 0, column = 1)
text_box["yscrollcommand"] = main_scrollbar.set
clear_button = Button(bottom_frame, text = "clear", padx = 2, pady = 2, command = clear)
clear_button.grid(row = 0, column = 0, padx = 15, pady = 10)
save_button = Button(bottom_frame, text = "save note", padx = 2, pady = 2)
save_button.grid(row = 0, column =1, padx = 15, pady = 10)
#binding all buttons for changing colours when user hovers over it and leaves it
bold_button.bind("<Enter>", enter_button)
bold_button.bind("<Leave>", leave_button)
italics_button.bind("<Enter>", enter_button)
italics_button.bind("<Leave>", leave_button)
clear_button.bind("<Enter>", enter_button)
clear_button.bind("<Leave>", leave_button)
save_button.bind("<Enter>", enter_button)
save_button.bind("<Leave>", leave_button)
# main program loop
root.mainloop()
here's an image of the problem image of problem
I would also be very grateful if one could explain the concept of scrollbar.set and like yview and why they are both needed for the scrollbar to work. Tutorials and videos don't seem to explain the concept, but just implement it
In line 145. You're missing sticky
main_scrollbar.grid(row = 0, column = 1, sticky=NS)
Output:
I am currently trying to implement a GUI as kind of a 'Presentors' Toolkit'.
It shall contain how much time you have left on your presentation and who shall be the next speaker.
I manage to build the GUI with boxes, where I can insert the time and the name of the next speaker, but somewhat I can't manage to get my head around the display of name and time (updated every second).
The program will start, when I hit the start button, but also will not terminate.
I have tried a couple of things and also checked out other stack overflow entries but couldn't manage to transfer those approaches to mine.
My code looks like this:
from tkinter import *
import time
import datetime
#build the GUI
window = Tk()
window.title("presenters Toolkit")
lbl_duration = Label(window, text = "duration [mins]")
lbl_duration.grid(column = 0, row = 0)
presentationDuration = Entry(window, width = 10)
presentationDuration.grid(column = 1, row = 0)
lbl_speaker = Label(window, text = "next Speaker")
lbl_speaker.grid(column = 2, row = 0)
nextSpeaker = Entry(window, width = 25)
nextSpeaker.grid(column = 3, row = 0)
lbl = Label(window, text = "", font = ("Arial Bold", 50))
lbl.grid(column = 1, row = 1)
left_Time = Label(window, text ="--", font = ("Arial Bold", 50))
left_Time.grid(column = 0, row = 4)
mid_Time = Label(window, text = ":", font = ("Arial Bold", 50))
mid_Time.grid(column = 1, row = 4)
right_Time = Label(window, text = "--", font = ("Arial Bold", 50))
right_Time.grid(column = 2, row = 4)
btn = Button(window, text = "start", command = clicked)
btn.grid(column = 1, row = 3)
#method, that will act upon clicking the 'start button'
def clicked():
t = float(presentationDuration.get())
nSpeaker = nextSpeaker.get()
t = int(t*60)
update(t, nSpeaker)
#method, that shall update the labels according to the time and that shall do this only once every second
def update(t, nSpeaker):
h = int(t//3600)
m = int(t//60)
s = int(t-3600*h-60*m)
while t >= 0:
left_Time.configure(text = m)
mid_Time.configure(text = ":")
right_Time.configure(text = s)
lbl.configure(text = nSpeaker, bg = "red", font = ("Arial Bold", 50))
t = t - 1
window.after(1000, update(t, nSpeaker))
window.mainloop()
I still have the calculations for the hour included, though I believe that won't be necessary since presentations usually don't go that long.
Thank you very much for any approach to help me!
All the best :)
I've created a temperature converter programme in which the calculated temperature from an entry widget gets displayed in a separate label, what I need to do is to grab that converted variable and put it into a list.
I think that making a connected entry widget to the label widget would work where they are connected so I could grab the variable using the .get method but that would look awfully messy. Is there any other way I could proceed with this?
This is my first post and I am a beginner in Python, very sorry if the code looks messy and if I included too much code.
data = []
tempVal = "Celcius"
def store_temp(sel_temp):
global tempVal
tempVal = sel_temp
class Calculator:
def __init__(self, num_a, num_b):
self.num_a= num_a
self.num_b = num_b
def convert(self):
if tempVal == 'Fahrenheit':
return float((float(self.num_a) - 32)* 5 / 9)
if tempVal == 'Celcius':
return float((float(self.num_a) * 9/ 5) + 32)
def display_add(entry_numa,entry_numb,label_answer):
#get the value from entry_numa
num_a = entry_numa.get()
num_b = entry_numb.get()
num_a = str(num_a)
num_b = str(num_b)
#create an object
global data
calc = Calculator(num_a,num_b)
label_answer['text'] = calc.convert()
data += [calc]
def calc_history():
global data
#creat e another window
window_calc_list = Tk()
window_calc_list.geometry("400x200")
#create a listbox
listbox_calc_list = Listbox(window_calc_list, width= 300)
listbox_calc_list.pack()
listbox_calc_list.insert(END, "list of data")
for info in data:
listbox_calc_list.insert(END, str(info.num_a) + " " + str(info.num_b) + " " )
window_calc_list.mainloop()
def main():
window = Tk()
window.geometry("500x150")
validate_letter = window.register(only_letters)
validate_nb = window.register(only_numbers_max_3)
label = Label(window, width = 30, background = 'lightblue', text='enter temperature, only numbers')
label.grid(row=0, column=0)
entry_numa = Entry(window, width = 30, validate="key", validatecommand=(validate_nb, '%d', '%P'))
entry_numa.grid(row = 0, column = 1)
#create another label and entry object for num_b
label_numb = Label(window, width = 30, background = 'lightblue', text='enter location, only letters')
label_numb.grid(row=1, column=0)
entry_numb = Entry(window, width = 30, validate="key", validatecommand=(validate_letter, '%d', '%S'))
entry_numb.grid(row = 1, column = 1)
#create another label to display answer
label_answer = Label(window, width = 30, background = 'lightyellow')
label_answer.grid(row = 2, column = 1)
entry_answer = Entry(window, width = 30)
entry_answer.grid(row = 2, column = 0)
button_add = Button(window, text = "ADD", command = lambda: display_add(entry_numa,entry_numb,label_answer))
button_add.grid(row=3, column = 0)
button_delete = Button(window, text = "DELETE", command = lambda: delete_data(data))
button_delete.grid(row=3, column = 2)
#create another button to display all previous calculations
button_display = Button(window,text = "calc_history", command = lambda: calc_history())
button_display.grid(row=3, column = 1)
var = StringVar()
dropDownList = ["Celcius", "Fahrenheit"]
dropdown = OptionMenu(window, var,dropDownList[0], *dropDownList, command=store_temp)
dropdown.grid(row=0, column=2)
window.mainloop()
A tk.Label displayed value can be accessed via the text property
, labelwidgetname['text'].
Depeneding on when and how you want the independent list of stored values
to be updated there are a variety of options. The example shows one if the
user is required to press a submission button. This could be adapted,
for example,when the tempreture calculation is performed.
Of course it would be simpler to update the list of stored values directly at the point in the script where the calculated tempreture for the label text has been derived.
import tkinter as tk
stored_values = []
def add_labelvalue_tolist(temp):
'''Store label value to list.'''
stored_values.append(temp)
print('contents of list', stored_values)
def add_entry_tolabel(event):
display_label['text'] = user_entry.get()
ROOT = tk.Tk()
user_entry = tk.Entry()
user_entry.grid(column=0, row=0)
user_entry.bind('<KeyRelease>', add_entry_tolabel)
display_label = tk.Label()
display_label.grid(column=1, row=0)
# update list via button command linked to label text value
add_button = \
tk.Button(text='add to list',
command=lambda:add_labelvalue_tolist(display_label['text']))
add_button.grid(column=0, row=1)
ROOT.mainloop()
try making a function that is like this
def letterused():
converter=(letter.get())# letter is a entry box at the bottom is the code
converted.set(converter)
for i in range(1):
used_letters1.append(converter) #list
letter = ttk.Entry(root, width = 20,textvariable = letter)
letter.pack()
I am trying to write a function that adds the user's chosen numbers and displays the sum after every button click. This function is a part of a bigger program. Hence I have to put it in a class or a fuction.
The program works when it's outside the function
import Tkinter as tk
total = 0
def Sum():
global total
num = var.get()
total = num+ total
label.config(text = total)
root = tk.Tk()
var = tk.IntVar()
numbers = [("1"),
("2"),
("3"),
("4"),
("5")]
for val, choice in enumerate(numbers):
tk.Radiobutton(root,
text=choice,
indicatoron = 0,
width = 5,
padx = 100,
variable=var,
command=Sum,
value=val).pack()
label = tk.Label(root, width = 30, height = 3, bg = "yellow")
label.pack()
root.mainloop()
But when I put it inside a function like this
import Tkinter as tk
def func():
total = 0
def Sum():
global total
num = var.get()
total = num+ total
label.config(text = total)
root = tk.Tk()
var = tk.IntVar()
numbers = [("1"),
("2"),
("3"),
("4"),
("5")]
for val, choice in enumerate(numbers):
tk.Radiobutton(root,
text=choice,
indicatoron = 0,
width = 5,
padx = 100,
variable=var,
command=Sum,
value=val).pack()
label = tk.Label(root, width = 30, height = 3, bg = "yellow")
label.pack()
root.mainloop()
func()
it throws me the following error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1532, in __call__
return self.func(*args)
File "C:\Python27\Gui_demo.py", line 9, in Sum
total = num+ total
NameError: global name 'total' is not defined
I'm new to Python and was hoping there's a simple workaround. Any help would be appreciated. Thanks
My suggestion is to place your app in a class instead of nested functions.
class App:
total = 0
def __init__(self):
root = tk.Tk()
self.var = tk.IntVar()
numbers = [("1"),
("2"),
("3"),
("4"),
("5")]
for val, choice in enumerate(numbers):
tk.Radiobutton(root,
text=choice,
indicatoron = 0,
width = 5,
padx = 100,
variable=self.var,
command=self.Sum,
value=val+1).pack()
self.label = tk.Label(root, width = 30, height = 3, bg = "yellow")
self.label.pack()
root.mainloop()
def Sum(self):
num = self.var.get()
App.total += num
self.label.config(text = App.total)
App()
I would like user to click on the number's and then the number should change color and i shall be able to capture on what label user has clicked, this form then shall be saved in Text and PDF format..Thanks a mil in advance for any help
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
class Proj_pres:
"""Defininf clickable labels in frame"""
#def fr_lb(self):
def __init__(self,master):
master.title(" Feedback Form")
#master.resizable(False,False)
self.frame_header = ttk.Frame(master, borderwidth = 5, relief ='ridge').grid(sticky = NE)
#self.frame_header.pack()
ttk.Label(self.frame_header, text = " For recording feedback on Autumn(inerm) project presentations",
font=('Arial',16,'bold')).grid(row = 0, column = 0,sticky = NW)
"""Defining new frame"""
self.frame_content = ttk.Frame(master,borderwidth = 5)
self.frame_content.grid(row = 2, column = 0,columnspan = 3, sticky = NW)
"""Adding check buttons for Studio 1 and Studio 2"""
self.chkb1 = IntVar()
self.b1 = ttk.Checkbutton(self.frame_content, text = "UC1Studio1", variable = self.chkb1).grid(row =0,column = 0)
self.chkb2 = IntVar()
self.b2 = ttk.Checkbutton(self.frame_content, text = "UC2Studio2", variable = self.chkb2).grid(row = 0, column = 8,columnspan = 2,stick=W)
"""Adding Labels for Team and Reviewer"""
ttk. Label(self.frame_content, text = "Team Name").grid(row =4, column = 0,sticky = W)
ttk.Label(self.frame_content, text = "Reviewer").grid(row = 4,column = 7, sticky = E)
ttk.Label(self.frame_content).grid(row=2, column=0)
"""Adding Entry Boxes for team name and reviewer"""
ttk.Entry(self.frame_content).grid( row = 4, column = 1,columnspan = 4,sticky = W)
ttk.Entry(self.frame_content).grid( row = 4, column = 8,columnspan = 2, sticky = E)
"""Adding Label and frame for grading info"""
self.frame_info = ttk.Frame(master,borderwidth = 5, relief = 'solid')
self.frame_info.grid(row = 3, column = 0,sticky = NW)
ttk.Label(self.frame_info).grid(row =5,column = 0)
ttk.Label(self.frame_info, text ="Please use the feeedback scale for each of the following criterion, "
"where 5 = excellent and 1 = poor").grid(row = 7, column = 0,sticky = W)
ttk.Label(self.frame_info).grid(row = 6, column =0)
ttk.Label(self.frame_info,text = "OVERVIEW OF PROJECT").grid(row = 8, column = 0, sticky = NW)
ttk.Label(self.frame_info, text = " 5: Well Structured,4: Clear aim, 3:Understandable project "
"view").grid(row = 9, column = 0, sticky = NW)
ttk.Label(self.frame_info, text=" 2: Absent,1: Confused "
"view").grid(row=9, column=5, sticky=NW)
#ttk.Label(self.frame_info, text=" should come here").grid(row=9, column=1, sticky=NW)
"""Adding frame in column 2 for clickable Labels"""
self.frame_clk=ttk.Frame(self.frame_info, borderwidth= 5, relief ='solid')
self.frame_clk.grid(row = 9,column = 2,columnspan = 3,sticky = NW)
self.f1_l5 = StringVar()
l5 = ttk.Label(self.frame_clk,text = " 5 " ,
background = 'white',borderwidth=5,relief= 'ridge',font =('Helvetica',12,'bold'))
#,textvariable = self.f1_l5
l5.grid(row=0,column =1,columnspan =2 )
f1_l4= ttk.Label(self.frame_clk, text=" 4 ",background = 'white',borderwidth=5,relief= 'ridge', font=('Helvetica', 12, 'bold'))
f1_l4.grid(row =0 , column = 3)
f1_l3 = ttk.Label(self.frame_clk, text=" 3 ",background = 'white',borderwidth=5,relief= 'ridge', font=('Helvetica', 12, 'bold'))
f1_l3.grid(row=0, column=4)
f1_l2 = ttk.Label(self.frame_clk, text=" 2 ",background = 'white',borderwidth=5,relief= 'ridge', font=('Helvetica', 12, 'bold'))
f1_l2.grid(row=0, column=5)
f1_l1 = ttk.Label(self.frame_clk, text=" 1 ",background = 'white', borderwidth=5,relief= 'ridge',font=('Helvetica', 12, 'bold'))
f1_l1.grid(row=0, column=6)
#elf.frame_content.pack()
def main():
root = Tk()
proj_pres = Proj_pres(root)
root.mainloop()
if __name__ == '__main__':main()
def clickFunction(event): #event is argument with info about event that triggered the function
global selectedNumber #make the number visible throughout the program, don't need this if you'll just pass it as argument to function
event.widget.config(background = "green") #event.widget is reference to widget that was clicked on and triggered the function
selectedNumber = 7 - event.widget.grid_info()["column"] #grid info is dictionary with info about widget's grid relative to widget, more at http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/grid-methods.html
if(selectedNumber > 5): selectedNumber = 5
print(selectedNumber)
''' if someday you won't use grid, but will use list to store Labels, this is a way to get Label's position
selectedNumber = myLabels.index(event.widget)
'''
l5.bind("<Button-1>", clickFunction)
f1_l4.bind("<Button-1>", clickFunction)
f1_l3.bind("<Button-1>", clickFunction)
f1_l2.bind("<Button-1>", clickFunction)
f1_l1.bind("<Button-1>", clickFunction)
''' Alternative way for making lots of similar widgets, not to mention extending Label class
myLabels = [] #create List to make code more compact and to be able to use loops
for i in range(5, 0, -1):
myLabels.append(ttk.Label(self.frame_clk, text=" " + str(i) + " ",background = 'white',borderwidth=5,relief= 'ridge', font=('Helvetica', 12, 'bold'))
myLabels.bind("<Button-1>", clickFunction)
myLabels[i].grid(row =0 , column = 6 - i)
'''
Here is code you can add below "f1_l1.grid(row=0, column=6)" line (around ln 77). But I think you might need RadioButton for that purpose since it automatically unmarks other options and supports IntVar. More about events: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/events.html This webpage has excellent (but a bit outdated) documentation.
Btw, there is one quick fix you might want to apply when making programs for yourself. In Python you can add fields to classes and their instances outside their definition. E.g. in your code, you cold have written f1_l1.myNumber = 1 after "creating" it and in clickFunction instead of grid_info() use selectedNumber = event.widget.myNumber. It'd do the thing, but don't tell them I taught you that ;) since it isn't considered good practice adding fields that way.
If you have any more questions feel free to ask.