Tkinter widgets only drawn if I press alt button - python

I have a small app on Linux in which I sub-class the Frame class from tkinter and sometime the widgets are only drawn after I press the alt button. Everything works fine, though this is the first time I use this GUI and I may miss something.
Follows a short example of my code:
from tkinter import *
class MyFrame(Frame):
def one_method(self):
root_frame.geometry("200x400")
button = Button(self, command=self.clean_and_draw_more_widget, text="Hello")
button.pack(side=TOP) #I also use grid()
the main driver code:
root_frame = Tk()
root_frame.title("Window")
frame = MyFrame(root_frame)
frame.pack()
root_frame.mainloop()
As you can see nothing compless, but still I have this problem.
EDIT
I use grid() and pack() but each one in different methods
Thanks for helping

Related

Tkinter: Remove active button highlight

How can I remove the dotted black border after a button is clicked in Tkinter (with Ttkthemes)?
I'm on Windows 10, Python 3.7.9.
There seems to be no uniform way to remove it and I searched across Google and SO with no luck. Thanks.
Here's a minimal example:
import tkinter
import tkinter.ttk
from ttkthemes import ThemedTk
tk = ThemedTk(theme="arc")
tk.configure(background="#f5f6f7")
tk.resizable(0,0)
selectFileInput = tkinter.ttk.Button(
tk,
text="Select Input File"
)
selectFileInput.place(x=20,y=60)
tk.mainloop()
I found the solution. It was to create a dummy button and focus it to remove focus from the button to the dummy button by using dummy.focus()
ttk.Button has the keyword argument takefocus this can be set to false and the button does not take focus after it is clicked.
ttk.Button(.., .., takefocus=False)
Therefore you do not need a hack with a dummy button that takes focus as in the answer.

Python Tkinter how to hide a widget without removing it

I know similar things have been asked a lot, but I've tried to figure this out for two hours now and I'm not getting anywhere. I want to have a button in a Tkinter window that is only visible on mouseover. So far I failed at making the button invisible in the first place (I'm familiar with events and stuff, that's not what this question is about) pack_forget() won't work, because I want the widget to stay in place. I'd like some way to do it like I indicated in the code below:
import tkinter as tki
class MyApp(object):
def __init__(self, root_win):
self.root_win = root_win
self.create_widgets()
def create_widgets(self):
self.frame1 = tki.Frame(self.root_win)
self.frame1.pack()
self.btn1 = tki.Button(self.frame1, text='I\'m a button')
self.btn1.pack()
self.btn1.visible=False #This doesnt't work
def main():
root_win = tki.Tk()
my_app = MyApp(root_win)
root_win.mainloop()
if __name__ == '__main__':
main()
Is there any way to set the visibility of widgets directly? If not, what other options are there?
Use grid as geometry manager and use:
self.btn1.grid_remove()
which will remember its place.
You can try using event to call function.
If "Enter" occurs for button then call a function that calls pack()
and if "Leave" occurs for button then call a function that calls pack_forget().
Check this link for event description:List of All Tkinter Events
If you wish your button to stay at a defined place then you can use place(x,y) instead of pack()

Python Tkinter side notebook tabs

I am redesigning the GUI of a program that uses tkinter in python. I used ttk widgets for this program, but I think, even on W10, the interface is way too old so I decided to update the visual interface for the program using METRO interface or W10 alike UI.
The first thing that come in mind, is that W10 have a left-side "tabs" that are very beautiful and useful, and the question is if is that a way to using the ttk.notebook widget, change the position of the tabs?
Otherwise, I could do buttons placed on the side and load frame widgets on every button clicked, but I think this could overload so much the program loading constantly frames and widgets, and I am trying to avoid this way.
Thanks to everyone.
It is possible to change the position of the tabs by configuring the tabposition option of the TNotebook style.
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
style = ttk.Style(root)
style.configure('lefttab.TNotebook', tabposition='ws')
notebook = ttk.Notebook(root, style='lefttab.TNotebook')
f1 = tk.Frame(notebook, bg='red', width=200, height=200)
f2 = tk.Frame(notebook, bg='blue', width=200, height=200)
notebook.add(f1, text='Frame 1')
notebook.add(f2, text='Frame 2')
notebook.pack()
root.mainloop()
This is how it looks like with the default theme on linux:
However, the text inside the tabs is always horizontal. I don't have Windows, so I don't know exactly how the W10 UI looks like, but I guess that you would like to rotate the tabs, not just change there position and I don't know how to do that.

Tkinter Focus lost after askstring

I am currently implementing a program that uses many tkinter frames and while subframe is being opened I want the superframe to be locked for the user (otherwise things will not work out). After some research I found the grab_set and grab_release method which worked quite fine.
However once the subframe (instanciated by Toplevel) calls the askstring the grab is "losed" and the user can interact with the superlevel window again. An example would be this (very simplified code):
import tkinter as tk
import tkinter.simpledialog
root = tk.Tk()
def open_sublevel():
tl = tk.Toplevel(root)
def ask():
print(tk.simpledialog.askstring("askstring", "askstring"))
tk.Button(tl, text="ask", command=ask).pack()
tl.grab_set()
root.wait_window(tl)
tl.grab_release()
print("release")
tk.Button(root, text="asdf", command=open_sublevel).pack()
tk.mainloop()
Once the user opens the subframe by clicking "asdf" the frame containing "asdf" will be locked for the duration while the subframe is opened. However once the user selects the "ask"-Button in the subframe this "lock" somehow disappears.
According to the notes in the tkinter library:
A grab directs all events to this and descendant widgets in the application.
I am not able so far to find any documentation that would explain why the grab_set() is falling off after you finish submitting your askstring but I would imaging it is because once the widget is gone the grab_set() falls off. Just like if you were to close out the Toplevel window.
In this case tl.grab_release() does not appear to be needed as grab releases once the window closes.
From what I have tested if you reset the grab_set() after the askstring is done then it will still work properly.
You need to simply add tl.grab_set() just below print(tk.simpledialog.askstring("askstring", "askstring")).
Modified code below:
import tkinter as tk
import tkinter.simpledialog
root = tk.Tk()
def open_sublevel():
tl = tk.Toplevel(root)
tl.grab_set()
def ask():
print(tk.simpledialog.askstring("askstring", "askstring"))
tl.grab_set()
tk.Button(tl, text="ask", command=ask).pack()
print("release")
tk.Button(root, text="asdf", command=open_sublevel).pack()
tk.mainloop()
setting the parent for simpledialog will make simpledialog take focus
x = simpledialog(parent = window_x, title = z etc.)
this will make sure x takes focus and not withdraw

Multiple tkinter windows look different when closing and reopening window

I got the following code from a tutorial. I then modified main() so that two windows are created as seperate threads. When I run it, only one window is created. Then when I press the Quit button in that window, a second window appears. In this new window the button has a different look than the first one (a look which I like better) and then if I press either of the two Quit buttons, both windows close and the program exits.
Why does the second window not appear until the first Quit button is pressed, and why does it look different when it does appear?
EDIT: This happens when no threads are used as well, where only one window is created at a time.
EDIT: This is a screenshot of the two windows that are created. The one on the left is created with the program is run, the one on the right is created after clicking the "Quit" button on the first.
from Tkinter import Tk, BOTH
from ttk import Frame, Button, Style
class Example(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Quit button")
self.style = Style()
self.style.theme_use("default")
self.pack(fill=BOTH, expand=1)
quitButton = Button(self, text="Quit",
command=self.quit)
quitButton.place(x=50, y=50)
from threading import Thread
def main():
for i in range(2):
root = Tk()
root.geometry("250x150+300+300")
app = Example(root)
Thread(target=root.mainloop()).start()
if __name__ == '__main__':
main()
You cannot use tkinter this way. Tkinter isn't thread safe, you can only ever access tk widgets and commands except from the thread that created the root window.
As for one window only showing after the other is destroyed even without threading, it's hard to say since you don't show the code. If you're creating more than one instance of Tk, and calling mainloop more than once, that's the problem. Tkinter is designed to work when you create precisely one instance of Tk, and call mainloop precisely once.
If you want more than one window, create a single instance of Tk for the first window, and instances of Toplevel for additional windows.

Categories