Pygame set_caption not working [python3, Ubuntu] [duplicate] - python-3.x

I am trying to change the name of a pygame window from "Pygame Window" to "test caption".
I have tried:
pygame.display.set_caption('test caption')
But I don't think it is the right script.

Refer to http://www.pygame.org/docs/ref/display.html#pygame.display.set_caption:
set_caption(title, icontitle=None) -> None
If the display has a window title, this function will change the name
on the window. Some systems support an alternate shorter title to be
used for minimized displays.
Your usage was correct, so there must be another issue. Either your window is initialized incorrectly, or it isn't even initialized at all. Contributing your code would be helpful.

Call it after init().
pygame.init()
pygame.display.set_caption('test caption')

Just call the set_caption() function again.
pygame.display.set_caption('original caption')
while myGameRunning:
pygame.display.set_caption('new caption')

pygame.display.set_caption():
If the display has a window title, this function will change the name on the window. [...]
However, PyGame is based on SDL and the behavior is system-dependent. Call set_caption() after initializing the display window with pygame.display.set_mode(). In addition, the events may need to be handled after changing the window title. See pygame.event.pump():
internally process pygame event handlers. [...] This ensures your program can internally interact with the rest of the operating system.
window = pygame.display.set_mode((width, height))
pygame.display.set_caption('window caption')
pygame.event.pump()
In a common application, you have an application loop and an event loop. This makes the additional call to pygame.event.pump() superfluous, since the events are continuously handled in the application loop:
window = pygame.display.set_mode((width, height))
pygame.display.set_caption('window caption')
# [...]
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# [...]

Related

Run OpenGL window besides Tkinter window

I am trying to open :
on one hand, an OpenGL window, using glfw
on the other hand, a GUI window, using tkinter
However, both are run with a blocking call for them to render:
glfw: while not glfw.window_should_close(window): ...
Tkinter: self.ui_root.mainloop()
Would you know a way to circumvent that, and to allow to have both windows open at the same time, accepting Keyboard/Mouse events?
If you want to run the tkinter window on a keyboard event, you have to write a callback function to do this. Suppose, if you press "T" then the tkinter window will be showed up. According to your question it will run self.ui_root.mainloop(). Here, the basic structure of your code will be this:
#callback function
def key_input_callback(window, key, scancode, action, mode):
if key == glfw.KEY_T and action == glfw.PRESS:
self.ui_root.mainloop()
#display loop
while not glfw.window_should_close(window):
....
....
glfw.set_key_callback(self.window, key_input_callback)
....
....
Here, the callback function receives the keyboard key and the action, and perform what you want it to do. The action is one of glfw.PRESS, glfw.REPEAT, or glfw.RELEASE.

Control close event pyglet

I have a program that has multiple windows in pyglet, and I want to make one window unclosable, rather to set its visibility to false. Is there a way I can access the event handle for close, to make it instead of closing the window, possibly return a bool or a string like "should close."?
Found the answer to my own question, first define a custom event loop with window_event_loop = pyglet.app.EventLoop(), then create a handler for .event for the event loop
#window_event_loop.event
def on_window_close(window):
# Extra code here
return pyglet.event.EVENT_HANDLED

PyQt5 UI stuck at long operation

I'm creating a game with some AI that may take some time. The problem is even if I call relevant methods to update the UI before running the AI function, the UI is not visually updated.
Some example code looks like this
def onClickBoard(self, e):
x, y = toBoardGrid(e.x(), e.y())
self.game.move(x, y)
self.update_board()
print("before AI")
# This line takes a few seconds
ai_move = self.ai.get_best_move(self.game)
print("after AI")
self.game.move(ai_move[0], ai_move[1])
self.update_board()
Where self.update_board is a method that updates a QWidget and it's very fast. This onClickBoard method is assigned to the widget's mouseReleaseEvent.
self.board.mouseReleaseEvent = self.onClickBoard
When running the game, I can see before AI printed to the terminal but the visual window doesn't change. I see the window updates only once, after the AI commits its move.
Is there a way to make the board update once before the slow function call and another once after it?
Yes, you can force Qt to process all pending events, and thus update the GUI, with the QApplication::processEvents() method. Add the following line just before the slow function call:
QtWidgets.QApplication.instance().processEvents()

X11 FocusIn is not working

As long as I understand it, the X11 FocusIn event is triggered whenever the window comes into focused. It the the window that the keyboard input is sent to. I am having trouble triggering this event. I have made sure to give it the FocusChangeMask when creating the window. I have created a breakpoint inside my event handler where the FocusIn event is supposed to happen and it is not stopping.
I have 2 separate window, a transparent one and one non-transparent. Currently I have it so the transparent window is always on top of the non transparent window. Whenever I switch focus and then switch back to the transparent window, the non-transparent window is directly underneath. This causes other windows to be stuck in 'between' the transparent and non-transparent window.
I have noticed that whenever I focus on the non-transparent window that is underneath that triggers the FocusIn event. I can not get the transparent window to trigger the event. Does this have something to do with the window being in 32-bit color?
What am I missing?
while(!renderer->stop)
{
XNextEvent(renderer->x_display, &event);
switch(event.type)
{
case Expose:
if (event.xexpose.window == gstreamer_window)
{
XRaiseWindow(renderer->x_display, renderer->opengl_window);
}
break;
case FocusIn:
if (event.xfocus.window == renderer->opengl_window)
{
XRaiseWindow(renderer->x_display, gstreamer_window);
}
break;
case ConfigureNotify:
if (event.xconfigure.window == renderer->opengl_window)
{
XMoveWindow(renderer->x_display, gstreamer_window,
event.xconfigure.x, event.xconfigure.y - top_border_offset);
}
break;
}
}
Here is how I created the window.
XSetWindowAttributes swa;
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | FocusChangeMask;
swa.colormap = XCreateColormap(x_display, XDefaultRootWindow(x_display), visual, AllocNone);
swa.background_pixel = 0;
swa.border_pixel = 0;
/* Create a window */
opengl_window = XCreateWindow (
x_display, parent,
0, 0, m_plane_width, m_plane_height, 0,
depth, InputOutput,
visual, CWEventMask | CWBackPixel | CWColormap | CWBorderPixel,
&swa );
It appears as though I set the FocusChangeMask at the wrong place. By adding the line XSelectInput(x_display, opengl_window, FocusChangeMask)
, it now triggers the FocusIn event. It was triggering the other display because it had the mask but this one didn't.
It's not clear from your question whether the windows referenced in your question are top level application windows, or secondary, ancillary windows that are child windows of your top level application windows.
But in all cases, proper input focus handling requires you to inform the window manager exactly how your application expects to handle input focus.
See section 4.1.7 of the ICCCM specification for more information. Unfortunately, it's not enough just to code an event loop that handles FocusIn messages, and expect them to fall out of the sky. First, you need to tell your window manager how exactly you are going to handle input focus switching, then respond to the window manager's messages, as explained in the ICCCM specification; perhaps by explicitly sending the SetInputFocus requests for your own application windows.
See my post under OP's self accepted answer for background
I had the same problem and it seems if you use XSelectInput it overrides the event mask for a window, instead of adding to it. You need to either:
skip adding XSelectInput and set the event masks on the window when created
or add all of the masks for the window to the XSelectInput command
Here's my similar setup which worked before I added the XSelectInput line:
swa.event_mask = StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask | ExposureMask | KeyPressMask;
wnd = XCreateWindow(disp, wndRoot, left, top, width, height, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
XMapWindow(disp, wnd);
When I added this for capturing key input:
XSelectInput(disp, wnd, KeyPressMask | KeyReleaseMask);
everything else stopped working, which I didn't realize for a while, until now, because I was just testing keys.
I have a single window application with no controls in the client area, so I don't know what else XSelectInput does for a window that already has the masks, but I do get key up and down messages without it. In the OP's self accepted answer he just goes the other way and adds 'FocusChangeMask' to XSelectInput instead.
The documentation for a lot of X11 is, in my opinion, a lot like the standard Apple documentation where it has the affliction of never saying what the function really actually does or affects, but tells you all about everything else. (See bottom snippet here) To be fair a good portion of the Cocoa docs are pretty decent, but maybe half are not. That goes for many or most of the parameters as well.
From Linux man page which I think is the maybe verbatim the same as the Xlib manual here https://tronche.com/gui/x/xlib/
The XSelectInput function requests that the X server report the events associated with the specified event mask.
Setting the event-mask attribute of a window overrides any previous call for the same window but not for other clients.
(Below is my own perhaps incorrect rewording of the XInputSelect docs)
This can be interpreted as perhaps:
XSelectInput sets the event-mask on a window for a display for events reported to the client. Each client can set its own independent mask for events it wants to receive with the following exceptions (skipping the exceptions).
Now the critical part:
XInputSelect will override and replace for a client any previous event-mask settings for a window on a display, including any event-mask set when creating the window.
And what I wish it was written as to make sure its understood, if true, that the XInputSelect does nothing else like enable key to character interpretation and what not, because I believe the core confusion is that people from all the various examples out there get the impression that there is some other magic besides setting mask. I'm assuming there's not, and the docs speak of no other magic besides the mask.
XInputSelect sets the event-mask for a window and allows for setting an event mask after a window is created.
And my opinion is that that line should have been first.

Freeze when using tkinter + pyhook. Two event loops and multithreading

I am writing a tool in python 2.7 registering the amount of times the user pressed a keyboard or mouse button. The amount of clicks will be displayed in a small black box in the top left of the screen. The program registers clicks even when another application is the active one.
It works fine except when I move the mouse over the box. The mouse then freezes for a few seconds after which the program works again. If I then move the mouse over the box a second time, the mouse freezes again, but this time the program crashes.
I have tried commenting out pumpMessages() and then the program works. The problem looks a lot like this question pyhook+tkinter=crash, but no solution was given there.
Other answers has shown that there is a bug with the dll files when using wx and pyhook together in python 2.6. I don't know if that is relevant here.
My own thoughts is that it might have something to do with the two event loops running parallel. I have read that tkinter isn't thread safe, but I can't see how I can make this program run in a single thread since I need to have both pumpmessages() and mainlooop() running.
To sum it up: Why does my program freeze on mouse over?
import pythoncom, pyHook, time, ctypes, sys
from Tkinter import *
from threading import Thread
print 'Welcome to APMtool. To exit the program press delete'
## Creating input hooks
#the function called when a MouseAllButtonsUp event is called
def OnMouseUpEvent(event):
global clicks
clicks+=1
updateCounter()
return True
#the function called when a KeyUp event is called
def OnKeyUpEvent(event):
global clicks
clicks+=1
updateCounter()
if (event.KeyID == 46):
killProgram()
return True
hm = pyHook.HookManager()# create a hook manager
# watch for mouseUp and keyUp events
hm.SubscribeMouseAllButtonsUp(OnMouseUpEvent)
hm.SubscribeKeyUp(OnKeyUpEvent)
clicks = 0
hm.HookMouse()# set the hook
hm.HookKeyboard()
## Creating the window
root = Tk()
label = Label(root,text='something',background='black',foreground='grey')
label.pack(pady=0) #no space around the label
root.wm_attributes("-topmost", 1) #alway the top window
root.overrideredirect(1) #removes the 'Windows 7' box around the label
## starting a new thread to run pumMessages() and mainloop() simultaniusly
def startRootThread():
root.mainloop()
def updateCounter():
label.configure(text=clicks)
def killProgram():
ctypes.windll.user32.PostQuitMessage(0) # stops pumpMessages
root.destroy() #stops the root widget
rootThread.join()
print 'rootThread stopped'
rootThread = Thread(target=startRootThread)
rootThread.start()
pythoncom.PumpMessages() #pump messages is a infinite loop waiting for events
print 'PumpMessages stopped'
I've solved this problem with multiprocessing:
the main process handles the GUI (MainThread) and a thread that consumes messages from the second process
a child process hooks all mouse/keyboard events and pushes them to the main process (via a Queue object)
From the information that Tkinter needs to run in the main thread and not be called outside this thred, I found a solution:
My problem was that both PumpMessages and mainLoop needed to run in the main thread. In order to both receive inputs and show a Tkinter label with the amount of clicks I need to switch between running pumpMessages and briefly running mainLoop to update the display.
To make mainLoop() quit itself I used:
after(100,root.quit()) #root is the name of the Tk()
mainLoop()
so after 100 milliseconds root calls it's quit method and breaks out of its own main loop
To break out of pumpMessages I first found the pointer to the main thread:
mainThreadId = win32api.GetCurrentThreadId()
I then used a new thread that sends the WM_QUIT to the main thread (note PostQuitMessage(0) only works if it is called in the main thread):
win32api.PostThreadMessage(mainThreadId, win32con.WM_QUIT, 0, 0)
It was then possible to create a while loop which changed between pumpMessages and mainLoop, updating the labeltext in between. After the two event loops aren't running simultaneously anymore, I have had no problems:
def startTimerThread():
while True:
win32api.PostThreadMessage(mainThreadId, win32con.WM_QUIT, 0, 0)
time.sleep(1)
mainThreadId = win32api.GetCurrentThreadId()
timerThread = Thread(target=startTimerThread)
timerThread.start()
while programRunning:
label.configure(text=clicks)
root.after(100,root.quit)
root.mainloop()
pythoncom.PumpMessages()
Thank you to Bryan Oakley for information about Tkinter and Boaz Yaniv for providing the information needed to stop pumpMessages() from a subthread
Tkinter isn't designed to be run from any thread other than the main one. It might help to put the GUI in the main thread and put the call to PumpMessages in a separate thread. Though you have to be careful and not call any Tkinter functions from the other thread (except perhaps event_generate).

Resources