So I'm using Pygame to create a fancy display for a program I am writing. I chose Pygame because it's easy to get started and does a great job with animations. I want the display to be as big as I can make it so as much information can be shown as possible. Here is the kicker however, I still want to be able to get to the console of the program.
Pygame forces a fullscreen window to the front, so you cant tab out, and moving the windows to another windows desktop crashes the display. I would do a key trick to switch the pygame mode, but I cannot use pygame.event.get() because of how the program the threaded.
Is there a way to make it a full-screen window so that I can tab out and leave it up in the background? I dont really want it to just be a normal window because it is not as big that way.
The display crashes after I tab out and back in, here is what that looks like:
I also get a non-zero exit code: -805306369 (0xCFFFFFFF)
Here is a broken down version of the code that still gives me this error, you'll notice there are some things in here you wouldn't have if this was your full program, but I wanted to retain as much architecture as I could.
import pygame
import os
BACKGROUND = (9, 17, 27)
os.environ['SDL_VIDEO_WINDOW_POS'] = "0,0"
pygame.init()
pygame.font.init()
infoObject = pygame.display.Info()
SIZE = (infoObject.current_w, infoObject.current_h)
X_CENTER = SIZE[0]/2
Y_CENTER = SIZE[1]/2
# create a borderless window that's as big as the entire screen
SCREEN = pygame.display.set_mode((SIZE[0], SIZE[1]), pygame.NOFRAME)
clock = pygame.time.Clock()
TextFont = pygame.font.SysFont('Courant', 30)
class DisplayState:
state = type(bool)
def __init__(self):
self.state = True
def get_state(self):
return self.state
def change_state(self, new_state):
self.state = new_state
def main(display_state_object):
running = True
while running:
if display_state_object.get_state():
SCREEN.fill(BACKGROUND)
pygame.display.flip()
else:
return 1
return
if __name__ == "__main__":
main(DisplayState())
EDIT
I think it is a multi-threading problem! See this code:
Produces Error
def start_display():
display(params)
def display(params):
pygame loop
if __name__ == "__main__":
display_thread = threading.Thread(target=start_display)
display_thread.start()
Does not produce error
def display(params):
pygame loop
if __name__ == "__main__":
display_thread = threading.Thread(target=display(params))
display_thread.start
# marker
One problem with the version that does work, the program does not seem to be continuing forwards outside the thread (ie the marker is never reached). Is this how the threading library works? It may explain why I had the middle man function present. Maybe this is a different problem and deserves its own question?
EDIT
Setting up the thread like this allows the main thread to continue, but brings back the pygame error:
threading.Thread(target=display, args=(DisplayState(),))
There's no easy way to do this on windows/sdl using the real fullscreen mode, and the usual way to solve this is to use a borderless window.
Here's how to create such a "fake" fullscreen window in pygame:
import pygame
import os
# you can control the starting position of the window with the SDL_VIDEO_WINDOW_POS variable
os.environ['SDL_VIDEO_WINDOW_POS'] = "0,0"
pygame.init()
# now let's see how big our screen is
info = pygame.display.Info()
# and create a borderless window that's as big as the entire screen
screen = pygame.display.set_mode((info.current_w, info.current_h), pygame.NOFRAME)
You have to call one of the pygame event functions (e.g. pygame.event.pump() or pygame.event.get()) each frame or the window will become unresponsive and the program will appear to have crashed. If you call one of those functions, you should be able to press Alt+Tab (in Windows) to get back to the desktop without crashing the program (if you select the desktop, the window will be minimized and if you select another window, it will just be brought to the front).
def main(display_state_object):
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
# Press Esc to quit.
if event.key == pygame.K_ESCAPE:
running = False
if display_state_object.get_state():
SCREEN.fill(BACKGROUND)
pygame.display.flip()
else:
return 1
return
Related
When I run this code:
import pygame
import time
pygame.init()
WIDTH, HEIGHT = 900, 500 # this declares the size of the window the GUI will open in
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Encryption and Decryption") # this titles the window
FPS = 60 # this declares the magnitude of the framerate of the window
def draw_window():
GREY = (54, 45, 45)
WIN.fill(GREY) # this colours the window grey
pygame.display.update() # this updates the colouring of the window the next time the frame cycles
def Coursework():
clock = pygame.time.Clock() # this declares the refresh rate as a variable the function can use
run = True
while run: # everything in this loop will only happen when the window is open
clock.tick(FPS) # this refreshes the frame every 1/FPS second
for event in pygame.event.get(): # this manages events that may happen in the window
if event.type == pygame.QUIT:
run = False # this ends the loop if the user quits the program
draw_window() # this ensures that when this function is called the window is created
pygame.quit()
if __name__ == "__Coursework__": # this ensures that the GUI will open when this specific program is running
Coursework()
The pygame window closes instantly. I saw in another similar question that there are certain things an application loop must do and I believe I have done all of them, but the window still closes instantly. As I'm still a novice it's very likely that I am wrong about having hit all bases, but I do not know what I have missed.
this ensures that the GUI will open when this specific program is running
You are right, but the __name__ should be set to '__main__' in this case, so:
if __name__ == "__main__":
Coursework()
I want to completely prevent the user from closing the Pygame window except for the key x. Currently, I'm able to prevent the user from closing it, but I am unable to prevent the user from opening another window that overlaps it (press windows key -> open chrome, which overlaps the Pygame window).
import sys
import pygame
from pygame.locals import *
pygame.init()
infoObject = pygame.display.Info()
screen = pygame.display.set_mode((infoObject.current_w, infoObject.current_h), flags=pygame.NOFRAME)
while True:
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
pygame.quit()
sys.exit()
if event.type == QUIT:
pass
pygame.display.flip()
We don't have complete solutions for this task.
You can make the title var vanish away by setting display mode to NOFRAME (You have already used this): pygame.display.set_mode(flags = pygame.NOFRAME), but this is overkill for just stopping close buttons
Although any user with minimum Computer Knowledge will fire up a Task manager and kill python.exe :-(
There are ways of disabling task manager through Registry in Windows, Image File Execution Options blah blah, but your game script will barely run with Administrator priviliges (With nagging of UAC)
In order to do this, you can add this piece of code to your pygame.display.set_mode():
pygame.display.set_mode(..., flags=pygame.NOFRAME). Now, the bar with the "x" button will disapear.
Notice that if you decide to make this change, you won't be able to move your game window anymore. (Unless you change it back).
I'm a new in PyGame and I was making a game. Until I discovered that when you were moving the window to another place of your desktop for example, the game temporarily stops. But ticks of the game still running when I used pygame.time.get_ticks().
So I made a completely new program with only the necessary code and it does the same thing.
Can someone explain me why it does it and if we can resolve this problem?
import pygame
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption('The Test Program')
running = True
update_counter = 1
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
print(str(update_counter) + " updates")
update_counter += 1
pygame.quit()
quit()
# So try to move the window across your screen and you will see that, prints will stop and they will resume when you will release the click
So someone tell me that was normal, so I think it's only on Windows but there are no solutions. I put a script that show a pause symbol on screen when the cursor leave the window to make it normal.
I'm working on a game with Pygame and it was going well...until it decided to not respond. Here's my code:(sorry if the formatting doesn't work im new to stackoverflow)
#MODULES USED (use from to make calling functions easier)
from random import *
from pygame import *
import pygame
from pygame.locals import *
pygame.init()
from time import *
#INITIALISE THE PYGAME WINDOW
pygame.event.pump()
screen = display.set_mode([500, 500])
blue = [230, 242, 255]
screen.fill(blue)
pygame.display.update()
default = pygame.image.load("default.jpg")
screen.blit(default, (0,0))
pygame.display.update()
click = pygame.mouse.get_pressed()
#BASIC HEXAPAWN
#ALL POSSIBLE COMPUTER'S MOVE BOARDS AS ARRAY HERE
#TThe moves from the board images are left to right
class Board:
def __init__(self, board, moves):
self.board = board
self.moves = moves
boards1 = [pygame.image.load("a1.jpg"), pygame.image.load("a2.jpg"), pygame.image.load("a3.jpg")] #move1 boards
#irrelevant stuff removed, just initialising the other boards.
#GAME MAIN LOOP
while True:
#START GAME - 1st move
print("You play as O, computer is X")
currentboard = "O O O\n# # #\nX X X"
print(currentboard)
#PLAYER MOVE 1
screen.blit(boards1[0], (0, 250))
pygame.display.update()
if boards1[0].get_rect().collidepoint(pygame.mouse.get_pos()) and click:
screen.blit(boards1[0], (0,0))
pmove = 0
#note: I haven't added the other board options yet.
currentboard = boards1[pmove]
#[insert more unnecessary code here]
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
break
pygame.quit()
Basically whenever I run the code, the Pygame window looks alright, but when I try to click on the image it just stops responding. Also the window is always stuck on a loading cursor, idk why.
I've tried everything I could find but, nope, not working.
If anyone can help then I'd appreciate it.
Thanks :)
Eleeza
edit:i didnt know others could edit my posts too
Clearing some stuff up, when I ran my code, there were no errors, no Traceback the only problem is the unresponsive thing.
Also sorry im really bad at explaining things :/
There are a few things going on, but the main one is that you have you click variable set only once when the program starts.
Move click = pygame.mouse.get_pressed() inside of the main loop.
If you do that and it still hangs, you should show the rest of your code.
Also, the full code is not there, so I can't be 100% sure, but I don't think that break should be there.
I am an amateur programmer. I have a small (and urgent) problem. I am working on a text (console) based adventure game for fun. At a certain point, I want a pygame window to open. The player has to click in the window as fast as possible. The reaction time should be returned to the main program, and the pygame window should close. The main program will then continue running.
I've already written the script for the pygame window and it works fine. My main program also works fine. Now how do I call the pygame window from the main program?
I tried importing the pygame script but that didn't work.
Thanks.
Here's my pygame script:
import pygame, sys, time
from pygame.locals import *
pygame.init()
#Set up window
pygame.event.set_grab(0)
pygame.mouse.set_visible(1)
screen = pygame.display.set_mode((300,200))
shape = screen.convert_alpha()
pygame.display.set_caption("Sniper Alert")
#Colors
WHITE = (255, 255, 255)
BLACK = (0,0,0)
RED = (255, 0, 0)
#Draw on surface object
screen.fill(BLACK)
def alert():
#Create a font
font = pygame.font.Font(None,50)
#Render the text
text = font.render("Sniper Alert", True, RED)
#Create a rectangle
textRect = text.get_rect()
#Center the rectangle
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery
#Blit the text
screen.blit(text, textRect)
pygame.display.update()
return press()
def press():
t0 = time.clock()
dt = 0
while time.clock() - t0 < 1.5:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
dt = time.clock()- t0
return dt
#Exit
pygame.quit()
sys.exit()
#Run the game loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
There are three ways I can think of. Here they are:
Solution Number 1:
This way is probably the worst solution and the hardest to implement, but lets get it out of the way. I wouldn't advise using it but you may want to in some circumstances. You could use the threading module. Threading is designed for multitasking like this, and would do what you want. You can create a new thread like so:
import threading
def DoSomething(a,b,c): #this function will be called in the background, simultaneously to the main program
#do something here
apple = 1
banana = 2
cat = 3
mythread = threading.thread(target=DoSomething,args=(apple,banana,cat)) #defines a thread
mythread.start() #tells the thread to start running
Solution Number 2
A much better way to do this would be just to launch it as a different program. You could do that with the subprocess module, used for running command line commands. This would effectively run the program as if you had executed it in a new tab of your terminal (without the new tab). You can then make the program able to communicate with yours using subprocess.comunicate(). I will connect the input and output of the pygame program to your main program from here. Here is an example of this:
import subprocess
input = <insert input> #when you run the program and it requires something like a raw_input, this will give it input. You could probably avoid needing to send the pygame program input, because all you really want to do is receive an output from it.
process = subprocess.Popen(["python","<popup filename>"],stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=False) #this function is how subprocess runs shell/command prompt commands. On a side note, if you simply want to run a shell command without accessing input or output, just use "subprocess.call(<list of words in command (so ls -a would be ['ls','-a'])>)"
output = process.communicate(input)[0] #this will return any output the program prints, meaning you can communicate with the program and receive information from it
Using subprocess is probably the best way.
Solution Number 3
The final option, if you want it all in one file and do not want to mess around with threading, would be just to alternate the two programs in a while loop. Basically, you would run a loop that executes code from both programs. This is how it would work:
while True: #an infinite loop. it doesn't necessarily have to be infinite.
#call methods or run code to maintain text based game
#call methods or run code to maintain pygame window
this has worked just fine for me in a pygame game i made which also had a text component, but the subprocess way is probably better...