hiding tkinter window using withdraw vs wm_withdraw - python-3.x

What is the difference between withdraw and wm_withdraw?
import time
import tkinter as tk
def hide():
root.withdraw()
time.sleep(2)
root.deiconify()
root = tk.Tk()
tk.Button(root, text = 'hide', command = hide).pack()
root.mainloop()
When the 'hide' button is clicked, the window is hidden. It disappears from the panel (taskbar), and is not visible in the task view (simultaneous view of all open windows) for 2 seconds.
import time
import tkinter as tk
def hide():
root.wm_withdraw()
time.sleep(2)
root.deiconify()
root = tk.Tk()
tk.Button(root, text = 'hide', command = hide).pack()
root.mainloop()
Same code, but wm_withdraw instead of withdraw. Again, clicking the 'hide' button makes the both the taskbar entry and the window itself invisible for 2 seconds.
Is there any difference at all between these two? Which one should I use? Further, should I use deiconify or wm_deiconify? All four combinations (withdraw, deiconify; wm_withdraw, deiconify; withdraw, wm_deiconify; wm_withdraw, wm_deiconify) seem to do the exact same thing. Is there any application where they will do different things?

There's no difference between them - they both (withdraw and deiconify) just shortucts for wm_ counterparts.
The same applies to all functions, that interact with Window manager under Wm class.

There is no difference between withdraw and wm_withdraw. I can not specify why this was done, but here is the source of tkinter in which we have line withdraw = wm_withdraw (which makes it clear that both calls end up at the same method):
def wm_withdraw(self):
"""Withdraw this widget from the screen such that it is unmapped
and forgotten by the window manager. Re-draw it with wm_deiconify."""
return self.tk.call('wm', 'withdraw', self._w)
withdraw = wm_withdraw

Related

How do I display a message before closing the tkinter window?

A message is required to be shown just before closing the tkinter window on the click of a close button added to the window.
lab = Label(window,text = 'thank you')
lab.grid()
window.destroy()
I used the above code to do so, but the window gets closed before the message is being displayed
Can I have the solution for this?
You can either use this:
from tkinter import Tk
import tkinter.messagebox as msgbox
def display_msg():
msgbox.showinfo(title='', message='Thank You')
root.destroy()
root = Tk()
root.protocol('WM_DELETE_WINDOW', display_msg)
root.mainloop()
which will show You a messagebox before closing,
or if You want to display a widget use this:
from tkinter import Tk, Label
def display_msg():
msg = Label(root, text='Thank You!')
msg.pack()
root.after(3000, root.quit)
root = Tk()
root.protocol('WM_DELETE_WINDOW', display_msg)
root.mainloop()
When You protocol root with 'WM_DELETE_WINDOM' You can make it execute a function when You try to close the window.
In the first example it will just show an infobox.
In the second example it will wait for 3 seconds (3000 miliseconds) and then destroy the root

How to forget buttons created by a loop?

I need to create buttons with a for loop, here its an example of what i need to do:
But the problem is that when I press the different buttons, its prints the correct number, but it only forgets the last button created (in this case the button "4").
How can i do to forget all the buttons at once by only pressing one of them?
Its important the creation of the buttons by the loop
import tkinter as tk
root=tk.Tk()
def Eliminate(Number):
def Forget(number):
button.pack_forget()
print(number)
for i in range(Number):
button= tk.Button(root,text=i,command=lambda number=i:Forget(number))
button.pack()
Eliminate(5)
root.mainloop() ```
You need to pass in the button widget itself, not the number that created it. To do that you simply need to issue the command argument in a new line, like this:
import tkinter as tk
def Forget(btn):
btn.pack_forget()
def Eliminate(Number):
for i in range(Number):
button= tk.Button(root,text=i)
button.config(command=lambda button=button:Forget(button))
button.pack()
root=tk.Tk()
Eliminate(5)
root.mainloop()
However as the command is only calling the pack_forget method, it's much easier to forget making your own callback function and just provide pack_forget:
import tkinter as tk
def Eliminate(Number):
for i in range(Number):
button= tk.Button(root,text=i)
button.config(command=button.pack_forget)
button.pack()
root=tk.Tk()
Eliminate(5)
root.mainloop()

How to use the event driven GUI menu's default value, before user starts his events in tkinter, Python?

I have one menu in my GUI. This menu is used to select which label will be added to the GUI.
When I start the program, the menu already shows the default option selected, but this option isn't used anywhere in the program. It requires user's action (click and select in menu) to get something out of that menu.
I want my program to immediately use the default menu's option, that later can be changed by the user.
Can you give me tips not only for this specific label-related task, but in general? How to use the default menu value in the program, without interaction with the menu?
This is my code:
from tkinter import *
root=Tk()
root.title("test")
# root.geometry("400x400")
def selected(event):
myLabel=Label(root, text=clicked.get()).pack()
options=["a","b","c"]
clicked = StringVar()
clicked.set(options[0])
drop=OptionMenu(root,clicked,*options, command=selected)
drop.pack()
root.mainloop()
An easy way:
from tkinter import *
root=Tk()
root.title("test")
# root.geometry("400x400")
def selected(event):
myLabel['text'] = clicked.get()
options=["a","b","c"]
clicked = StringVar()
clicked.set(options[0])
drop=OptionMenu(root,clicked,*options, command=selected)
drop.pack()
myLabel = Label(root, text=clicked.get())
myLabel.pack()
root.mainloop()
Or I suggested you use textvariable,then you needn't to use a function to change the label:
from tkinter import *
root=Tk()
root.title("test")
# root.geometry("400x400")
options=["a","b","c"]
clicked = StringVar()
clicked.set(options[0])
drop=OptionMenu(root,clicked,*options)
drop.pack()
myLabel = Label(root, textvariable=clicked) # bind a textvariable
myLabel.pack()
root.mainloop()

stop ttk.Entry() from reading keyboard

Environment: macOS Catalina, Python 3.7.4, Tcl/Tk 8.6.9, VSC 1.39.1
I have a situation where I am using a bar/qr code scanner to provide a string to a ttk.Entry() method, which then fires off a function.
The reader is seen by the OS as an HID keyboard, so the text from the QR code is received by the ttk.Entry() widget that I give focus to during code execution. I have bound the widget to the key because the scanner sends a cr/lf at the end of the text string, which works as needed.
However, I am running into an issue where if the qr code lingers over the scanner too long it will rescan the qr code and the widget receives the qr code text again, which then causes it to be processed again.
I have tried disabling the ttk.Entry() in the function, deleting the widget contents, and removing focus to no avail. The behavior I'm seeing is occurring even though the widget is disabled and does not have focus, it is still getting input and executing the function again if the scanner rescans the qr code while the function is executing.
In this first example, I simply tried to disable the widget, but that doesn't work. The widget still gets the later scans while in the function.
# test-ttk-entry1.py
import time
import tkinter as tk
from tkinter import StringVar, ttk
root = tk.Tk()
def print_text(event):
global kbEntry
textValue = kbEntry.get()
kbEntry.configure(state="disabled")
time.sleep(2) # Add in a delay to allow for repeat scan
print(textValue)
time.sleep(2) # Add in a delay to allow for repeat scan
kbEntry.configure(state="active")
kbText = StringVar()
kbEntry = ttk.Entry(root, width=10, textvariable=kbText)
kbEntry.bind("<Return>", print_text)
kbEntry.pack()
kbEntry.focus_set()
root.mainloop()
The second attempt was to disable the entry widget and upon making it active again delete the text in the field.
# test-ttk-entry2.py
import time
import tkinter as tk
from tkinter import END, StringVar, ttk
root = tk.Tk()
def print_text(event):
global kbEntry
textValue = kbEntry.get()
kbEntry.delete(0, END)
kbEntry.configure(state="disabled")
time.sleep(2) # Add in a delay to allow for repeat scan
print(textValue)
time.sleep(2) # Add in a delay to allow for repeat scan
kbEntry.configure(state="active")
kbEntry.delete(0, END)
kbText = StringVar()
kbEntry = ttk.Entry(root, width=10, textvariable=kbText)
kbEntry.bind("<Return>", print_text)
kbEntry.pack()
kbEntry.focus_set()
root.mainloop()
And finally, I was reading about taking focus from a widget and giving focus to the root window, so I added that in and it still prints multiple times to the console like there is a keyboard buffer being read by the ttk.Entry() widget. The weird thing is it seems like widgets don't normally respond to any calls to methods when they are disabled, but it appears the ttk.Entry() widget's properties/attributes (excuse me if my OOP terms are not correct) can be manipulated while disabled.
# test-ttk-entry2.py
import time
import tkinter as tk
from tkinter import END, StringVar, ttk
root = tk.Tk()
def print_text(event):
global kbEntry
textValue = kbEntry.get()
kbEntry.delete(0, END)
kbEntry.configure(state="disabled")
root.focus_set()
time.sleep(2) # Add in a delay to allow for repeat scan
print(textValue)
time.sleep(2) # Add in a delay to allow for repeat scan
kbEntry.configure(state="active")
kbEntry.delete(0, END)
kbEntry.focus_set()
kbText = StringVar()
kbEntry = ttk.Entry(root, width=10, textvariable=kbText)
kbEntry.bind("<Return>", print_text)
kbEntry.pack()
kbEntry.focus_set()
root.mainloop()
So how can I prevent the ttk.Entry() widget from accepting any input from the HID/keyboard device while my function is executing?
Since I am unable to find a way to temporarily disable the .Entry() widget programmatically to keep it from reading successive inputs, I have come up with this solution:
# test-ttk-entry2.py
import time
import tkinter as tk
from tkinter import END, StringVar, ttk
root = tk.Tk()
tempStr = "" # Global temporary string variable to trip repeated scans
def print_text(event):
global tempStr
textValue = kbEntry.get()
if tempStr == textValue:
kbEntry.delete(0, END)
print ("Duplicate scan")
return
tempStr = textValue
kbEntry.delete(0, END)
print(textValue)
time.sleep(3) # Simulate the time it takes for the function to complete
kbEntry = ttk.Entry(root, width=10)
kbEntry.bind("<Return>", print_text)
kbEntry.grid(row=0, column=0, padx=10, pady=10)
kbEntry.focus_set()
root.mainloop()

tkinter Button does not open new window

I’m experiencing problems with tkinter.
I have code that is meant to open a new window on button press, but the window does not open.
Here’s my code:
Main Module
#!/usr/bin/python
#encoding: latin-1
import tkinter
import ce
#window config
window = tkinter.Tk() #create window
window.title("BBDOassist") #set title
window.geometry("750x500") #set size
…
# buttons
button_ce = tkinter.Button(window, text="CE Evaluation", command="ce.run()")
button_ce.pack()
window.mainloop() #draw the window and start
’CE’ Module
#!/usr/bin/python
#encoding: latin-1
import tkinter
…
def run():
#window config
window = tkinter.Tk() #create window
window.title("BBDOassist - CE Evaluation") #set title
window.geometry("750x500") #set size
…
window.mainloop() #draw the window and start
You have at least two problems
First, you must give the command attribute a reference to a function. You are passing it a string. A string is useless. You need to change your button definition to this:
button_ce = tkinter.Button(window, text="CE Evaluation", command=ce.run)
Second, if you want to create additional windows then you need to create instances of Toplevel rather than Tk. A tkinter program needs exactly one instance of Tk, and you need to call mainloop exactly once.
Change run to look like this (and remove the call to mainloop inside run):
def run():
#window config
window = tkinter.Toplevel()
...

Resources