Does wm_iconbitmap method forces tkinter to enter an event loop while it processes the icon file? Is there a way to avoid this? Check this example that illustrates this:
from tkinter import *
import time
root = Tk()
root.iconbitmap('images/logo.ico') # Without `mainloop()` shows the window, means the events have started being processed?
time.sleep(3)
I couldn't find any related info in the documentation either.
Thanks in advance :)
Edit: A little more research shows that root.iconbitmap() does not enter event loop, maybe because there is no icon to process/check? But that would not answer why root.iconphoto does not enter an event-loop when called
The eventloop and the created window are different things. In your case it is the window that is forced into existence and is mentioned in the source code as a side effect:
Side effects:
One or all windows may have their icon changed.
The Tcl result may be modified. The window-manager will be
initialised if it wasn't already. The given window will be forced
into existence.
See the source code for details.
Related
My current situation is that I open a process, which opens in a random location (thats how this process works).
I have the process PID so I need to somehow focus this window, and move it to the center of my screen.
Im doing something wrong as I can't even set focus on that window... tried it with different apps and got the same result...
The way I select the window -
appl = pywinauto.application.Application()
appl.connect(process=824)
app_dialog = appl.top_window_()
app_dialog.Minimize()
app_dialog.Maximize()
##app_dialog.SetFocus() ##doesn't work aswell
##pywinauto.win32functions.SetForegroundWindow(app_dialog)## doesn't work
Thanks for reading :)
Can't say why it doesn't work with pywinauto...
Got it to work with win32gui as the answer here- Python Window Activation
long yet efficient ;)
Method app_dialog.set_focus() should work in pywinauto 0.6.2. If not, it might be a bug. Is your application publicly available somehow? I'd like to reproduce it on my side. Are you trying to activate a background window while you have modal dialog on top of it?
Second case is a wrong usage of SetForegroundWindow(...). It should give a handle, but you pass WindowSpecification object app_dialog. Right way is the following:
handle = app_dialog.wrapper_object().handle
pywinauto.win32functions.SetForegroundWindow(handle)
I am trying to follow along in the book Python Programming for Kids. I am working with a group of neighborhood kids and to reduce the cost we are using the Raspberry Pi as our computer. I am a Windows guy and the GUI builder of choice for me is WxPython. I am trying to get ready for next weeks class and have run into a problem. I have entered the code below
from tkinter import *
tk = Tk()
btn = Button(tk,text = 'click me')
btn.pack()
according to the book the second line is supposed to create a window (frame I think in the Wx world) and the third line defines a button object and the fourth inserts it in the window.
However, this is not working - the tk window is not displayed nor is there a button on the screen and I have not been able to figure out why. tkinter is imported and the tk object has lots of methods/properties visible when I type dir(tk) so I know that we have tkinter on the Pi's.
Again, after entering this code nothing visible happens. I deleted the code relating to creating the button and still nothing happens so I am not sure where to start diagnosing the issue I have Googled for information and found nothing useful
Any insight would be appreciated.
I did ask this question on superuser but there is no Tkinter tag so . . .
humm do I need a
tk.pack()
statement - I will report back.
No, you do not need tk.pack(). What you do need is start the event loop. The event loop, as it's name suggests, is a loop that processes events. Everything in Tkinter happens as a response an event, including the actual drawing of a widget or window on the screen.
As the last line in your file, add the following:
tk.mainloop()
I encourage you to not do the import the way you are doing. I know a lot of tkinter tutorials do it that way, but it's a bad thing to do. Instead, do it like this:
import tkinter as tk
root = tk.Tk()
btn = tk.Button(root, text='click me')
btn.pack()
root.mainloop()
It requires typing three extra characters for every widget, but in exchange you get code that is easier to maintain over time.
PEP8 is the official python style guide, and it explicitly recommends against wildcard imports:
Wildcard imports (from import *) should be avoided, as they
make it unclear which names are present in the namespace, confusing
both readers and many automated tools. There is one defensible use
case for a wildcard import, which is to republish an internal
interface as part of a public API (for example, overwriting a pure
Python implementation of an interface with the definitions from an
optional accelerator module and exactly which definitions will be
overwritten isn't known in advance).
See http://legacy.python.org/dev/peps/pep-0008/#imports
I am having a problem between the python shell in my IDE and the Tkinter window. What I am trying to do is have all of my user input in the shell, and then I would like to output the corresponding information in a Tkinter window.
However, when my window is made and pops up, I close it to continue my program in the shell, then I continue with input. However, when I try to reinitialize my window. It says that the window has been destroyed. I understand what this means so I tried having a Toplevel window where I output my info which can be closed, and hide my root window, but the shell will not continue until I close/destroy the root window as well.
Is there a way I can continue in the shell without destroying my root window? I am fairly new to this language so any help would be very much appreciated.
This is my general idea:
from Tkinter import *
#get all my info from the shell
root = Tk()
root.withdraw() #hide the root window
main = Toplevel()
#this is the window that I want to be able to close and open later
#get more info from the shell after main is closed
#now I want to open the updated main window
Thanks in advance! (And I am working on Windows if that matters)
I'm not sure if the way you are trying to do this is the most efficient way, but i would propose these changes so far:
from Tkinter import *
#get all my info from the shell
window = Tk()
window.iconify() #hide the root window
#get more info from the shell after main is closed
window.deiconify()
window.mainloop() # to handle events
i renamed your root-Window to make it more clear for you whats happening and removed the superflous (imho) additional Toplevel-window!
Also keep in mind, that you won't accomplish anything without the mainloop and the necessary event-handlers!
Simply put, this is not how Tkinter is designed to work. Tkinter was designed to have a single root window that is created once, and with a single eventloop that is running. Using it any other way is bound to lead to undesired behavior.
If you really need code to work this way, gather your input from your shell in one process, then use a separate process to display the tkinter window. You can either communicate from one the other using a socket, or you could pass the data from the parent to the child via arguments or environment variables or temporary files.
Every tkinter tutorial I have seen claims that tkinter.mainloop must be called for windows to be drawn and events to be processed, and they always call this function, even in hello world programs. However, when I try these out in the interactive shell, windows are drawn correctly without having to call mainloop. This example of embedding matplotlib graphics in tkinter produces a relatively complex application, with buttons for panning, zooming and resizing a plot within a tkinter window, and again, this all works if you remove the call to mainloop and run the code in the interactive shell. Of course, if I run the script (with mainloop removed) outside the interactive shell, the program ends too quickly to see what happens, but if I add a call to input to hold the program open everything works correctly (I'm running python 3.2.2 on linux).
So what exactly does mainloop do, and when is it necessary to call it?
EDIT:
To clarify, if I open up the GNOME terminal and type
$python3
>>> import tkinter
>>> root = tkinter.Tk()
a window immediately appears without having to call mainloop, and more complex tkinter functionality seems to work as well (for example, adding buttons to the window). In IDLE, a call to mainloop is necessary. It was my understanding that nothing should be drawn, and no events should be processed, until mainloop is called.
The answer to your main question is, you must call mainloop once and only once, when you are ready for your application to run.
mainloop is not much more than an infinite loop that looks roughly like this (those aren't the actual names of the methods, the names merely serve to illustrate the point):
while True:
event=wait_for_event()
event.process()
if main_window_has_been_destroyed():
break
In this context, "event" means both the user interactions (mouse clicks, key presses, etc) and requests from the toolkit or the OS/window manager to draw or redraw a widget. If that loop isn't running, the events don't get processed. If the events don't get processed, nothing will appear on the screen and your program will likely exit unless you have your own infinite loop running.
So, why don't you need to call this interactively? That's just a convenience, because otherwise it would be impossible to enter any commands once you call mainloop since mainloop runs until the main window is destroyed.
Compare a program with an interactive GUI to a program that calculates the hundredth Fibonacci number. All the latter program has to go through a series of steps in order, top to bottom. The set of steps and their sequencing can be known in advance, and it'll remain constant no matter how many times you run the program.
But the GUI program is different: at any given moment, it has to be able to handle all sorts of different kinds of events and interactions. This requirement is often implemented using a programming construct called an event loop. An event loop is the central control structure of a program. It waits for an event to happen, and then dispatches the appropriate handler.
You didn't mention which interactive shell you're using, but I'm guessing it's IDLE. IDLE itself is a Tkinter program, and it already has an event loop going. So possibly the Tkinter code you are typing into the shell is getting bound to IDLE's event loop.
When you execute your code, the tkinter window will refuse to open without there being a mainloop function.
For example this will not work:
from tkinter import*
root=Tk()
This, however, will work:
from tkinter import*
root=Tk()
root.mainloop()
If you’re using python interective shell, you don’t need to call the root.mainloop() function. But if you are coding in a file, suppose one in IDLE, you need to call out the mainloop() function in order for your program to work as follows:
from tkinter import *
root = Tk()
# Elements in the GUI must go here eg:
lbl = Label(root, text=“Text”)
lbl.pack()
# At the end of the program, do this:
root.mainloop()
As follows:
from tkinter import *
tk = Tk()
canvas = Canvas(tk, width=500, height=500)
canvas.pack()
canvas.create_line(0, 0, 500, 500)
mainloop()
I've decided that, instead of sticking a call directly to mainloop anywhere in my script, I'll just add it as part of atexit - that is, when the Python interpreter decides it's time to start closing down, it's going to enter Tk's mainloop. This then prevents it from finishing the shut down sequence until the user actually tells Tk to quit (IE, with command-Q on a Mac, or by clicking on the red X in Windows.)
from Tkinter import Tk
root = Tk()
import atexit
atexit.register(root.mainloop)
There seems to be no need to call mainloop from a system command line. The Python interpreter will continue running without it, because it's waiting for further input from you (until you run exit()).
I've created a very simple app, which presents an easygui entrybox() and continues to loop this indefinitely as it receives user input.
I can quit the program using the Cancel button as this returns None, but I would also like to be able to use the standard 'close' button to quit the program. (ie. top right of a Windows window, top left of a Mac window) This button currently does nothing.
Taking a look at the easygui module I found this line:
root.protocol('WM_DELETE_WINDOW', denyWindowManagerClose )
This would seem to be the culprit. I'm no TKinter expert but I could probably work out how to alter this handler to act the way I want.
However, as I'd rather not mess about with the easygui module, Is there a way to override this behavior from my main script, and have the close button either close the program outright or return None?
It would require altering the easygui module, yes. I will get it modified!
** I have sent in a e-mail to the EasyGUI creator explaning this [12:12 PM, January 23/09]
** I just want to say that the possibility of this change happening - if at all, which I doubt - is very tiny. You see, EasyGUI is intended to be a simple, discrete way to create GUIs. I think that this addition wouldn't help any, especially since the interface is very sequential, so it would be confusing to new users. [12:19 PM, January 23/09]
** The EasyGUI creator said this in reply to my e-mail:
An easygui dialog should never exit
the application -- it should pass back
a value to the caller and let the
caller decide what to do.
But this is an interesting idea.
Rather than simply ignoring a click on
the "close" icon, easygui boxes could
return the same value that a click on
the "cancel" button would return.
I'll meditate on this.
-- Steve Ferg
I think that this is progress at least. [2:40 PM, January 23/09]
I don't know right now, but have you tried something like this?:
root.protocol('WM_DELETE_WINDOW', self.quit)
or
root.protocol('WM_DELETE_WINDOW', self.destroy)
I haven't tried, but google something like "Tkinter protocol WM_DELETE_WINDOW"
I found a solution, the answer is below the choice box, when he defines some functions (you can just type to find denyWindowManagerClose) and go to where he defines it. Just erase it and put this code in its place.
def denyWindowManagerClose():
#------------------------------------------------------------------
# Changed by ProgrammingBR
# Enables the user to close the window without entering a value
# Youtube URL: https://www.youtube.com/channel/UCTZh6kWz_iYACNE6Jcy2lhw
#------------------------------------------------------------------
global __enterboxText
__enterboxText = None
boxRoot.quit()
You can create a backup file, but this will work for all boxes, the suggestions given here aside from this will not work, I tried the them. if you want to see I have a video on it (it is in Portuguese, but you can follow it) just go to the youtube channel, I will upload it soon and post the link here :)