Discussion:
[Tutor] How to close a Tkinter window from a different thread?
boB Stepp
2015-04-20 03:34:43 UTC
Permalink
I am not certain that my terminology is correct in the subject line.
Let me explain my issue.

Scenario A:
1) I start out inside a commercial software environment (Abbreviated
CSA henceforth).
2) I initiate a script in the CSA's scripting language.
3) This script calls an external Python script.com
4) This Python script generates a Tkinter window, populating it with
information from the CSA.
5) Control will not pass back to the CSA until the Tkinter window is
closed. Because of this, none of the CSA's tools can be used until the
Tkinter window is closed.

Scenario B:
1) I start out inside the CSA.
2) I initiate a script in the CSA's scripting language.
3) This script calls an external Python script in a new thread.
4) This Python script generates a Tkinter window, populating it with
information from the CSA.
5) Control returns to the CSA while the Tkinter window is populating
itself. The CSA's tools can be used while the Tkinter window remains
open displaying its information.

My users want scenario B to occur. This way they can refer to the
Tkinter window's info and make changes to their plan based on this
info. However! Once they make their changes they will want to rerun
the same Python script. This would then result in TWO Tkinter windows
being open, one displaying the old info, the new one with the
post-changes info. This is not acceptable.

So, how do I:
1) Check for the existence of an already open window from a previous
running of the script?
2) If such a window exists, how do I close it from the new script
execution? And, then, of course generate a new instance of the
information window.

I need to be able to identify the existence of such a window without
causing anything to happen to the CSA's normally open windows. And
then close the particular window I need closed -- IF it is even open.
I feel the solution must be in Tkinter's access to the X Window
system, but nothing in the documentation is *clicking* with me yet.

Thanks!
--
boB
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Alan Gauld
2015-04-20 07:10:38 UTC
Permalink
Post by boB Stepp
1) Check for the existence of an already open window from a previous
running of the script?
2) If such a window exists, how do I close it from the new script
execution? And, then, of course generate a new instance of the
information window.
I would suggest forgetting about windows and think about
the processes that create them. Use the OS tools (via
the os module) to see if the first process is still running.
If so kill the process - which will in turn kill the window.

You can find the process based on its name or based on
its PID which you could store in a file somewhere
(like in /tmp?)
Post by boB Stepp
I feel the solution must be in Tkinter's access to the X Window
system, but nothing in the documentation is *clicking* with me yet.
Trying to manipulate GUIs via the windowing system should always
be a last resort, it is very hard to get right.
--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
boB Stepp
2015-04-20 12:45:50 UTC
Permalink
Post by Alan Gauld
Post by boB Stepp
1) Check for the existence of an already open window from a previous
running of the script?
2) If such a window exists, how do I close it from the new script
execution? And, then, of course generate a new instance of the
information window.
I would suggest forgetting about windows and think about
the processes that create them. Use the OS tools (via
the os module) to see if the first process is still running.
If so kill the process - which will in turn kill the window.
I started poking around a little in this area in my books, but did not
know if this was the way to go or not. I was still hung up on how to
identify the correct process...
Post by Alan Gauld
You can find the process based on its name or based on
its PID which you could store in a file somewhere
(like in /tmp?)
I was thinking in these terms from a Tkinter window id perspective,
but storing the PID while the original window is known to be open
looks like the way to go. Thanks, Alan! I may have more questions on
this later as I have not explicitly worked with this via Python. I've
only killed processes via the command line before.
Post by Alan Gauld
Post by boB Stepp
I feel the solution must be in Tkinter's access to the X Window
system, but nothing in the documentation is *clicking* with me yet.
Trying to manipulate GUIs via the windowing system should always
be a last resort, it is very hard to get right.
If I am learning nothing else from my exploration of GUI programming,
this is becoming ever more evident!
--
boB
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Laura Creighton
2015-04-20 09:40:33 UTC
Permalink
Post by Alan Gauld
Trying to manipulate GUIs via the windowing system should always
be a last resort, it is very hard to get right.
And the hardness increases exponentially if you want to be portable
across different operating systems.

Laura

_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
boB Stepp
2015-04-21 02:34:39 UTC
Permalink
Post by Alan Gauld
Post by boB Stepp
1) Check for the existence of an already open window from a previous
running of the script?
2) If such a window exists, how do I close it from the new script
execution? And, then, of course generate a new instance of the
information window.
I would suggest forgetting about windows and think about
the processes that create them. Use the OS tools (via
the os module) to see if the first process is still running.
If so kill the process - which will in turn kill the window.
You can find the process based on its name or based on
its PID which you could store in a file somewhere
(like in /tmp?)
I'm currently at home and cannot access Solaris, but I believe that
the following will do what I want:

import os
import signal
from tkinter import *

def kill():
os.kill(pid, signal.SIGKILL)

root = Tk()
pid = os.getpid()

btn = Button(root, text='Kill me!!!', command=kill)
btn.pack()
root.mainloop()

The process id would have to be stored persistently to do the real
deal, of course, as Alan suggested. I cannot make this example work in
Windows. As far as I can tell, signal.SIGKILL won't work with Windows.
If I replace it with 9, then it does work. If I have understood what I
have read to date, using signal.SIGKILL is preferable to using 9.

Some questions:

1) Is the placement of "pid = os.getpid()" critical? My thinking is
that I want to capture the pid of the root window, store it, and then
use it if I need to kill the root and any children it has in my actual
GUI display. If, say, I placed it immediately before
"root.mainloop()", would it do what I want? Of course, I plan to
experiment with this at work tomorrow. I'll also continue to play
around with it in Windows.

2) The other possibility was to use "os.getppid" and, I suppose,
"os.kill(ppid, signal.SIGKILL)". Would this be preferable? Or will
wreak some sort of havoc?

Thanks!
boB
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
boB Stepp
2015-05-27 21:42:49 UTC
Permalink
Python 2.4.4, Solaris 10

I realize that this is a bit old, but I got severely sidetracked! ~(:>)
Post by Alan Gauld
I would suggest forgetting about windows and think about
the processes that create them. Use the OS tools (via
the os module) to see if the first process is still running.
If so kill the process - which will in turn kill the window.
Is this a reasonable way to determine if a given pid is still active?
I found this at:

http://stackoverflow.com/questions/568271/how-to-check-if-there-exists-a-process-with-a-given-pid

import os

def check_pid(pid):
""" Check For the existence of a unix pid. """
try:
os.kill(pid, 0)
except OSError:
return False
else:
return True

I realize that this will also return True if I don't have permissions
to kill, or some such.
Post by Alan Gauld
You can find the process based on its name or based on
its PID which you could store in a file somewhere
(like in /tmp?)
I can implement this, but thinking about this anew has led to a
concern. Hypothetically, if I check for the existence of a running
process based on this stored pid, what is the likelihood that the pid
will be reassigned to something other than one of my program's windows
left open?
--
boB
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Cameron Simpson
2015-05-27 23:03:52 UTC
Permalink
Post by boB Stepp
Python 2.4.4, Solaris 10
I realize that this is a bit old, but I got severely sidetracked! ~(:>)
[...]
Post by boB Stepp
Post by Alan Gauld
I would suggest forgetting about windows and think about
the processes that create them. Use the OS tools (via
the os module) to see if the first process is still running.
If so kill the process - which will in turn kill the window.
Is this a reasonable way to determine if a given pid is still active?
http://stackoverflow.com/questions/568271/how-to-check-if-there-exists-a-process-with-a-given-pid
import os
""" Check For the existence of a unix pid. """
os.kill(pid, 0)
return False
return True
I realize that this will also return True if I don't have permissions
to kill, or some such.
Yes it is reasonable and normal. However the clean way to do it involves an
extra test:

try:
os.kill(pid, 0)
except except OSError as e:
if e.errno == errno.EPERM:
return True
return False
else:
return True

Do bear in mind that process ids repeat. So on a busy system (or if your own
program is very long lived and the original process exited a long time ago) you
might be polling that pid as used by something unrelated.

However, if you started the process directly and it has not been wait()ed for,
then the pid will not be available for reuse and you will be ok.
Post by boB Stepp
Post by Alan Gauld
You can find the process based on its name or based on
its PID which you could store in a file somewhere
(like in /tmp?)
I can implement this, but thinking about this anew has led to a
concern. Hypothetically, if I check for the existence of a running
process based on this stored pid, what is the likelihood that the pid
will be reassigned to something other than one of my program's windows
left open?
As discussed above. Possible but unlikely. And if you are the creator of the
original process you can control the situation.

Cheers,
Cameron Simpson <***@zip.com.au>

Processes are like potatoes. - NCR device driver manual
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Steven D'Aprano
2015-04-24 13:41:56 UTC
Permalink
Coming in late to this conversation...
Post by boB Stepp
1) I start out inside the CSA.
2) I initiate a script in the CSA's scripting language.
3) This script calls an external Python script in a new thread.
4) This Python script generates a Tkinter window, populating it with
information from the CSA.
5) Control returns to the CSA while the Tkinter window is populating
itself. The CSA's tools can be used while the Tkinter window remains
open displaying its information.
I think one way of doing this is by making the Python script a daemon
that runs in the background. That at least will solve the problem from
Scenario A that the CSA becomes unresponsive while the Tkinter window is
open: as far as the CSA is concerned, the process it launched has ended.

Three follow-up problems then occur:

- Can daemons run as graphical applications?

- Once the daemon is running, how does the CSA communicate with it?

- How do we make sure that the daemon closes down safely when the
CSA quits?


I don't know the answers to these.

Ben Finney maintains a Python daemon library. If Ben is around, he may
be able to shed some further light onto this question, and answer
whether a daemon is suitable. Perhaps even give some sample code.
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
boB Stepp
2015-04-24 17:23:19 UTC
Permalink
Post by Steven D'Aprano
Post by boB Stepp
1) I start out inside the CSA.
2) I initiate a script in the CSA's scripting language.
3) This script calls an external Python script in a new thread.
4) This Python script generates a Tkinter window, populating it with
information from the CSA.
5) Control returns to the CSA while the Tkinter window is populating
itself. The CSA's tools can be used while the Tkinter window remains
open displaying its information.
I think one way of doing this is by making the Python script a daemon
that runs in the background. That at least will solve the problem from
Scenario A that the CSA becomes unresponsive while the Tkinter window is
open: as far as the CSA is concerned, the process it launched has ended.
This part sounds promising.
Post by Steven D'Aprano
- Can daemons run as graphical applications?
- Once the daemon is running, how does the CSA communicate with it?
I'd be extremely interested if this is possible! My biggest struggles
are exchanging information between the CSA and other programs external
to it. And it is much harder going in one direction than the other.
Liberal use of temp files seems to be the most reliable means of
exchanging information, though some exploitation of the CSA's global
variables is possible, though this is usually a last ditch effort when
nothing else seems to work.
Post by Steven D'Aprano
- How do we make sure that the daemon closes down safely when the
CSA quits?
I don't know the answers to these.
Ben Finney maintains a Python daemon library. If Ben is around, he may
be able to shed some further light onto this question, and answer
whether a daemon is suitable. Perhaps even give some sample code.
I'll keep my fingers crossed!
--
boB
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Loading...