I am using tkinter to create a popup from within a plug-in for another program. The issue is that with two monitors, if the program I call the plug-in from is on the left monitor then the popup shows up on the right one.
OS is windows, but I would like to be able to use this for both windows and linux
Any way I can fix this so that the popup displays in front of the program?
code sample
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
called by
root = tk.Tk()
app = Application(master=root)
app.mainloop()
image of issue:
Related
I have a visualization tool written in Tkinter. Typically, I execute it standalone and then manually close the window when I'm finished. However, I'd like to be call it from another Python program, execute the main loop once (and save the canvas as an SVG), and then close the window, allowing the program to continue.
If I could not even bother opening a window, but just re-use my code to draw an SVG, that would work too.
My tk application looks like this:
class MainApplication(tk.Frame):
def __init__(self, output_path, parent=None):
tk.Frame.__init__(self, parent)
self.parent = parent
# draw visualization, save as svg
#...
#
From another part of my code, I call the
kill = True
root = tk.Tk()
root.title("Placement Visualizer")
MainApplication(output_path, root ).pack(side="top", fill="both", expand=True)
if kill:
root.destroy()
root.mainloop()
I get this error: Tcl_AsyncDelete: async handler deleted by the wrong thread Aborted (core dumped)
I've tried using root.quit() or removing root.mainloop(), but I don't get the desired result.
Thank you
In "the other part of my code":
if kill:
root.quit()
else:
root.mainloop()
To not open a window at all, but to draw everything and save the SVG, just call root.quit(). To open the window normally (and have to close it, killing the process), call root.mainloop().
I'm fairly new to python and try to build a simple GUI following an object oriented approach. Therefor I let my widget classes inherit from tk.Frame and create an application controller to build the GUI.
My application contains the following two files:
mainModule.py
# coding: utf8
from testPackage import myGUI
import Tkinter as tk
root = tk.Tk() # Main window
my_gui = myGUI.MainApplication(root)
root.mainloop() # Hold window open until we close it
myGUI.py
# coding: utf8
import Tkinter as tk
# Application initializer
class MainApplication(tk.Frame):
def __init__(self, master):
self.master = master
tk.Frame.__init__(self, master)
self.configure_gui()
self.pack() # <--- CODE IN QUESTION
self.create_widgets()
def configure_gui(self):
self.master.title("Any title")
self.master.geometry('800x600')
self.master.minsize(600, 100)
def create_widgets(self):
self.main_window = MainWindow(self)
self.main_window.pack()
# Main Data Window
class MainWindow(tk.Frame):
def __init__(self, master):
self.master = master
tk.Frame.__init__(self, master)
self.main_window = tk.Label(self, text="This is a test")
self.main_window.pack(side="top", fill="x")
Initially running my code without self.pack() (marked as #Code in question) in the MainApplication class definition gave me only the root basic window without the Label created from MainWindow class.
As simple as the answer may be but why?
I used a few sources to get into the topic inbefore and some of them didn't use any geometry manager on the root window (or i'm to inexpierienced to see it. Source below for examples).
Source:
https://www.begueradj.com/tkinter-best-practices.html
http://python-textbok.readthedocs.io/en/latest/Introduction_to_GUI_Programming.html#putting-it-all-together
Tkinter example code for multiple windows, why won't buttons load correctly?
Only after reading following answers regarding widget creation I came aware of the missing part:
Best way to structure a tkinter application
creating a custom widget in tkinter
Figuring that pack() on initialization would be the same as
MainApplication(root).pack(side="top", fill="both", expand=True)
or
Example(root).place(x=0, y=0, relwidth=1, relheight=1)
for a grid based layout.
I guess it's a very simple or obvious element i don't see relating to inheritance but i'm not entirely sure why have to pack() the MainApplication Frame and furthermore why it seems to work for example without this step.
Because MainWindow inherits from Frame, it is itself a frame. If you never call pack, place, or grid on it, it will be invisible. This is no different than if you created a button or scrollbar or any other widget and then don't call one of those methods on it.
Since all of the other widgets are a children of this frame, they will be invisible since their parent is invisible.
Somewhat unrelated to the question being asked, self.pack() is a code smell. Generally speaking, a class should never call pack, place or grid on itself. This tightly couples itself to the caller (meaning, this widget has to know that the caller is using one of those methods).
In other words, if you decide that MainApplication wants to switch from pack to grid for all of its children, you can't just update MainApplication, you also have to update MainWindow. In this case, the root window has only one child so the problem is fairly small, but by doing it this way you are starting a bad practice that will eventually cause you problems.
The rule of thumb is that the function that creates a widget should be responsible for adding it to the screen. That means that it would be better to do it like this:
root = tk.Tk()
my_gui = myGUI.MainApplication(root)
my_gui.pack(fill="both", expand=True)
You would then need to remove self.pack() from MainApplication.__init__.
You also have some very misleading code that might be contributing to the confusion. Take a look at this code:
# Main Data Window
class MainWindow(tk.Frame):
def __init__(self, master):
...
self.main_window = tk.Label(self, text="This is a test")
self.main_window.pack(side="top", fill="x")
Notice how you have a class named MainWindow. Within that you have a label that is named self.main_window, but self.main_window is not a MainWindow. This is especially confusing since the function that creates MainWindow also creates an instance variable named self.main_window.
You might want to consider renaming this label to be something else (eg: self.label, self.greeting, etc).
I am making an app with Tkinter (2.7) that imports a frame from another file. Unfortunately though the background colour isn't showing even though I have defined it in the imported file. The text widget on the frame shows up though. I have tried taking the mainframe = … out of the class and putting it into the body of the code between the two bottom lines but to no avail.
Main file:
import Tkinter as tk
import frames
class Window(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Example Code")
mainframe = frames.Main(start)
start = Window()
start.mainloop()
Frame file:
import Tkinter as tk
class Main(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.config(background="#5fe689")
tk.Label(text="hi").pack()
Any help is appreciated!
You never put the frame in the root window. You need to call pack, place or grid on mainframe.
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.
Question
How can I hide the two Tkinter root windows that are popping up in my program? I have tried to use root.widthdraw(). Here is a link to my Pastebin.
Background
I am trying to create a really basic email client to learn more about Tkinter and SMTP. I have decided that my program will first create a Toplevel window where the user will enter their credentials, and if the Server can authenticate them, then the program opens the email send dialogue. Annoyingly, I have not been able to hide the 2 other root windows which open when the program starts up. I have attempted to use root.widthdraw() to avoid this issue.
Relevant Code
#-----Authen is a toplevel class-------------
passcheck = Authen()
root = Tk()
root.mainloop()
root.widthdraw()
You should create your root window before creating any other windows. Otherwise you get exactly what you observe: Tkinter will automatically create a root window the first time you create some other widget, and the you are creating a second one.
I'm running Python2.7, with the default tkinter package, and my root object doesn't have a withdraw() method. Besides that, you can also just run mainloop off the toplevel called passcheck and it'll save you a window.
class Authen(Frame):
def __init__(self, master):
Frame.__init__(self, master)
then:
root = Tk()
passcheck = Authen(root)
root.mainloop()
edit: Here's a solution, instead of Authen being a TopLevel, have it be a Frame instead, and pass root as it's master. http://pastebin.com/TtnvU0er