I've been working on a GUI for a sort of "Rota manager" app that has a calendar object in the main window to allow the user to select a specific date on it and record beginning and end of his/her working shift.
In the main window I would like to have a tk.Label that display the date selected on the calendar and change every time the user clicks on a different day.
I found a lot of question related to something similar but I can't figure it how to make the label update itself after a click.
So far I could only display the first selection of the date (today's date by default).
Here the part of the code:
import tkinter as tk
from tkinter import StringVar
from tkcalendar import Calendar
class MainWindow:
def __init__(self, master):
self.master = master
master.title("Rota Manager")
master.geometry("400x550")
master.grid_rowconfigure(0, weight=1)
master.grid_columnconfigure(0, weight=1)
master.resizable(False, False)
self.cal = Calendar(self.master, font="Arial 14", selectmode='day', date_pattern='dd/mm/yy')
self.cal.grid(sticky='nsew', pady=10, padx=5)
self.v = StringVar()
self.dynamic_label = tk.Label(self.master, textvariable=self.v, font=('Arial', 10))
self.dynamic_label.grid(row=5, sticky='n')
self.v.set(f"Date selected: {self.cal.get_date()}")
if __name__ == "__main__":
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
This is just the portion of the code with the task I'm asking about.
As usual, thanks a lot to whoever can help.
Another solution is to use Calendar's textvariable option to keep track of the selected day. So just connect both the label and the calendar to the same StringVar.
import tkinter as tk
from tkinter import StringVar
from tkcalendar import Calendar
class MainWindow:
def __init__(self, master):
self.master = master
master.title("Rota Manager")
master.geometry("400x550")
master.grid_rowconfigure(0, weight=1)
master.grid_columnconfigure(0, weight=1)
master.resizable(False, False)
self.v = StringVar(self.master, Calendar.date.today().strftime("%d/%m/%y"))
self.cal = Calendar(self.master, font="Arial 14", selectmode='day',
date_pattern='dd/mm/yy', textvariable=self.v)
self.cal.grid(sticky='nsew', pady=10, padx=5)
label_frame = tk.Frame(self.master) # put static label and dynamic label in single frame
tk.Label(label_frame, text="Date selected: ",
font=('Arial', 10)).pack(side="left") # static_label
self.dynamic_label = tk.Label(label_frame,
textvariable=self.v, font=('Arial', 10))
self.dynamic_label.pack(side="left")
label_frame.grid(row=5, sticky='n')
if __name__ == "__main__":
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
Related
I have 3 modules (small, dont worry).
main_module = it has a combobox and a button. Comobobox list must be update each time a list (in module2) increases in number of names (combo values). Button calls the second window (module2)-->
myapp_second_window.py which has a entry box and another button. We write a name in the entry, push the button...voila..the list increases. In the origina app the list is created automatically when (2) is called.
Now I pass the list to a Pages.variable that is in -->
my_pages_to_connect_modules.
So, when app start I can populate combobox calling (2) to generate a Pages.variable list or populate combobox with json previously written.
The problem? --> how populate combobox while app is running. I mean, we go to (2) create a new name in entry come back to (1) and it is already there.
main_module
import tkinter as tk
from tkinter import*
from tkinter import ttk
import myapp_second_window
from myapp_second_window import SecondClass
root= Tk()
root.geometry("500x500")
root.title('myAPP_Main_Window')
class MainClass:
def __init__(self, parent,myapp_second_window):
self.parent = parent
self.my_widgets1()
def call_second_page (self):
Window2 = tk.Toplevel(root)
Window2.geometry('400x300')
myapp_second_window.SecondClass(Window2)
def my_widgets1(self):
self.field1_value = StringVar()
self.field1 = ttk.Combobox(self.parent, textvariable=self.field1_value)
self.field1['values'] = [1,2] # Pages.variable comes Here
self.field1.grid( row=0, column=0)
self.myButton = tk.Button(self.parent, text = "Call Second module", command = self.call_second_page)
self.myButton.grid(row=2, column=0)
if __name__ == '__main__':
app = MainClass(root, myapp_second_window)
root.mainloop()
myapp_second_window.py
import tkinter as tk
from tkinter import*
from tkinter import ttk
root= Tk()
root.minsize(550,450)
root.maxsize(560,460)
root.title('myAPP_Second_Window')
class SecondClass:
def init(self, parent):
self.parent = parent
self.my_widgets()
self.names = []
def my_widgets(self):
mylabel = Label(self.parent, text='Insert new name in next widget:')
mylabel.grid(column=0, row=0, sticky=W, pady=3)
button1 = tk.Button(self.parent, text="Click to enter Names in list", command=self.addToList)
button1.grid(column=3, row=0, sticky=W, pady=3)
self.name = StringVar()
valueEntry = tk.Entry(self.parent, textvariable= self.name)
valueEntry.grid(row=1, column=0, sticky=W, pady=3)
def addToList(self):
self.names.append(self.name.get())
print('listentries', self.names)
Pages.list_of_names = self.names
my_pages_to_connect_modules.
class Pages():
list_of_names = " "
It`s been challenging to me, every help is welcome. But please dont say just that I must update main window, I need to know how. Thanks to all of you.
I am trying to open a second window in tkinter but it always appears as a tab rather than separately. Code showing the problem is as follows:
import tkinter as tk
class MainWindow:
def __init__(self, master):
self.master = master
frame = tk.Frame(self.master)
button = tk.Button(frame, text = 'New Window', width = 25, command = self.new_window)
button.pack()
frame.pack()
def new_window(self):
newWindow = tk.Toplevel(self.master)
SecondWindow(newWindow)
class SecondWindow:
def __init__(self, master):
frame = tk.Frame(master)
quitButton = tk.Label(frame, text = 'Second Window')
quitButton.pack()
frame.pack()
def main():
root = tk.Tk()
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
When I run this I get the following output:
Clicking the button gives:
(Ignoring the secondary issue of the size) if we expand it we get the following:
I can get a separate window by dragging the tab. How to I code this so that I get the window displaying as a separate window when I click the button ?
How can I create a Modal Dialogue Box by messagebox.showerror?
messagebox.showerror("Error", "No downloader.exe found")
When I create a messagebox, I found I can move the root windows.
and i need to create a Modal Dialogue Box like filedialog.askopenfilename.
filedialog.askopenfilename(initialdir = self.get_path()+ '/bin', filetypes=[("BIN Files", ".bin")])
here's the codes:
import tkinter
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
import os
class Application(Frame):
def createWidgets(self, main_frame):
#self.llabel = Label(main_frame, text="Ready", width=20, bg="turquoise", font = ftLabel)
#self.llabel.grid(row=0, column=0, sticky=W+E) #columnspan=2
self.frame1 = Frame(main_frame)
self.frame1.grid(row=0, column=0, columnspan=2, sticky=W+E+N+S)
self.addr = StringVar()
self.addrtext = Entry(self.frame1, width=20, textvariable = self.addr)
self.addrtext.grid(row=0, column=0, sticky=W+E+N+S)
self.addr.set("0x0")
self.bfile = Button(self.frame1, text='BIN File', width=20)
self.bfile.grid(row=0, column=1, sticky=W+E+N+S)
messagebox.showerror("Error", "No downloader.exe found")
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack(fill=BOTH, expand=1)
main_frame = Frame(master)
main_frame.pack(fill="y", expand=1)
self.createWidgets(main_frame)
self.dl_thread = 0
if __name__=="__main__":
root = Tk()
#lock the root size
root.resizable(False,False)
app = Application(master=root)
app.mainloop()
I tried your code and messagebox.showerror is modal to me.
Maybe there is something else in your code (threads?) or maybe it's
dependent on your environment.
For reference, my entire code:
from tkinter import *
from tkinter import messagebox
root = Tk()
def do(): messagebox.showerror("Error", "No downloader.exe found")
b = Button(root, text='Dialog', command=do)
b.pack()
root.mainloop()
If that doesn't work you might want to take a look at: Tkinter messagebox not behaving like a modal dialog
I am dabbling in tkinter's possibilities to make a simple application that shows a "Enter password" little window upon startup. But the weirdest behaviour started to happen...
mainWindow.py
import tkinter as tk
import password
class mainWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("mainWindow")
self.geometry("{0}x{1}+20+20".format(50,50))
if __name__ == "__main__":
mainW = mainWindow()
passW = password.passwordWindow()
passW.resizable(False, False)
passW.attributes("-topmost", True)
passW.mainloop()
password.py
import tkinter as tk
import mainWindow
class passwordWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Password")
self.frame = tk.Frame(height=2, bd=1, relief=tk.SUNKEN)
self.frame.pack(fill=tk.X, padx=5, pady=5)
self.label = tk.Label(self.frame, text="This Label is packed\nin the Password's Frame.")
self.label.pack(fill=tk.BOTH, expand=1)
Result:
Needless to say, it's not the desired effect. The "Label" part should be on the password window! Any clue why am I getting this result? Thanks in advance!!
The 1st porblem I can see is you are using Tk() twice here. Instead of using Tk() for a new window use Toplevel() instead. Toplevel is meant to be used to create new windows after the main window has been generated.
Next we need to pass the root window to the password class so we can use it as the top level of the main windows instance.
So in short your code should look like this:
mainWindow.py
import tkinter as tk
import password
class mainWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("mainWindow")
self.geometry("{0}x{1}+20+20".format(50,50))
if __name__ == "__main__":
mainW = mainWindow()
passW = password.passwordWindow(mainW)
passW.resizable(False, False)
passW.attributes("-topmost", True)
mainW.mainloop()
password.py
import tkinter as tk
import mainWindow
class passwordWindow(tk.Toplevel):
def __init__(self, controller):
tk.Toplevel.__init__(self, controller)
self.title("Password")
self.frame = tk.Frame(self, height=2, bd=1, relief=tk.SUNKEN)
self.frame.pack(fill=tk.X, padx=5, pady=5)
self.label = tk.Label(self, text="This Label is packed\nin the Password's Frame.")
self.label.pack(fill=tk.BOTH, expand=1)
Results:
I have this ttk calendar and my program is meant to update a field when a date in the calendar widget is pressed.
Here are the start_date and end_date fields:
start_date = StringVar()
start_date = ttk.Entry(f2, width=15, textvariable=start_date)
start_date.grid(column=2, row=1, sticky=E)
ttk.Label(f2, text="Start date:", width=10).grid(column=1, row=1, sticky=E)
end_date = StringVar()
end_date = ttk.Entry(f2, width=15, textvariable=end_date)
end_date.grid(column=2, row=2, sticky=E)
ttk.Label(f2, text="End date:", width=10).grid(column=1, row=2, sticky=E)
Here's the function that the button triggers:
def callbackCal():
root2=Toplevel(f2)
ttkcal = ttkcalendar.Calendar(root2,firstweekday=calendar.SUNDAY)
ttkcal.pack(expand=1, fill='both')
root2.update()
root2.minsize(root2.winfo_reqwidth(), root2.winfo_reqheight())
Here's the button code:
b=ttk.Button(f2, width=4, text="Cal", command=callbackCal).grid(column=3,row=1, sticky=W)
Thanks to NorthCat's help, I was able to get this far. And I know the ttk calendar has the methods _pressed() , _show_selection() and selection(). But I have no idea how I can use them in order to show the selected date when it is clicked. And also, to close the calendar widget once that is done.
Thanks a lot! and sorry for these newbie questions.
I don't pretend to understand the code, but I found an answer to another question that suggested a few changes, the answer was from kalgasnik
Python tkinter with ttk calendar
Then I made this change :-
def __init__(self, master=None, selection_callback=None, **kw):
and added this in the init function
self.selection_callback = selection_callback
In the _pressed function I added
if self.selection_callback:
self.selection_callback(self.selection)
Basically adding a callback to get the values when a date is clicked.
My sample callback program was :-
import calendar
import tkinter as TK
import tkinter.font
from tkinter import ttk
from ttk_calendar import Calendar
import sys
class Test():
def __init__(self, root):
self.root = root
self.root.title('Ttk Calendar')
frame = ttk.Frame(self.root)
frame.pack()
quit_button = ttk.Button(frame, text="Calendar", command=self.use_calendar)
quit_button.pack()
self.calendarroot = None
def use_calendar(self):
if not self.calendarroot:
self.calendarroot=TK.Toplevel(self.root)
ttkcal = Calendar(master=self.calendarroot, selection_callback=self.get_selection, firstweekday=calendar.SUNDAY)
ttkcal.pack(expand=1, fill='both')
self.calendarroot.update()
self.calendarroot.minsize(self.calendarroot.winfo_reqwidth(), self.calendarroot.winfo_reqheight())
else:
self.calendarroot.deiconify() # Restore hidden calendar
def get_selection(self, selection):
print (selection)
self.calendarroot.withdraw() # Hide calendar - if that is what is required
if __name__ == '__main__':
root = tkinter.Tk()
x = Test(root)
root.mainloop()
I tried to destroy the TopLevel frame but got an error, hence I used withdraw and deiconify, not best, but at least I got something to work.
A bit of a muddled answer I realize, but you might be agle to figure out a better solution.