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

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.

Related

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()

Destroy window not closing all windows properly

I have two queries in this section.
In my code i have created two frames under root, the first frame have "NEXT" button to go on second frame. In second frame there is Run button, which has mapped with close_window function. It should close all windows properly. But in my case not closing it.
When i click "Run" i need to close all windows and need to execute another script on the same directory. Is that possible to do it ?
from Tkinter import *
def close_window():
frame2.destroy()
frame1.destroy()
def swap_frame(frame):
frame.tkraise()
root = Tk()
root.geometry("900x650+220+20")
root.title("Testing")
root.configure(borderwidth="1", relief="sunken", cursor="arrow", background="#dbd8d7", highlightcolor="black")
root.resizable(width=False, height=False)
frame2 = Frame(root, width=900, height=650)
frame1 = Frame(root, width=900, height=650)
Button1 = Button(frame1, text="Next", width=10, height=2, bg="#dbd8d7", command=lambda: swap_frame(frame2))
Button1.place(x=580, y=580)
Button2 = Button(frame2, text="Run", width=10, height=2, bg="#dbd8d7", command=close_window,)
Button2.place(x=580, y=580)
frame2.grid(row=0, column=0)
frame1.grid(row=0, column=0)
root.mainloop()
what is wrong in the code?
"Destroy window not closing all windows properly"
Nor should it. destroy method destroys a widget, and when a widget is destroyed so are its children.
Since neither frame1 nor frame2 are 'windows' or a window's parents, there's no window destruction taking place.
"When I click "Run" I need to close all windows and need to execute another script in the same directory. Is that possible to do it?"
It is possible. Use quit on any GUI object, instead of destroy. It stops the mainloop, hence destroying the entire GUI. In that it solves the first problem as well. Then import another_script:
...
def close_window():
frame1.quit()
...
root.mainloop()
import another_script

Disable focus for tkinter widgets?

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

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