wxPython - Showing logo while importing - python

I am running a wxPython application that does a lot of modules and packages importing at the beginning and gathering information about the computer (network interfaces, internet connection..) so it takes time, and I'm showing a logo in that time until it ends. the problem is that the logo crashes if you press on it (because the importing are on the MainThread and the GUI can't respond to events), How can I show a logo while importing without letting the GUI crash? (I don't want to let the user to click on the Logo anyway)

Inspired by Tim Roberts in this wxPython-users thread I first tried to spin off the splash screen in a separate thread, which did not work (wxwidgets complains it it not in the main thread). So I did the only obvious thing which I should have done in the first place: make the long running at startup a separate thread.
Side effect: As the splash screens now can react to events, it will disappear when clicked on.
import wx
class long_running(object):
def __init__(self):
bitmap = wx.EmptyBitmap(300, 150, 127)
self.mainframe = wx.Frame(None, -1, 'mainframe')
self.splash = wx.SplashScreen(bitmap, wx.SPLASH_TIMEOUT, 20000, self.mainframe)
def start(self):
import time
# mimicking something taking very long time on startup
for i in range(20):
time.sleep(0.5)
print i
wx.CallAfter(self.continue_)
def continue_(self):
#Destroy the splash screen.
if self.splash:
self.splash.Hide()
# self.splash.Destroy()
self.mainframe.Show()
if __name__ == '__main__':
import thread
app = wx.App()
long_rnn = long_running()
# Begin loading the application.
thread.start_new_thread(long_rnn.start, ())
# Application loaded.
app.MainLoop()

In a recent project (on Windows7 and wxPython 2.9.5.1): For displaying a wx.SplashScreen while modules are importing we did the following:
We have a main module, which does import wx in the beginning, create the wx.App and display the splash screen. Only after showing the splash screen we begin to import the "heavy" modules. The very first startup will take 40 seconds. In fact the app will crash if the user clicks on the splash screen. Better said, Windows displays a message box (EDIT2) with "Python.exe has stopped working." If the user clicks "Terminate" the app will in fact terminate/crash. If the user does nothing, the app will start up normally. So on Windows there is no "real" crash. It will also not happen when starting the second time (because things are cached)? On subsequent starts startup time is 5 seconds. Sorry, no real answer but too long for a comment also.
EDIT: Minimum working example added: Click every one or two seconds on the splash while it is displayed to make Windows show the "Python has stopped working" dialog. The dialog will simply go away when long_running() has returned.
# -*- coding: utf-8 -*-
def long_running():
import time
time.sleep(10)
# does not show "Python ... stopped working ..."
#for _ in range(20):
# time.sleep(0.5)
# wx.Yield()
if __name__ == '__main__':
import wx
app = wx.App()
bitmap = wx.EmptyBitmap(300, 150, 127)
splash = wx.SplashScreen(bitmap, wx.SPLASH_TIMEOUT, 20000, None)
# Begin loading the application.
long_running()
# Application loaded.
#Destroy the splash screen.
splash.Hide()
splash.Destroy()
app.MainLoop()

Related

time .sleep() taking place at incorrect order in commands; always at the beginning of the function

The code below is a stripped down version (for clarity reasons) of a small application I am working on; an application for spelling words for children.
The problem
The problem I am having is in the function flash_correct(); its purpose is to show a word for 5 seconds, then hide again.
I must have a silly blind spot, but no matter where I put the time.sleep(5), the function starts with the break of 5 seconds, while the entry: self.entry2 never shows up:
Without the time.sleep(5) however, it shows up correctly:
Where is my blind spot?
The (stripped down) code:
#!/usr/bin/env python3
from gi.repository import Gtk, Pango, Gdk
import subprocess
import time
class InterFace(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Woorden raden")
maingrid = Gtk.Grid()
self.add(maingrid)
maingrid.set_border_width(10)
self.entry2 = Gtk.Entry()
self.entry2.set_size_request(500,60)
self.entry2.set_child_visible(False)
self.entry2.modify_font(Pango.FontDescription('Ubuntu 30'))
maingrid.attach(self.entry2, 0, 4, 4, 1)
quitbutton = Gtk.Button("Stop", use_underline=True)
quitbutton.modify_font(Pango.FontDescription('Ubuntu 20'))
quitbutton.connect("clicked", self.on_close_clicked)
maingrid.attach(quitbutton, 3, 7, 1, 1)
showword_button = Gtk.Button("↺", use_underline=True)
showword_button.modify_font(Pango.FontDescription('Ubuntu 25'))
showword_button.connect("clicked", self.flash_correct)
showword_button.set_size_request(60,20)
maingrid.attach(showword_button, 0, 6, 1, 1)
def flash_correct(self, button):
# the time.sleep(5) seems to take place at the beginning
# no matter in which order I set the commands
self.entry2.set_text("Monkey")
self.entry2.set_child_visible(True)
time.sleep(5)
self.entry2.set_child_visible(False)
def on_close_clicked(self, button):
Gtk.main_quit()
window = InterFace()
window.connect("delete-event", Gtk.main_quit)
window.set_default_size(330, 330)
window.set_resizable(False)
window.show_all()
Gtk.main()
You can use time.time to hide for roughly 5 seconds calling Gtk.main_iteration() in the loop to avoid your app becoming unresponsive.
def hide(self, time_lapse):
start = time.time()
end = start + time_lapse
while end > time.time():
Gtk.main_iteration()
def flash_correct(self, button):
# the time.sleep(5) seems to take place at the beginning
# no matter in which order I set the commands
self.entry2.set_text("Monkey")
self.entry2.set_child_visible(True)
self.hide(5)
self.entry2.set_child_visible(False)
There is a good explanation in the pygtk faq 7. How can I force updates to the application windows during a long callback or other internal operation?
If you have a long-running callback or internal operation that tries to modify the application windows incrementally during its execution, you will notice that this doesn't happen; the windows of your app freeze for the duration.
This is by design: all gtk events (including window refreshing and updates) are handled in the mainloop, and while your application or callback code is running the mainloop can't handle window update events. Therefore nothing will happen in the application windows.
The trick here is to realize where your operation can take a while to return, or where it is dynamically changing the window contents, and add a code fragment like this wherever you want an update forced out:
while gtk.events_pending():
gtk.main_iteration(False)
This tells gtk to process any window events that have been left pending. If your handler has a long loop, for instance, inserting this snippet as part of the loop will avoid it hanging the window till the callback has finished.
More eloquently, in the words of the great Malcolm Tredinnick, 'this requires using what should be called "Secret Technique #1 For Making Your Application Look Responsive"(tm):
Adding while gtk.events_pending(): may be no harm also.
It would be better to use a timer that integrates with the main loop, rather than busy-waiting until the time has elapsed. Luckily there is just such a facility in GLib:
def flash_correct(self, button):
self.entry2.set_text("Monkey")
self.entry2.set_child_visible(True)
GLib.timeout_add_seconds(5, self.flash_end)
def flash_end(self):
self.entry2.set_child_visible(False)
return GLib.SOURCE_REMOVE

install module snapshot python

I am using wxPython to build the GUI for my application. I built the GUI using wxFormBuilder. But when bring the code into my python application, and launch it the window pops up then closes instantly. I am using the XRC for my GUI as well. I am given no error message in the console either while using PyDev with Eclipse.
Python code to launch GUI: http://pastebin.com/jBYWerd9
XRC code: http://pastebin.com/QVEcuX0i
I think you just need
def main():
app = VisualController(redirect=False)
app.MainLoop() #you need this
return #after calling Mainloop you will not get here until your main window is destroyed
The problem is two-fold. As Joran mentioned, you need to actually create an instance of your App class and call the MainLoop() method. The second piece is that you need to actually load the frame from the XRC file and Show it. Change your code to something like this:
import wx
from wx import xrc
class VisualController(wx.App):
def OnInit(self):
self.res = xrc.XmlResource('data/GUI.xrc')
frame = self.res.LoadFrame(None, "MyFrame1")
frame.Show()
return True
def main():
app = VisualController(redirect=False)
app.MainLoop()
if __name__ == '__main__':
main()
If you don't load the frame and show it, then the app doesn't do anything and just exits when it finishes running the OnInit() method. Here are a few links on using XRC:
http://www.blog.pythonlibrary.org/2010/05/11/wxpython-an-introduction-to-xrc/
http://wiki.wxpython.org/XRCTutorial
http://wiki.wxpython.org/UsingXmlResources

Different behaviour between python console and python script

I am experiencing different behaviour on the same code using the python console and a python script.
The code is as follows:
import gtk
import webkit
win = gtk.Window()
win.show()
web = webkit.WebView()
win.add(web)
web.show()
web.open("http://www.google.com")
When running the code in the python console, the output is a new frame that contains the google main page.
When running the code as a script, the result is a void frame. It closes very fast but even if I use a delay function, the webkit is not added to the frame.
How is it possible?
Furthermore, using PyDev IDE it flags: "unresolved import: gtk",
but if i run the project, the program starts without problem of compilation. is it normal?
Add
gtk.main()
to the end of your script. This starts the gtk event loop.
import gtk
import webkit
class App(object):
def __init__(self):
win = gtk.Window()
win.connect("destroy", self.destroy)
web = webkit.WebView()
web.open("http://www.google.com")
win.add(web)
web.show()
win.show()
def destroy(self, widget, data = None):
gtk.main_quit()
app = App()
gtk.main()
My guess is that the console keeps the python session open, while at the end of the script the program closes. When the script closes, it takes everything it created with it.
Something to test this theory: if you type "exit" in the console do you see the interface shut down in the same manner? If so, think of some code (e.g. a pause like a raw_input) that will allow the script to stay open.
Good luck!

Python console prints output differently than sypder console

I have a python code that takes measurements off of a HP LCR Meter and collects the data for us in various ways. I recently created a GUI for imputing initial conditions for employees not comfortable modifying variables in the code. Everything works except for 1 thing. WE use the latest python xy so python version 2.6.6 with pyqt and spyder on a windows 7 PC.
Normally we would open the code in spyder. But opening spyder takes a while and my supervisor liked the ability to just double click on the file which opens the GUI with a python console window to print errors and various information as you would see in spyder.
As can be seen in the screen shots provided, there is a initial machine setup mode for setting up the device to be scanned by the LCR Meter and there are two user inputs that the code prompts. On spyder it prints these prompts nicely in the console but in the python console opened without spyder it continuously prints QCoreApplication::exec: The event loop is already running Weird thing is you can still just push enter twice as normal and the code will run like normal. But its going to be confusing to basically everyone but me.
Does anyone know why this would be happening?
Here are the pictures of the output
Here is the code that prompts the input.
lcr = visa.instrument('GPIB::17')
#clear the instrument
lcr.write('*RST;*CLS')
#enable operation complete notification
lcr.write('*OPC')
if parallel:
lcr.write('FUNC:IMP CPG') #Parallel capacitance, conductance model
else:
lcr.write('FUNC:IMP CSRS') #Series capacitance, resistance model
lcr.write('APER '+integration+','+averages)
lcr.write('OUTP:HPOW ON')
lcr.write('OUTP:DC:ISOL OFF')
lcr.write('VOLT '+vac)
lcr.write('TRIG:SOUR BUS')
if zero == True:
#set open correction parameters
lcr.write('DISP:PAGE CSET')
lcr.write('CORR:LENG 1')
lcr.write('CORR:METH SING')
lcr.write('CORR:LOAD CPG')
lcr.write('CORR:USE 10')
lcr.write('CORR:SPOT1:STATE ON')
lcr.write('CORR:SPOT2:STATE OFF')
lcr.write('CORR:SPOT3:STATE OFF')
lcr.write('CORR:SPOT1:FREQ '+frequency)
#perform open correction -> unprobe device\
raw_input('Unprobe DUT and press ENTER to continue...')
lcr.write('CORR:SPOT1:OPEN')
lcr.write('CORR:OPEN:STATE ON')
lcr.write('DISP:PAGE MEAS')
#poll lcr to determine measurment state
lcr.write('*OPC?')
done = lcr.read()
while done == 0:
lcr.write('*OPC?')
done = lcr.read()
time.sleep(0.5)
#reprobe device
raw_input('Probe DUT, then press ENTER')
lcr.write('FREQ '+frequency)
The Prompts are the two raw_input().
Reason why you get continuous messages in your console, is that system logs use same output-stream than your app.
Spyder is nice program, which just embeds IPython or Python(backup) console in QT window, you can use similar solution - just use Qt4 to draw window, which includes IPython console
What you need to do is this(source):
def embed_ipython(window):
"wrapper funcs - works < IPython 0.11"
from IPython.Shell import IPShellEmbed
ipshell = IPShellEmbed(user_ns = dict(w = window))
ipshell()
Here ‘window’ is a central object of some kind that you want to expose to IPython (to manipulate, test various methods, etc).
GUI app initialization would be like this:
if __name__ == "__main__":
import sys
from PyQt4 import QtGui
app = QtGui.QApplication(sys.argv)
window = QtGui.QMainWindow()
window.show()
embed_ipython(window)
sys.exit(app.exec_())
Some additional readings:
QT4 tutorial: http://zetcode.com/tutorials/pyqt4/firstprograms/
Similar topic - how to embed python console: How to embed a Python interpreter in a PyQT widget
IPython and QT console: http://ipython.org/ipython-doc/dev/interactive/qtconsole.html

Interacting with a gtk.container while gtk.main() is executing?

Experimenting with a battery monitor icon at the moment in Python using pygtk and egg.trayicon to create an icon to display a battery icon/tooltip.
I seem to be able to add the icon and the tooltip text, but when it then reaches the gtk.main() stage I need a way to modify these so it can then show the updated values.
I've tried gobject.idle_add() and gobject.timeout_add() without much luck, not sure where to go from this.
Anyone got any ideas?
EDIT: Perhaps not the clearest of questions.
I need to loop, fetching information from acpi while running and apply it to widgets inside the gtk container.
EDIT 2: Ok, it's properly down now. The issue was that I wasn't returning anything inside my callback. I just gave it "return 123" and now it's happily chugging away in my system tray, notifying me of my battery percentage :)
This example works for me:
# -*- Mode: Python -*-
# vi:si:et:sw=4:sts=4:ts=4
import gobject
import gtk
from egg import trayicon
label = gtk.Label("Over here")
def callback(widget, ev):
label.set_text("You found me")
def timeout():
label.set_text("What are you waiting for?")
tray = trayicon.TrayIcon("TrayIcon")
box = gtk.EventBox()
box.add(label)
tray.add(box)
tray.show_all()
box.connect("button-press-event", callback)
gobject.timeout_add(3000L, timeout)
gtk.main()
Without seeing your code, it's hard to tell what doesn't work.

Categories