Disable focus for tkinter widgets? - python

How can I make a widget that will not get the focus ever in tkinter?
For example, a button that when I will press TAB the focus will skip on him

I have found some time to provide a working example:
import tkinter
root = tkinter.Tk()
but1 = tkinter.Button(root, text ="Button 1")
but1.pack()
butNoFocus = tkinter.Button(root, text ="Button no focus", takefocus = 0)
butNoFocus.pack()
but2 = tkinter.Button(root, text = "Button 2")
but2.pack()
root.mainloop()
The takefocus option set to 0 will disable tab focus on butNoFocus.

I'm aware that this is an old question, but for any future readers, a simpler way to remove cycling focus for widgets is by unbinding <<NextWindow>>, as stated by Bryan Oakley here in this post.
import tkinter as tk
root = tk.Tk()
button1 = tk.Button(root, text='Hello') # Two example buttons
button2 = tk.Button(root, text='World!')
button1.pack(ipadx=15, ipady=10)
button2.pack(ipadx=10, ipady=10)
root.unbind_all('<<NextWindow>>') # Unbinding the behavior that causes Tab Cycling
root.mainloop()
This will disable Cycling all widgets with Tab, if you would want to remove cycling focus for a single widget, setting -takefocus to 0 would be easier

Related

Python | (Tkinter) only shows text when button is pressed

So I made a button to copy something to clipboard, but the button itself is always showing, but the text on it only when its pressed, how to fix it?
(Here the part with the button code:)
canvas1 = tk.Canvas(root, width=300, height=300)
canvas1.pack()
def copy_button():
clip = tk.Tk()
clip.withdraw()
clip.clipboard_clear()
clip.clipboard_append(pw)
clip.destroy()
button1 = tk.Button(text="Copy to Clipboard", command=copy_button, bg="grey", fg="white", font=("Helvetica", 12, "bold"))
canvas1.create_window(150, 150, window=button1)
Your disappearing text issue does not appear in Linux OS but I suspect your issue is related to your button1 = tk.Button(....) statement.
The first argument to a tk.Button widget must be its parent (see this link on this requirement) and not a keyword/option.
Try button1 = tk.Button(canvas1, text="Copy to Clipboard", ....). Doing so, you define the tk.Button to be a child of the tk.Canvas widget.
If you are putting more than a button in the canvas, you might want to consider:
defining a tk.Frame to be a child of the tk.Canvas(e.g. frame1=tk.Frame(canvas1)),
replace window=button1 with window=frame1,
letting button1 to be a child of frame1, e.g. button1 = tk.Button(frame1, text="Copy to Clipboard", ....)
Do let me know if this answer addresses your issue.
Other suggestion:
You can remove clip = tk.Tk(), clip.withdraw(), clip.destroy() and replace the clip term in clip.clipboard_clear() and clip.clipboard_append(pw) with root. Here, I assume that you had earlier defined root = tk.Tk() at the start of your code.

Trying to get my GUI windows automatically exit when I open the next window

How can I manage to automatic cancel this 1st window when I click the next window button?
sample code:
from tkinter import *
from tkinter import messagebox
root = Tk()
root.title("GUI practice")
def open():
top = Toplevel() # new window
top.title("Kokomi")
labels = Label(top, text="This one automatically close when i click the next window").pack()
button2 = Button(top,text="Close window", command=top.destroy).pack()
button3 = Button(top,text="Next window", command=open2).pack()
def open2():
top = Toplevel() # new window
top.title("Guide")
labels = Label(top, text="end").pack()
button2 = Button(top, text="Close window", command=top.destroy).pack() # destroy to quit things
button = Button(root, text="Open(No need to close this)", command=open).pack()
root.mainloop()
[Click open][1]
[Click Next window and after that this windows should disappear and continue to the 3rd picture][2]
[The 2nd picture goes disappear when i click the next window][3]
[1]: https://i.stack.imgur.com/plS1T.png
[2]: https://i.stack.imgur.com/EFW76.png
[3]: https://i.stack.imgur.com/xSZCp.png
For this specific case of using two functions and two windows, you can just simply rename the Toplevel widgets to different names and then globalize one and then access it from another function and destroy it before the new windows is shown.
def open():
global top
top = Toplevel() # new window
top.title("Kokomi")
Label(top, text="This one automatically close when i click the next window").pack()
Button(top, text="Close window", command=top.destroy).pack()
Button(top, text="Next window", command=open2).pack()
def open2():
top.destroy() # Destroy previously open window
top1 = Toplevel() # new window
top1.title("Guide")
Label(top1, text="end").pack()
Button(top1, text="Close window", command=top1.destroy).pack() # destroy to quit things
If you noticed, I removed the variable names of buttons and labels because its useless to have those as their value is None, read Tkinter: AttributeError: NoneType object has no attribute <attribute name>.
When you wish to use more functions and windows, you have to manually follow this procedure for all the functions. Unless ofcourse there is a better and cleaner way of designing your app using classes and frames.
Alternatively you can also invoke two functions from a single button, this method will get rid of globalization and renaming and might be a bit better than the above mentioned solution:
def open():
top = Toplevel() # new window
top.title("Kokomi")
Label(top, text="This one automatically close when i click the next window").pack()
Button(top, text="Close window", command=top.destroy).pack()
Button(top, text="Next window", command=lambda: [top.destroy(),open2()]).pack()
def open2():
top = Toplevel() # new window
top.title("Guide")
Label(top, text="end").pack()
Button(top, text="Close window", command=top.destroy).pack() # destroy to quit things

tkinter: Frame in Toplevel displayed in parent

I have currently two problems with Toplevel instances in Tkinter.
First and most important: I want to display a popup window and place 2 frames in it for better arangement in grid, but it doesn't work as I expect it to work:
import tkinter
root = tkinter.Tk()
tkinter.Button(root, text="ABC").grid(column=0, row=0)
tkinter.Label(root, text="FOO").grid(column=1, row=1)
win = tkinter.Toplevel()
f1 = tkinter.Frame(win).grid(row=0, column=0)
f2 = tkinter.Frame(win).grid(row=1, column=1)
tkinter.Label(f1, text="FRAME 1").grid()
tkinter.Label(f2, text="FRAME 2").grid()
root.mainloop()
I would expect "FRAME 1" and "FRAME 2" to be placed in the Toplevel window, but they are actually placed in root. How do I fix this?
Second, less important: The popup window in the code above is spawning behind the root window, while I would like it to be placed in front of root, how do I achieve this?
You set your frames f1 and f2 to the return-value of the grid() command, which is None, therefore tkinter.Label(f1, text="FRAME 1").grid() does not work as you expect.
Try something like this:
win = tkinter.Toplevel()
f1 = tkinter.Frame(win)
f1.grid(row=0, column=0)
tkinter.Label(f1, text="FRAME 1").grid()
When setting your geometry manager be it grid(), pack() or place() and you need to be able to interact with that widget later you will need to assign the widget to a variable and then apply the geometry manager on a new line using that variable name. This way your variable will not be a value of None but rather the proper widget. This happens because the geometry managers all return None.
Next the reason your labels are on the wrong windows is because when your labels try to connect with f1 and f2 they are not able to find a proper tkinter container due to the values being None so it defaults to the root tkinter window in an attempt to be place on something.
With fixing the None issues you will also fix your label issue.
To address the matter of your top level window not being in front of your root window there are a couple of things you can do. The main reason this is happening is how your code is generating the top level at __init__ rather than later with a button or a timed event.
If you really need your top level window to open at the same time as root you can use after() and a function to do this and it will be placed on top. If you do not need it right when the window opens you may want to assign a command to a button to run a function that builds the top window.
Here is an example with after():
import tkinter as tk
root = tk.Tk()
def create_top():
win = tk.Toplevel(root)
f1 = tk.Frame(win)
f1.grid(row=0, column=0)
f2 = tk.Frame(win)
f2.grid(row=1, column=1)
tk.Label(f1, text="FRAME 1").grid()
tk.Label(f2, text="FRAME 2").grid()
tk.Button(root, text="ABC").grid(column=0, row=0)
tk.Label(root, text="FOO").grid(column=1, row=1)
root.after(10, create_top)
root.mainloop()
Here is an example with a button:
import tkinter as tk
root = tk.Tk()
def create_top():
win = tk.Toplevel(root)
f1 = tk.Frame(win)
f1.grid(row=0, column=0)
f2 = tk.Frame(win)
f2.grid(row=1, column=1)
tk.Label(f1, text="FRAME 1").grid()
tk.Label(f2, text="FRAME 2").grid()
tk.Button(root, text="ABC", command=create_top).grid(column=0, row=0)
tk.Label(root, text="FOO").grid(column=1, row=1)
root.mainloop()

How to hide scroll bar on certain pages except for page 1?

So I have code for a scroll bar here:
master = tk.Tk()
master.geometry("200x200")
scrollbar = tk.Scrollbar(master)
scrollbar.pack(side="right", fill="y")
text = tk.Text(master, yscrollcommand=scrollbar.set)
text.insert("1.0", "Hello")
text.pack()
text.configure(state="disabled", highlightthickness=0)
scrollbar.config(command=text.yview)
master.mainloop()
And the scrollbar works, however it pops up on every single page in my program. I have a program with several pages and classes, and I would like the scrollbar to pop up when clicking a button that leads to that specific page with the scrollbar. The scrollbar keeps poping up on all pages, including the homepage, and I can't find a way to hide it.
This is the page I would like to put the scrollbar on:
class CookiesBiscuits(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Ingredients", font=LARGE_FONT)
label.pack(pady=10,padx=10)
backButton = tk.Button(self, text="Back",
command=lambda: controller.show_frame(PageTwo))
backButton.pack()
#scrollbar
master = tk.Tk()
master.geometry("200x200")
scrollbar = tk.Scrollbar(master)
scrollbar.pack(side="right", fill="y")
text = tk.Text(master, yscrollcommand=scrollbar.set)
text.insert("1.0", "Hello")
text.pack()
text.configure(state="disabled", highlightthickness=0)
scrollbar.config(command=text.yview)
master.mainloop()
If anyone has a way that will let me hide the scrollbar, I would really appreciate it.
The code you copied was designed for each page to be a standalone object. All widgets within a page are managed by the page.
If you want a page to have scrollbars and a text widget, those widgets need to have the page as the parent:
scrollbar = tk.Scrollbar(self)
scrollbar.pack(side="right", fill="y")
text = tk.Text(self, yscrollcommand=scrollbar.set)
You also need to remove the following statements, since in the comments you implied you don't actually want or need another window (plus there's the fact that creating a second instance of Tk and calling mainloop a second time is not something you should do in general)
master = tk.Tk()
master.geometry("200x200")
master.mainloop()

ttk.Entry.select_range() works with Button, but not ttk.Button in python / tkinter?

Can some one please explain why entry.select_range() works with a Button, but not a ttk.Button?
from tkinter import *
from tkinter import ttk
root = Tk()
entry = ttk.Entry(root)
entry.pack()
#This works
button = Button(root, text="Select your text", command=lambda:
entry.select_range(0, END))
#but this doesn't
##button = ttk.Button(root, text="Select your text", command=lambda:
## entry.select_range(0, END))
button.pack()
root.mainloop()
This answer from Google Group says,
However, on Windows (only) the selection will only become visible
when the entry gets the focus.
and also this page about ttk button says,
By default, a ttk.Button will be included in focus traversal ... To
remove the widget from focus traversal, use takefocus=False
So you need to add takefocus option to ttk.Button.
button = ttk.Button(root, takefocus=False, text=...)

Categories