Strategy for managing long GUI construction times (wxPython) - python

I have a wxPython application with a multi-stage GUI. First a simple form pops for selecting from one of many (> 100) options (it's a part number list with a search box). Once the user has made their selection it builds the appropriate form and shows it, hiding the initial selection dialog. Due to the nature of this project, each secondary form has several matplotlib figures in a Notebook, around 7 or 8 figures each with 2-5 axes each. Because of this, the form takes several seconds between initialization and when it can be shown on the screen.
Does wxPython have a way to build a frame in the background? I don't mind forcing the user to wait a short while before it can be shown, but as it is right now building the form hogs the event loop and everything becomes unresponsive. If I use a thread to build the form, it completes successfully but when I call .Show() nothing happens and there's no error message.
As you can imagine, such a GUI has fairly complex code so it would be difficult to show a SSCCE (and it's not open source). If needed I can try to hack together something that would approximate my problem.

I have used BusyInfo before to tell the user that something is happening. You would put that in your frame's init() BEFORE you actually start creating the matplotlib figures. You can read about it here:
http://wiki.wxpython.org/BusyInfo
Another idea would be to create a second frame with a progressbar in it and a message. The progressbar would be set to just bounce back and forth and when you got done creating the matplot stuff, you would close the second frame.

Mike's idea of using wxBusyInfo is useful when something takes a long time, but it's possible you could make it take less time instead (or at least as well).
First, when inserting many (although I wouldn't say that 100 is that many, 1000 however definitely is) items into a wxChoice, freeze it before adding them -- and thaw it afterwards. This should cut down the time needed for the insertion drastically.
Second, creating all controls of a multi-page wxNotebook (or another wxBookCtrl) can be long, even in C++. So the idea is to not do it immediately but only create the controls of the page you are going to initially show to the user. And then create the other pages controls only when the user is about to select them, i.e. in your wxEVT_BOOKCTRL_PAGE_CHANGING event handler.
If you put this in place, you might not need wxBusyInfo any longer...

Related

In PyQt5, if you have multiple checkboxes how to direct to function if not a specific one but any is checked?

I have a program I'm developing using PyQt5 where I have 6 QComboBoxes to make selections from, and then based on these selections you can narrow down the data further. For clarity, it looks like this:
Image of Program
If something is in the "weakness" category I want the user to have the option to remove it from the final selection process in case the initial results are too narrow.
Here's where the problem is:
The final calculation is based on what checkboxes are checked. To make sure this is as reflected in the GUI I do the following things whenever a combobox is changed:
Changed the QStackedWidgets to the "deactivated" label
Determine strengths and weaknesses based on type data from comboboxes
Unchecked all the checkboxes and mark the appropriate ones as checked.
Code for this is below:
#deactivate all stacks
for t in range(0,18):
str_type0 = self.value[t].lower()[0:3]
str_stack0 = 'self.str_'+str(str_type0)
eval(str_stack0).setCurrentIndex(0)
weak_type0 = self.value[t].lower()[0:3]
weak_stack0 = 'self.weak_'+str(weak_type0)
eval(weak_stack0).setCurrentIndex(0)
#strong loop
for t in range(0,len(self.r)):
str_type = self.value[self.r[t]].lower()[0:3]
str_stack = 'self.str_'+str(str_type)
eval(str_stack).setCurrentIndex(1)
#weak loop
for t in range(0,len(self.q)):
weak_type = self.value[self.q[t]].lower()[0:3]
weak_stack = 'self.weak_'+str(weak_type)
eval(weak_stack).setCurrentIndex(1)
#set all checkboxes as checked if currently shown in stack
for t in range(0,18):
checkstr0= self.value[t].lower()[0:3]
checkstr1='self.weak_'+str(checkstr0)+'_act'
eval(checkstr1).setChecked(False)
weak_stack1 = 'self.weak_'+str(checkstr0)
weak_stack1 = eval(weak_stack1)
if weak_stack1.currentIndex() == 1:
eval(checkstr1).setChecked(True)
else: continue
This is fine and works even if it's a little clunky (goal is tomake it work and then make it work efficiently later). The issue is that changing a checkbox is what triggers the function that does all the calculating for the results, but since multiple checkboxes change at the same time, or even just changing one, triggers this function a multiplicity of times. It's a huge waste of computation.
I've thought of some solutions. I think perhaps the best way to solve this problem is to run the function not when any particular checkbox changes but there is a change. Something like:
if any (checkbox.checkState()==changed): do something.
I'm not sure if that would be a good solution, or how to even do that.
Any ideas are appreciated. Thanks in advance!
Figured out the answer while I continued to think about the problem. The problem was that it signaled every time it changed, which is a horrible amount while the program configured itself.
The obvious yet simple solution was to change the checkboxes from:
checkbox.stateChanged.connect(function)
to
checkbox.pressed.connect(function)
This way the checkbox signal will only go forth when I physically press on it in the program. Hopefully this will be able to help anyone else out there who runs into the same issue in the future.

Python : How to deal with threads priority in Gtk3

I am building an user interface using Python, Gtk3 and Glade. I want to change several things on the UI at the same time (i.e start an animation and display a new text) which leads to the application freezing.
I have read that Gtk wasn't thread safe so I didn't used the Thread module.
Instead, I used Glib.idle_add and Gdk.threads_add_idle functions. I am tryig to update a treeview, display some text and show an animated logo at the same time. The application works but it freezes a few seconds and then everything appears at the same time. I try to set different priorities to the threads but it does'nt seem to fix it.
Gtk.threads_add_idle(Glib.PRIORITY_DEFAULT, label.set_text, "text_to_set")
Gtk.threads_add_igle(GLib.PRIORITY_DEFAULT, function_to_display_logo)
I expect the different texts and the treeview and the logo to be displayed without any freeze. Does anyone know how I can fix that ?
Please have a look here at a script example in https://github.com/f4iteightiz/UWR_scoreboard : a GTK window is updated all 0,2s for example (countdowns of several timers appearing in labels; I think anything else could be updated) and it stay reactiv the whole time. No freezing noticeable.
I found out what my error was. I was using the GLib.idle_add function too many times even in some cases where I had no use for it.
For example in the main code I had :
Glib.idle_add(my_function,buffer)
but my_function looked like this :
def myfuntion(buffer):
GLib.idle_add(buffer.set_text,"text")
I deleted the GLib.idle_add call in the main code and now it works perfectly.

How can a wxpython frame "steal" and "return" focus similar to the Dash app?

I want to make a heads-up display that pops up it's frame, taking focus from the previous application and then gives focus back to that application when it's done.
wxPython frames have Hide and Show methods that work but don't focus the application. Also, there's SetFocus which you'd think would do it but doesn't.
Update
I found a nasty hack that works. Rather than hide and show the frame, you save the app state and close the app instead of hiding. Then when you want to show again you spark a new one in a new multiprocessing.Process. Hardly ideal though. I hope someone has something better.
Clarification
To clarify, I'm trying to get the keyboard focus, not just to get the frame on top of the stack.
This issue might be specific to OS X.
You might be able to steal focus by calling Raise on the frame. There is the wx.STAY_ON_TOP style flag that could also be applied. Then you might be able to just use the frame's Show and Hide methods to make it work.
Depending on what exactly you want to do, you might take a look at the ToasterBox widget. I can't recall if it actually steals focus, but it just pop up and go away on its own, which is handy in some cases.

Force update GUI in kivy

I am writing an app in kivy which does cpu-heavy calculations at launch. I want the app to display what it's doing at the moment along with the progress, however, since the main loop is not reached yet, it just displays empty white screen until it finishes working. Can I force kivy to update the interface?
Basically I'm looking for kivy's equivalent of Tkinter's root.update()
I could create a workaround by defining a series of functions with each calling the next one through Clock.schedule_once(nextFunction, 1), but that would be very sloppy.
Thanks in advance.
Leaving aside the question of whether you should be using threading or something instead (which possibly you should), the answer is just that you should move your cpu calculations to somewhere else. Display something simple initially (i.e. returning a simple widget from your build method), then do the calculations after that, such as by clock scheduling them.
Your calculations will still block the gui in this case. You can work around this by doing them in a thread or by manually breaking them up into small pieces that can be sequentially scheduled.
It might be possible to update the gui by manually calling something like Clock.tick(), but I'm not sure if this will work right, and even if so it won't be able to display graphics before they have been initialised.

Excessive hang time when destroying a PyGTK window

My PyGTK application creates a secondary popup window for displaying a preview of results. This window is fairly elaborate, with Table widgets nested three deep and populated by HBoxes containing one Label each at the lowest level. The number of Labels total can be in the thousands. I am noticing that when I close this window, GTK becomes extremely busy processing something (functions added with gobject.idle_add don't resolve for >10 seconds) and the main window of my application becomes unresponsive in this time. Even with this many widgets, it seems strange to me that the window should take so long to close, longer even than it takes to set up and display. Is there any way to mitigate this? (I tried creating and showing the window in another thread, but apparently with GTK this is a no-no)
How long takes that window to show up? Are all the widgets created at once when it is displayed?
Your problem might be caused by the destruction of your thousands of widgets, all at the same time. Or by a lengthy action perform on on of those widgets destruction. But without some code to look at, there could be thousands of reasons, so a ptomato says, use a profiler...
Apparently it was being caused by my attempt to change the background color of the tables--I was setting the background color of every HBox (and Label), which was responsible for nearly all of the excessive teardown time. All I had to do was set the background color of the Viewports the Tables are contained in.

Categories

Resources