PyGTK, Glade, Changing the window view and threads - python

Forgive me if this seems like a stupid question, just so far no where on the internet can I find someone offering a solution to this and I just wanted to get some feedback from someone with more experience than myself (I've only been using python, pyGTK and Glade for 2 days now).
I have a UI window displaying and it updates with messages from a thread that is handling a bluetooth connection.
This is fine and I have the application closing and running quite reliably, the problem is, after a bluetooth connection is made I wish to maintain the bluetooth thread (i.e. keep the connection going) but completely change the UI of the main window.
Now the impression I am getting from pyGTK applications made from glade, is that the easiest thing to do is just open a new window. Is this really the best option? Can I cut the tree of widgets off at the root, maintaining the window widget but add on a new set of widgets from a separate glade file?
If opening a new window is the best option, am I right in assuming that the bluetooth thread can be kept alive during this transition, providing I update any callbacks?
Any help or pointers would be great.
Cheers,
Matt

If i well understand the connection is strictly coupled with the window. This seems like a good example of aggregation and composition. Simple decouple the window from the connection. Without code or more information is impossible to be more accurate. After this you can use both the solution you proposed: create a new window with a reference of the connection thread or "detach" the whole widgets tree and attach a brand new one, simple use gtk.Container.remove and gtk.Container.add (gtk.Window derive from gtk.Container).
If this is not enough modify your questions and add some info and code.

I think you already know, but GTK (PyGtk) is thread aware and not thread safe, so, modifying the UI from another thread that is not the one that holds gtk's main loop will probably make your program to crash.
You can make use of the .glade files several times, you can use just one widget (and its children) if you want and ignore everything else, that's why gtk.glade.XML accepts a root parameter. This root is where your widget tree will start.
gladeobject = gtk.glade.XML(path_to_glade_file, root='widgetname')
You can safely hide the windows and keep it updated, and avoid the "new window" solution.

Related

Progress Bar over getOpenFileName

In my application I have the following line which opens a file dialog window. Once I get the file name, I do a bunch of processing which takes quite some time, and once this is done the workspace is ready for the user.
filename, _ = QtGui.QFileDialog.getOpenFileName(self, 'Open file', os.curdir, "*.cws")
The file dialog is a modal window (by default), which is great, because it's preventing the user from doing stupid stuff while the workspace is not ready for use yet. I want to put a progress bar somewhere to give a sense of how much has be processed. I made another dialog window which displays a progress bar and some other information.
Now, since the file dialog window is modal, it just sits there frozen while my workspace is processing, and the progress dialog only pops up after everything is done.
I've looked into setting the file dialog window to not modal, but I don't think that is possible. I was thinking to maybe force it to close, and immediately have my progress dialog window pop up and take over the modality. How can I close the file dialog window programmatically? I don't know how to get a reference for the form.
Or perhaps you have a better suggestion on how to address this?
As thuga mentioned, your application event loop is stuck by your heavy processing.
So events (and especialy paint events) are not processed while your processing is running causing the GUI to freeze.
In my opinion, you have 2 options:
Force events to be processesed (not very classy but may work):
It depends on how your "heavy processing" is done.
Assuming the code hanging the loop is "under your hands" (not in a third party lib).
You can add as much call to QApplication.processEvents as you can in it.
If the processing is loop based, it can look like:
for item in itemList:
...processitem...
QtGui.QApplication.processEvents()
This as the main drawback of adding dependencies to GUI in parts of code that should not be aware of.
If your code is not loop based then you'll have to add several calls to processEvents that will pollute the processing code.
Stop hanging the event loop (more complicated but more maintainable)
That means you will have to deal with Threads and/or subprocesses as thuga suggested.
This solution assumes that GUI code and business code are separated well enough.
You can have a look at this article from Qt Quarterly that gives some highlights on this issue.
Because of python Global Interpreter Lock (GIL) you may not see better results with threads.
Consider using the multiprocessing library.

Writing an active program with wxPython. Where to start?

I spent the last hours trying to get to know wxPython, because I want to write a GUI program. I found some tutorials on that (not too many), but all of them just explain how to add yet another kind of widget, down to fancy things like LED number outputs and mouse gestures (this one e.g. takes it quite far: Another Tutorial). But everything I could find so far does nothing more than create a static GUI, waiting for the user to do something, then execute some handlers and wait again. It took me a while to even find out that wx.App takes a part in all of that, and that you can subclass it.
I want to write a program, that does things without input! The GUI is supposed to be a client that logs in on a server, and when the server sends something, I want the GUI to show what happened. I could not find a single tutorial even mentioning, that such programs exist. How can I write such a thing? How do they integrate with wxpython?
Do I need to span another thread? Is there a way to hook into the MainLoop and have some code executed periodically, that checks for change and then updates some of those fancy GUI things? And is there any page that teaches you, how to do this?
First of all, you should figure out how to do what you want WITHOUT a GUI. In this case, you'll need to figure out how to login to a server. You'll probably need to use something like paramiko for that. See http://www.lag.net/paramiko/
Once you've got that figured out, then you can add it to your GUI. Probably in a button handler so when the user presses a button, it pops up a dialog asking for a user name and password to pass to paramiko to login to the server.
If the server query takes a long time to execute (like say you're querying a database for a huge set of data), then you'll want to run the query in a separate thread. Why? Because that query will block the GUI's main loop and make your app freeze until it finishes. See the following articles for information on wxPython and threads:
http://wiki.wxpython.org/LongRunningTasks
http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
I wrote up a tutorial on making wxPython talk to a socket server, so you might find that useful: http://www.blog.pythonlibrary.org/2013/06/27/wxpython-how-to-communicate-with-your-gui-via-sockets/
I also have an article on how to make an image viewer, and do CRUD ops to a database on there.

Obscure, repeatable crashes in multi-threaded Python console application using tk

Using tk in my multi-threaded(*) console application causes it to crash without stacktrace, giving the message "Tcl_WaitForEvent: Notifier not initialized Abort trap".
The symptoms were that all my program's functions worked fine, until I brought up the tk window - then the very next operation would cause the crash.
Immediate searching found that Tkinter is not safe with respect to Python threads, so I made sure that I was not calling any Tk functions anywhere other than my main thread. The crashes continued.
I lost several hours because I believed that it was the specific command I was using that crashed the program - but eventually I realized that any keyboard input would crash the program.
After a lot of debugging, I finally boiled it down to a small program that demonstrates the issue, exposing what I believe is a bug or certainly a feature that needs documentation in the Tkinter library.
I was working on this posting I was debugging. I'm going to post it and answer my own question in the hopes that it will prevent the next person from wasting a day on it.
--
(* - Yes, it certainly needs to be multi-threaded. I have a thread for my socket connection, a thread that listens to a mic and finds levels, a thread to drive my serial port and more. In each case, the thing I'm reading on the thread naturally blocks most of the time.)
The solution!
The issue is that tk crashes if you read from Python's raw_input in a different thread from the tk thread!
A small program demonstrating the issue is here. If you run it, it gets keyboard input perfectly happily from the second thread - until you enter the command "tk" when it brings up an empty tk window. You can do whatever you like with that window - until you type in the console window and press return, when the whole program crashes.
Why am I reading from raw_input in a thread that isn't the main thread?
My program is a console application, but I'm controlling a lot of different parts, one of which is the pi3d OpenGL ES 2.0 graphics library which must be updated at or near the frame rate from the main Python thread.
How to work around it?
"Simple" enough - register for tk menu events and just get the keys directly! Except that's a crappy solution, because you have to emulate all those things that the console does for you already - deleting, left and right arrows and that sort of thing. But that's what I'll have to do.
Should the program become a fully-fledged tk application?
But I can't do that - the whole point of this program is that you can run it through a terminal window - often sshing into headless machines. I'm frankly more likely to make it a curses program!
The tk window is a minor part of the whole thing - just a window to show emulated lights when developing if you don't have the hardware hooked up (or don't want to keep flashing yourself in the face). I won't try to bring it up on headless machines, and that's fine.
Is this a bug?
I'm always loathe to attach such a label to software not my own, but I'm hard-pressed to come up with any other description. It causes a crash, and that crash produces no useful information of any type. I consider that Tkinter is somewhat lame for simply crashing when called from different threads, but at least this behavior is documented (if you dig down a little) - in this case, I'm calling a Python built-in, so I have no basis to expect that it will interact with this library at all, and there's no documentation of this problem.
Could there be a workaround?
I'm sort of hoping there will be a work-around - this one-page program was a single item on a long list of features has turned into a full-day head-scratching debugging session and I don't want to have to throw another day at least after this when none of this time is actually producing new features.
The best thing is if the tk team admitted this was a bug and came up with a fix. But I wouldn't expect that at my desktop before a year from now...
So perhaps the real best thing would be if there were some way to get tk to simply ignore the keyboard, and not crash. I did a tiny experiment with tk's "busy" but that didn't work and just doesn't seem to be the right sort of thing.
A little later, I'm now thinking about running the lighting as an independent program, a separate subprocess using Python's Subprocess library, and sending it text commands through stdin. This would be overkill if this were the only problem that was being solved, but in fact
Got it.
Replacing raw_input() with sys.stdin.readline() did the trick - at least in the demo (which I updated). Feel free to download this and experiment with it yourself!
I hope this saves someone else the time.
In my case (as mentioned in the comments under #Tom Swirly's answer) the solution was to switch to a non-interactive backend:
import matplotlib
matplotlib.use('Agg')

How do I detect when the contents of an X11 window have changed?

I'm trying to write an Xvfb-to-HTML5-canvas tool that will need to know when an X11 window changes so it can send a screen update to the client. Think of it like a web-based VNC or RDP but just for X11 windows (why send the whole desktop? =).
I thought there would be a straightforward way to do this via Xlib or xcb (xpyb) but in my experiments the best I've been able to do is detect when a window is created, destroyed, or moved. That's great and all but I need to know when the contents of windows change as well (imagine sending a keystroke to an xterm and having it appear frozen until you move the window).
If someone knows of a way to tell when the contents of an X11 window have changed I'd love to hear it! I'm open to creative solutions. For example, I tried using ffmpeg to stream x11grab through a fifo with regular checks to see if anything changed but it turned out to be extremely inefficient in terms of CPU utilization (it also seems to slow the whole system down even if nothing is going on).
I also tried just grabbing 15fps worth of screenshots in a loop while checking for changes in the most efficient way I could (e.g. does this cStringIO buffer match the last one?). That also was very CPU intensive.
The ideal solution would be for me to be able to watch the file descriptor of a socket and call a handler when there's a change in the X11 window. I'm willing to settle for detecting when the whole X11 screen has a change... That'd still be better than what I've got.
Any and all help with this is appreciated!
First of all, you can actually use vnc to track changes in just one window, not whole desktop. From x11vnc documentation:
-id windowid Show the X window corresponding to "windowid" not
the entire display. New windows like popup menus,
transient toplevels, etc, may not be seen or may be
clipped. Disabling SaveUnders or BackingStore in the
X server may help show them. x11vnc may crash if the
window is initially partially obscured, changes size,
is iconified, etc. Some steps are taken to avoid this
and the -xrandr mechanism is used to track resizes. Use
xwininfo(1) to get the window id, or use "-id pick"
to have x11vnc run xwininfo(1) for you and extract
the id. The -id option is useful for exporting very
simple applications (e.g. the current view on a webcam).
-sid windowid As -id, but instead of using the window directly it
shifts a root view to it: this shows SaveUnders menus,
etc, although they will be clipped if they extend beyond
the window.
-appshare Simple application sharing based on the -id/-sid
mechanism. Every new toplevel window that the
application creates induces a new viewer window via
a reverse connection. The -id/-sid and -connect
options are required. Run 'x11vnc -appshare -help'
for more info.
If you want to code similar functionality manually you need to use damage extension.
Here is simple example in javascript using node-x11 (sorry, I'm not sure about damage extension support in python)
var x11 = require('x11');
var X = x11.createClient(function(err, display) {
X.require('damage', function(Damage) {
var damage = X.AllocID();
Damage.Create(damage, parseInt(process.argv[2]), Damage.ReportLevel.NonEmpty);
X.on('event', function(ev) {
Damage.Subtract(damage, 0, 0);
console.log("window content changed!");
});
});
});
start it with window id as command line argument and you'll be notified whenever window content is changed.

Using external GUI libraries to make user interfaces in Autodesk Maya

I develop tools in Autodesk Maya. Many of the tools I build have simple windowed GUIs for the animators and modellers to use. These GUIs often contain what you'd normally expect to see in any basic window; labels, lists, menus, buttons, textfields, etc. However, there are limitations to the complexity of the UIs you can build with the available tools, specifically in the types of available widgets.
I'm interested in using some of the more advanced wxPython widgets such as the ListView (grid), Tree, etc. This would involve using a complete wxFrame (window) to display the whole UI, which would essentially mean that window would no longer be tied to Maya. Not a deal breaker, but it means when Maya is minimized, the window won't follow suit.
I've tried something like this before with tkinter as a test, but found that it needed a MainLoop to run in its own thread. This is logical, but in my case, it conflicts with Maya's own thread, essentially making Maya hang until the window is closed. This is due to the fact that Maya runs all scripts, be they MEL or Python, in a single thread that the main Maya GUI shares. This is to prevent one script from, say, deleting an object while another script is trying to do work on the same object.
wxPython has this same "mainloop" methodolgy. I'm wondering if there's any way around it so that it can work within Maya?
I'm not sure if this is germane, but some googling turns up that PyQt is pretty popular inside of Maya. You could try the technique here or here (explained here with source code) of creating a new threadloop via Maya and executing inside of that. It seems Maya has a module included that sets up a new thread object, with a QApplication inside it:
def initializePumpThread():
global pumpedThread
global app
if pumpedThread == None:
app = QtGui.QApplication(sys.argv)
pumpedThread = threading.Thread(target = pumpQt, args = ())
pumpedThread.start()
and then sets up a function to process the Qt events:
def pumpQt():
global app
def processor():
app.processEvents()
while 1:
time.sleep(0.01)
utils.executeDeferred( processor )
You can probably do something similar with wxPython as well. (utils.executeDeferred is a Maya function.) Be sure to check out how to create a non-blocking GUI on the wxPython wiki. Instead of processEvents(), you'll want to set up an event loop and check for "Pending" events inside the (hopefully renamed?) pumpQt function above. (The wxPython source has a Python implementation of MainLoop.) Likely this should be done through the app.Yield() function, but I'm not sure.
def pumpWx():
global app
def processor():
app.Yield(True)
while 1:
time.sleep(0.01)
utils.executeDeferred( processor )
def initializePumpThread():
global pumpedThread
global app
if pumpedThread == None:
app = wx.App(False)
pumpedThread = threading.Thread(target = pumpWx, args = ())
pumpedThread.start()
The wxPython docs indicate SafeYield() is preferred. Again, this seems like it could be a first step, but I'm not sure it will work and not just crash horribly. (There's some discussion about what you want to do on the wxPython mailing list but it's from a few minor versions of wx ago.) There is also some indication in various forums that this technique causes problems with keyboard input. You might also try doing:
def processor():
while app.Pending(): app.Dispatch()
to deal with the current list of events.
Good luck!
I don't know if there is a way around a mainloop for the gui, since it is needed to handle all event chains and redraw queues.
But there are several means of inter-process communication, like pipes or semaphores. Maybe it is an option to split your Maya extension into the actual plugin, being tight into maya, and a separate application for the gui. These two could use such means to communicate and exchange model information between plugin and gui.
I'm not sure, however, if I can really recommend this approach because it very much complicates the application.
You could have a look at IPython, an interactive Python shell, whose dev team has put some effort into integrating it with wxPython. They have some way of interrupting the event loop and hooking into it to do their own stuff.
The best way to go is creating a QWidget with what you need, and using it from within a MPxCommand thru the C++ API. That way you also have the chance to inject complete custom editors into Maya via scriptedPanels.
But if you're bound to Python, pyQt is the way to go.

Categories