wxPython not responding - python

I'm new to python and now I want to try wxpython, but I can't continue even at the very beginning.
Following the toturial,
import wx
app = wx.App(False)
frame = wx.Frame(None, wx.ID_ANY, "Hello World")
frame.Show(True)
after I did that, the new windows stops responding as soon as the it appears or I try to click it. Then I can only force close it and the editor restarts.
All the same on shell or IDLE, even all the same on different computers(I happened to bought a new one). Maybe I've done something wrong since I searched the internet and it seems no one encounters the problem, but I can't figure it out.
I'm using the latest python(x,y).
In addition, I tried tkinter also on my old computer and the problem is the same, if I remember rightly.

that's because the app loop is not running. usually, you also have to do:
app.MainLoop()
after frame.Show(). of course, now your console will be running the main loop, and you won't get your console back until after the app exits (well, when your main window closes), which probably isn't what you want either.
i haven't used python(x,y), but from a quick look, it looks like it supports IPython(x,y). If you use that as the console, then you can do
%gui wx
after loading, and then instead of creating/running the app yourself, IPython itself implements the app and does event processing in a special way as an input hook - which means that while it is waiting for you to type something, instead of just waiting, it actively polls the gui to see if there are active events and processes them if they are. This can create some interesting problems as well, but then you can just create the window & show it, and it will work correctly....

Related

Tkinter-based app keeps running in the background if the window is closed abruptly

I've created a tkinter app designed to let users create and take quizzes locally. Unfortunately, if a user closes the window by hitting the 'x' in the corner instead of hitting the "quit" button on the main menu, the window is destroyed but the process remains in the background. It isn't a huge deal as it stops using any CPU and only holds on to about 40mb of memory per instance, but this just seems pretty sloppy for an app that I'd like to deploy.
I have no idea what specifically is refusing to exit when the window is closed, and as it could be coming from almost anywhere in my 1700 lines of code, I'm instead looking for some more general tips for identifying what's still running or for killing any remaining processes when the window is closed. I'm happy to provide my code if anyone thinks it would help, though I reiterate that it's quite long given that I can't identify the source of the particular problem.
You can use state() from Tk to check if the window is open or not. When the window is open it should return 'normal' and if the window isn't open it will return something else.
What I would do is add something that checks the state of the window and exit the app when it's closed.
while app_is_running:
if root.state() != 'normal':
sys.exit(0)

Python - How to make a daemon out of GUI Application on Mac OS X?

On Windows it is easy. Just run your program with pythonw instead with python and code will be executed in the background.
So, the thing I wish to achieve is easily arranged.
I have an application which is really a service doing underground stuff. But this service needs a control panel.
So, on Windows I use wxPython to create a GUI, even some wx stuff to provide needed service, and when user is done with adjustments she/he clicks Hide and Show(False) is called on main window.
Thus the GUI disappears and the service continues its work in the background. User can always bring it back using a hotkey.
The trouble is that on Mac OS X this strategy works only to some degree.
When wx.Frame.Show(False) is called, the window disappears along with its menu bar and service works fine, but the Application is still visible there.
You can switch to it regardless the fact that you cannot do anything with it. It is still present in the Dock etc. etc.
This happens when program is using python or pythonw or when it is bundled with Py2App.
No matter what I do, the icon stays there.
There must be some trick that allows a programmer to remove this naughty icon and thus stop bothering poor little user when she/he doesn't want to be bothered.
Hiding window is obviously not enough. Anyone knows the trick?
N.B.: I would really like to do it the way I described above and not mess with two separate processes and IPC.
Edit:
After much digging I found these:
How to hide application icon from Mac OS X dock
http://codesorcery.net/2008/02/06/feature-requests-versus-the-right-way-to-do-it
How to hide the Dock icon
According to last link the proper way to do it is to use:
[NSApp setActivationPolicy: NSApplicationActivationPolicyAccessory];
or
[NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited];
So what I want (runtime switching from background to foreground and back) is possible.
But how to do it from Python???
Constants: NSApplicationActivationPolicyProhibited and NSApplicationActivationPolicyAccessory are present in AppKit, but I cannot find setApplicationActivationPolicy function anywhere.
NSApp() doesn't have it.
I know there is a way of doing it by loading objc dylib with ctypes, delegating to NSApp and sending "setApplicationActivationPolicy: <constant_value>", but I don't know how much will this mess with wx.App(). And it is a bit much work for something that should be available already.
In my experience, NSApp() and wx.App() active at the same time dislike eachother pretty much.
Perhaps we can get the NSApp() instance that wx is using somehow and use wx's delegate???
Remember please, already suggested solutions with starting as agent and switching to foreground or running multiple processes and doing IPC is very undesirable in my case.
So, ideally, using setApplicationActivationPolicy is my goal, but how? (Simple and easy and no messup to wx.App() please.)
Any ideas???
OK people, there is a good, nice and correct solution without any messing around.
Firstly, I want to explain why Windows GUI process goes to background when wx.Frame.Show(MyFrame, False) is called.
Very short explanation and skipping over details is that Windows consider the Window and an application the same thing.
I.e. The main element of the MS Windows application is your main GUI window.
So, when this window is hidden, an application has no more GUI and continues to run in background.
Mac OS X considers the application to be your application and any windows you choose to put into it are its children so to speak.
This allows you to have an application running while presenting no windows but a menu bar, from which you may choose an action which would then generate a needed window.
Very handy for editors where you may have more than one file opened at once, each in its own window and when you close the last one, you can still open a new one or create a blank one, etc. etc.
Therefore a main element of Mac OS X application is the application itself, and that is why it stays opened after last window is hidden, logically. Destroying its menu bar also will not help. The name of the app will stay present in Dock and in application switcher and in Force Quit. You will be able to switch to it and do nothing. :D
But, luckily, Mac provides us with function to put it to background though. And this function is already mentioned setApplicationActivationPolicy() from NSApp object.
The trouble was its naming in Python's AppKit, which is NSApp.setActivationPolicy_(). To complicate matters further, it is not available directly from Python's interactive shell but it has to be called at least from an imported module.
Why? I have no idea. Anyway here is a complete example for throwing an application into background that will work on Mac and Windows.
I didn't try it on Linux, which combines behaviour of Mac and Windows in matter of presenting an app, so, whether only hiding a window would be enough remains to be seen.
Feel free to try and submit an edit to make the example more cross-platform.
Example:
"""
This app will show you small window with the randomly generated code that will confirm that reopened window is still the same app returned from background,
and the button allowing you to send it to background.
After you send it to background, wait 8 seconds and application will return to foreground again.
Too prove that the application is continuing its work in the background, the app will call wx.Bell() every second.
You should hear the sound while app is in the foreground and when it is in background too.
Merry Christmas and a happy New Year!
"""
import wx
import random, sys
if sys.platform=="darwin":
from AppKit import NSBundle, NSApp, NSAutoreleasePool, NSApplicationActivationPolicyRegular, NSApplicationActivationPolicyProhibited
# Use Info.plist values to know whether our process started as daemon
# Also, change this dict in case anyone is later checking it (e.g. some module)
# Note: Changing this dict doesn't change Info.plist file
info = NSBundle.mainBundle().infoDictionary()
def SendToBackground ():
# Change info, just in case someone checks it later
info["LSUIElement"] = "1"
NSApp.setActivationPolicy_(NSApplicationActivationPolicyProhibited)
def ReturnToForeground ():
# Change info, just in case someone checks it later
info["LSUIElement"] = "0"
NSApp.setActivationPolicy_(NSApplicationActivationPolicyRegular)
else:
# Simulate Mac OS X App - Info.plist
info = {"LSUIElement": "0"} # Assume non background at startup
# If programmer chose not to display GUI at startup then she/he should change this before calling ReturnToForeground()
# To preserve consistency and allow correct IsDaemon() answer
def SendToBackground ():
info["LSUIElement"] = "1"
def ReturnToForeground ():
info["LSUIElement"] = "0"
def IsDaemon ():
return info["LSUIElement"]=="1"
class Interface (wx.Frame):
def __init__ (self):
wx.Frame.__init__(self, None, -1, "Test", pos=(100, 100), size=(100, 100))
wx.StaticText(self, -1, "Test code: "+str(random.randint(1000, 10000)), pos=(10, 10), size=(80, 20))
b = wx.Button(self, -1, "DAEMONIZE ME", size=(80, 20), pos=(10, 50))
wx.EVT_BUTTON(self, b.GetId(), self.OnDaemonize)
self.belltimer = wx.Timer(self)
wx.EVT_TIMER(self, self.belltimer.GetId(), self.OnBellTimer)
self.belltimer.Start(1000)
# On Mac OS X, you wouldn't be able to quit the app without the menu bar:
if sys.platform=="darwin":
self.SetMenuBar(wx.MenuBar())
self.Show()
def OnBellTimer (self, e):
wx.Bell()
def OnDaemonize (self, e):
self.Show(False)
SendToBackground()
self.timer = wx.Timer(self)
wx.EVT_TIMER(self, self.timer.GetId(), self.OnExorcize)
self.timer.Start(8000)
def OnExorcize (self, e):
self.timer.Stop()
ReturnToForeground()
self.Show()
self.Raise()
app = wx.App()
i = Interface()
app.MainLoop()
Of course, this example may be started from terminal or with CLI window. In this case the terminal control over your program will stay opened while app only will appear and disappear.
To complete your GUI daemon, you should start it with pythonw (on Windows) or launch it from daemontest.pyw file,
and on Mac you should use:
% nohup python daemontest.py &
or bundle it with py2app or use Python launcher that comes with python.org Python version to start daemontest.py without terminal.
Note: This example suffers from the same flaw on Mac OS X that is mentioned on links I supplied in my question. I refer to the problem of wrong focusing and menu bar not instantly appearing when app comes from background. User has to switch around and come back to newly returned app for it to work properly. I hope somebody will solve this too. And soon. It is quite annoying.
One more note: If you have threads running in your program, pause them while daemonizing and exorcizing. Especially if they are communicating with another app using Apple events. To be frank, something about wx.Timers should be done too. If you are not careful you may get leaking problems around non-existing NSAutoreleasePool and/or SegmentationFault upon program termination.
Ok. Here is the code to do what you want to do:
import AppKit
info = AppKit.NSBundle.mainBundle().infoDictionary()
info["LSUIElement"] = "1"
This the messier answer you do not want to do, but I will list it anyway. In the info.plist file add in this key:
<key>LSUIElement</key>
<string>1</string>
Another more daemonish solution but means it can't have a GUI, you add in this key to the info.plist file:
<key>LSBackgroundOnly</key>
<string>1</string>
Source

PyQt QWidget window closes immediately upon showing?

I realize that this question has been asking several times before, though none of them seem to apply to my situation. I have installed PyQt, and am simply trying to open up a window as such:
import sys
from PyQt4 import QtGui as qt
segmentation = qt.QApplication(sys.argv)
main = qt.QWidget()
main.show()
All the other questions I have looked at on here usually were caused by an error with the window going out of scope because of the window's show method being called from within a function, or something similar.
My code uses no functions at all so this cannot be the issue. This should work as it is, no? I am following this tutorial:
https://www.youtube.com/watch?v=JBME1ZyHiP8
and at time 8:58, the instructor has pretty much exactly what I have written, and their window shows up and stays around just fine. Mine displays for a fraction of a second and then closes.
Screen shot of the code block from the video to compare to the code block provided here:
Without seeing all of your code, I'm assuming that you're missing the sys.exit() bit.
For your specific code sys.exit(segmentation.exec_()) would be what you needed.
segmentation = qt.QApplication(sys.argv)
main = qt.QWidget()
main.show()
sys.exit(segmentation.exec_())
A little bit of detail of what's going on here.
segmentation = qt.QApplication(sys.argv) creates the actual application.
main = qt.QWidget() and main.show() creates the Widget and then displays.
When executing the python script, this does exactly what you tell it to:
Create an application
Create a widget
Show the widget
Finished. End of the script.
What the sys.exit() does is cleanly closes the python script. segmentation.exec_() starts the event driven background processing of QT. Once the segementation.exec_() is finished (user closes the application, your software closes the application, or a bug is encountered) it'll return a value which is then passed into the sys.exit() function which in turn terminates the python process.

PyGObject (Glade) Window Never Showing (Multithreaded)

I've been fighting for three hours now to get this process multithreaded, so that I can display a progress box. I finally got it working, insomuch as the process completes as expected, and all the functions call, including the ones to update the progress indicator on the window.
However, the window never actually displays. This is a PyGObject interface designed in Glade. I am not having fun.
def runCompile(obj):
compileWindow = builder.get_object("compilingWindow")
compileWindow.show_all()
pool = ThreadPool(processes=1)
async_result = pool.apply_async(compileStrings, ())
output = async_result.get()
#output = compileStrings() #THIS IS OLD
compileWindow.hide()
return output
As I mentioned, everything works well, except for the fact that the window doesn't appear. Even if I eliminate the compileWindow.hide() command, the window never shows until the process is done. In fact, the whole stupid program freezes until the process is done.
I'm at the end of my rope. Help?
(By the way, the "recommended" processes of using generators doesn't work, as I HAVE to have a return from the "long process".)
I'm not a pyGobject expert and i don't really understand your code. I think that you should post more. Why are you calling the builder in a function? you can call it at the init of the GUI?
Anyways.. It seems that you are having the common multithread problems..
are you using at the startup GObject.threads_init() and Gdk.threads_init() ?
Then, if you want to show a window from a thread you need to use Gdk.threads_enter() and Gdk.threads_leave().
here is an useful doc
I changed the overall flow of my project, so that may affect it. However, it is imperative that Gtk be given a chance to go through its own main loop, by way of...
if Gtk.events_pending():
Gtk.main_iteration()
In this instance, I only want to call it once, to ensure the program doesn't hang.
(The entire program source code can be found on SourceForge. The function in question is on line 372 as of this posting, in function compileModel().

NSEvent global event monitoring in background

I am writing a simple Mac application designed to run in the background and perform certain actions whenever the user clicks the mouse button. The app is written in Python using PyObjC. I am using addGlobalMonitorForEventsMatchingMask to watch for NSLeftMouseDown events:
NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(NSLeftMouseDownMask, handler)
This code works perfectly when running in the terminal. However, when I bundle it as a standalone app (using py2app) and then launch it, the app doesn't receive any events at first. (Or at least, if it does, it doesn't run the code in my handler method.) Only when I click on the app in the Dock does it start receiving events, and after that, it continues to receive events even after it returns to the background. But it doesn't receive anything until activated once.
My question is: How can I get my app to start receiving events as soon as it is launched, without having to be activated first by clicking the Dock icon? Is this some known quirk of NSEvents, or is there perhaps something wrong with my run loop in PyObjC?
Any help or guidance is greatly appreciated!
Edit: Upon further testing, it seems that, in fact, my app spontaneously starts receiving notifications about ten seconds after launch, regardless of whether I activate it. Which is slightly annoying, but fine.
However, if I run the app with either LSUIElement = true or LSBackgroundOnly = true in my Info.plist (which I ultimately want to do, since this app should only run in the background and never appear in the Dock), I never receive notifications. So I am still stuck.
As you said "Only when I click on the app in the Dock does it start receiving events" , that means the handler gets registered after you click on the app in the Dock.
So it depends on at which point in the code you are calling this : NSEvent.addGlobalMonitorForEventsMatchingMask_handler_(NSLeftMouseDownMask, handler) ,
that is registering the handler.
You should register the handler in appdidfinishlaunching function.

Categories