pySDL2 Display without End Loop - python

In every pySLD2 example I've found, I've seen a loop at the end of the code to keep the window open until closure. For example:
#!/usr/bin/env python
"""
The code is placed into public domain
by anatoly techtonik <techtonik#gmail.com>
"""
import sdl2
import sdl2.ext as lib
lib.init()
window = lib.Window('', size=(300, 100))
window.show()
renderer = lib.Renderer(window)
renderer.draw_point([10,10], lib.Color(255,255,255))
renderer.present()
####Specifically this loop####
running = True
while running:
for e in lib.get_events():
if e.type == sdl2.SDL_QUIT:
running = False
break
if e.type == sdl2.SDL_KEYDOWN:
if e.key.keysym.sym == sdl2.SDLK_ESCAPE:
running = False
break
All event handlers I've seen have been blocking. Is there a way, like I have seen done in standard SDL, to simply call initialization and updating functions on a window that stays open. I am writing to write this as an external library that I can call independently from any project.
Any ideas? Thanks!
EDIT: As per request for a way to do this in standard SDL, this works. Just call the init function to set up the screen and it will stay until you close it.

You are misinterpreting the example - this is an additional hook (screen.c) to be set up in the main loop.
SDL uses the main loop approach to deal with events, update the window display, etc. Yes, there is a way to work around that. Create your very own window and use whatever approach to keep it open, get the window handle via the SDL_SysWM* functions and update the window's display buffer.
This however involves some glue code and also requires you to do the window handling on your own.

Related

Why in tkinter you don't have to write init?

When I'm using Pygame, a python library, I have to write "pygame.init" to initiate all modules. However, when I'm using Tkinter, another library, I don't have to use "tkinter.init". Why?
Thanks!
When I'm using Pygame, a python library, I have to write "pygame.init()" to initiate all modules. However, when I'm using Tkinter, another library, I don't have to use "tkinter.init()". Why?
Each Python library comes with its own way of using it and own mechanisms implemented for event handling if the library provides methods for interacting with the user.
How to use the library is then explained in the documentation or can be inferred from the documentation coming along with each library method and printed on demand.
So the right answer to the question why you have to use the library this and not other way is as simple as maybe surprising:
Because the library requires to use it this and not other way.
By the way:
in Tkinter (newer versions of the module are named tkinter) the initialization is silently done within an initialization method __init__ of the class Tk when creating the root window with root = tkinter.Tk() and for the tkinter window coming up you need in addition to this initialization tkinter.mainloop().
Here a minimal tkinter code required to open a window (see comments for details/explanations):
import tkinter
root = tkinter.Tk()
tkinter.mainloop()
# ^-- requires root = tkinter.Tk() else:
# ^-- RuntimeError: Too early to run the main loop: no default root window
in pygame it is not necessary to call pygame.init() to open a pygame window.
Here a minimal pygame code required to open a window, keep it opened and responding (see comments for details/explanations):
import pygame
# pygame.init()
# ^-- is NOT required
screen = pygame.display.set_mode((640,480))
# ^-- REQUIRED else: pygame.error: video system not initialized
# ^-- creates the pygame window which stays opened (but not responding)
# ^-- as long as the Python script runs
# v--REQUIRED to keep the pygame window opened and responding:
running = True
while running:
# Check for exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

PySDL2: Creating a borderless window

I've been trying to find how I might create a borderless window (One not created using the typical windows border) in PySDL2.
I've looked at what resources I could find online, but haven't been able to pinpoint anything that would tell me how to accomplish this, despite it being apparently possible.
Research:
This link states that in most cases you have a border and title bar around your window, but never went into any more detail as to how to manipulate it.
I looked at some API references for SDL's Window, and did not see that borders could be manipulated at all. (Not stated that they couldn't be, just no mention)
Despite not finding anything PySDL2 related, I did find at this link that:
sdl.setWindowBordered(window, bordered)
Sets the border state of a window.
Unfortunately, I'm unable to get this to work within my simple example script.
Thanks for looking!
You need to make sure you have the flag: SDL_WINDOW_BORDERLESS.
Full example:
import sys
import sdl2.ext
sdl2.ext.init()
window = sdl2.ext.Window("Hello World!", size=(640, 480), flags=sdl2.SDL_WINDOW_BORDERLESS)
window.show()
processor = sdl2.ext.TestEventProcessor()
processor.run(window)
Modifying your script slightly we get:
import sys
import sdl2.ext
def run():
sdl2.ext.init()
W = sdl2.ext.Window("Default",size=(400,300), flags=sdl2.SDL_WINDOW_BORDERLESS)
W.show()
running = True
while running:
events = sdl2.ext.get_events()
for event in events:
if event.type == sdl2.SDL_QUIT:
running = False
break
W.refresh()
return 0
if __name__ == "__main__":
sys.exit(run())

handling things outside of main loop in PyQt4

We're building a hardware thing based on RaspberryPi and using PyQt4 to handle output on a small 3" screen.
Apart from screen we have a simple hardware keypad that needs handling in a loop to check for keys pressed and act accordingly.
To simplify things code right now looks something like this:
while True:
gui_initialized = False
current_screen = None
if gui_initialized is False:
app = QtGui.QApplication(sys.argv)
main_win = gui.GUI()
gui_initialized = True
sys.exit(app.exec_())
key_code = kp.getKey()
This code is wrong because of the PyQt4 main loop. Once execution gets to the line sys.exit(app.exec_()) - it stops in there forever and never gets to key_code = kp.getKey(). But I need key_code = kp.getKey() to execute somewhere within the loop to handle keypad and also will need to do other background work.
In fact usual Qt event handling is not really applicable in our case because we'll have no standard input tools, only a custom keypad and NFC antenna, both handled within main python program.
So the question is - how do I handle additional work I need to do along with PyQt4 main loop?
The idiomatic way of doing polling in Qt is to put your polling code in a slot, and connect to it a timeout signal from a QTimer with a zero timeout.

Exit from infinite loop after gtk window closes

I'm creating a program that keeps checking for change in a MySQL database, and according updates a GTK display. The part that keeps checking is in an infinite loop.
What I want is that once the GTK window has been closed, I can break out of the infinite loop.
But I don't know what condition to use for that. I've tried
if !window:
and
if window == None:
but in either case, it doesn't work.
The structure of my code is like this:
while True:
# my code
while gtk.events_pending():
gtk.main_iteration()
# something to exit here
window.connect("destroy", gtk.main_quit())
I don't know if placing "window.connect" there can cause a problem, because the window seems to close just fine. Also, if I placed it within the loop, or before the loop, I'd get a Runtime Error: called outside of mainloop.
So to re-iterate, how do I exit the infinite loop using the closure of the window as a condition? I don't want the user to have to use Ctrl + C.
Thanks in advance!
This is a classical background thread problem.
You need to have a loop like this:
closing = False
while not closing:
// do the MySQL stuff
And then connect a signal handler to window destroy event that sets closing to True
The basic structure of a pygtk app is usually something like this:
win = gtk.MyWindow()
win.connect("destroy", gtk.main_quit) # Note no paretheses after main_quit.
gobject.timeout_add(1000, win.check_DB)
win.show_all()
gtk.main()
The gobject.timeout_add command will call the win.check_DB method every 1000 milliseconds.
In win.connect("destroy", gtk.main_quit) it is important not to put parentheses after main_quit. You are passing the function object gtk.main_quit to the win.connect method, not the return value of having called gtk.main_quit(), which is what would happen if you add the parentheses.
Since gtk.main_quit() quits the app, using parentheses here halts the program too early.

wxPython won't close Frame with a parent who is a window handle

I have a program in Python that gets a window handle via COM from another program (think of the Python program as an addin) I set this window to be the main Python frame's parent so that if the other program minimizes, the python frame will too. The problem is when I go to exit, and try to close or destroy the main frame, the frame.close never completes it's execution (although it does disappear) and the other program refuses to close unless killed with TaskManager.
Here are roughly the steps we take:
if we are started directly, launch other program
if not, we are called from the other program, do nothing
enter main function:
create new wx.App
set other program as frame parent:
Get handle via COM
create a parent using wx.Window_FromHWND
create new frame with handle as parent
show frame
enter main loop
App.onexit:
close frame
frame = None
handle as parent = None
handle = None
Anybody have any thoughts on this or experience with this sort of thing?
I appreciate any help with this!
[Edit]
This is only the case when I use the handle as a parent, if I just get the handle and close the python program, the other program closes fine
I wonder if your Close call may be hanging in the close-handler. Have you tried calling Destroy instead? If that doesn't help, then the only solution would seem to be "reparenting" or "detaching" your frame -- I don't see a way to do that in wx, but maybe you could drop down to win32 API for that one task...?
If reparenting is all you need, you can try frame.Reparent(None) before frame.Close()
My resolution to this is a little bit hacked, and admittedly not the most elegant solution that I've ever come up with - but it works rather effectively...
Basically my steps are to start a thread that polls to see whether the window handle is existent or not. While it's still existent, do nothing. If it no longer exists, kill the python application, allowing the handle (and main application) to be released.
class CheckingThread(threading.Thread):
'''
This class runs a check on Parent Window to see if it still is running
If Parent Window closes, this class kills the Python Window application in memory
'''
def run(self):
'''
Checks Parent Window in 5 seconds intervals to make sure it is still alive.
If not alive, exit application
'''
self.needKill = False
while not self.needKill:
if self.handle is not None:
if not win32gui.IsWindow(self.handle):
os._exit(0)
break
time.sleep(5)
def Kill(self):
'''
Call from Python Window main application that causes application to exit
'''
self.needKill = True
def SetHandle(self, handle):
'''
Sets Handle so thread can check if handle exists.
This must be called before thread is started.
'''
self.handle = handle
Again, it feels a little hackish, but I don't really see another way around it. If anybody else has better resolutions, please post.

Categories