Open and close pygame window within loop without "backend terminated" message [duplicate] - python

This question already has answers here:
How to get keyboard input in pygame?
(11 answers)
Closed last year.
I'm working on a program for school and am required to use a pygame window to display cumulative totals for my program (it's for ordering coffee). Here is what the code looks like for the part where the window opens:
if totalconf == 'y':
# if user wishes to view cumulative totals
pygame.init()
background_colour = (231,247,146)
(width, height) = (1500, 900)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Running Totals')
# initialise new window with yellow background and title
myFont = pygame.font.SysFont("arial", 40)
myFont2 = pygame.font.SysFont("arial", 20)
# initialise small and large fonts
text = myFont.render("In store totals:", True, (0, 0, 0))
text3 = myFont.render("Takeaway totals:", True, (0, 0, 0))
text4 = myFont.render("In store earnings:", True, (0, 0, 0))
text5 = myFont.render("Takeaway earnings:", True, (0, 0, 0))
text6 = myFont.render(f"Total discounts: ${total_discounts}", True, (0, 0, 0))
text7 = myFont.render(f"Total gst: ${total_gst}", True, (0, 0, 0))
text8 = myFont.render(f"Total surcharges: ${total_takeawaycharges}", True, (0, 0, 0))
# initialise headings and totals to display on screen
screen.fill(background_colour)
# fill screen with background color
pygame.display.flip()
# update screen
running = True
# run window
while running:
# while window is running
screen.blit(text, (20, 20))
screen.blit(text3, (300, 20))
screen.blit(text4, (600, 20))
screen.blit(text5, (900, 20))
screen.blit(text6, (20, 700))
screen.blit(text7, (20, 740))
screen.blit(text8, (20, 780))
# project all text onto screen
pygame.display.update()
# update screen
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[0]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (20, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[1]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (300, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[2]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (600, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
initial = 70
# set initial as 70 down
for item, values in totalsdict.items():
# for values stored in totals dict
text2 = myFont2.render(f'{item.title()}: {values[3]}', True, (0,0,0))
# print out item and equivalent total in small font
screen.blit(text2, (900, initial))
# display text on screen
pygame.display.update()
# update screen
initial += 40
# increase inital by 40 so values print vertically down
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if running == False:
pygame.quit()
# code to stop running if 'X' is pressed
If the user wants to see the cumulative totals, they input 'y' for totalconf. This bit of code sits in a continuous while loop which takes orders until a blank is entered. The first time the program runs this works great and opens and closes without stopping the program. However, the second time, if I wish to see the updated cumulative totals and open the pygame window, I get a message which says "Backend terminated or disconnected.Windows fatal exception: access violation". This is a really long program but I hope the information I have given is enough.
So in summary, I need to be able to open and close the window every time the loop runs without getting the message above.

Use the keyboard event:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_x:
running = False
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action.

Related

How to make text-rects appear one after another, after a delay in pygame

hoping to get some help regarding blitting text-rects in a sequence, a small delay of about a second between them. I've managed to get pretty close however my most recent attempt repeats the process of blitting my three lines of text over and over. I can't for the life of my figure out how to have these three lines blit to the screen in order, and then stop.
I have included an example of this part of my code, any and all help would be greatly appreciated!
def Title_Screen():
while True:
TitleScreen_MOUSE_POS = pygame.mouse.get_pos()
# Background
SCREEN.blit(BG, (0, 0))
pygame.display.flip()
# Title
pygame.time.delay(1000)
SCREEN.blit(TitleScreen1_TEXT, TitleScreen1_RECT)
pygame.display.flip()
pygame.time.delay(1000)
SCREEN.blit(TitleScreen2_TEXT, TitleScreen2_RECT)
pygame.display.flip()
pygame.time.delay(1000)
SCREEN.blit(TitleScreen3_TEXT, TitleScreen3_RECT)
# Press Any Key To Continue
SCREEN.blit(PressKeyText, PressKeyRect)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
Main_menu()
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
You need to maintain the state of the resources outside of the main loop.
In the example below, we use a list of font-images to hold what-to-paint. But the control of which image to paint is advanced with a timer function.
Of course, there's lots of different ways to do this.
import pygame
WIDTH = 800
HEIGHT= 300
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
pygame.init()
screen = pygame.display.set_mode( ( WIDTH, HEIGHT ) )
pygame.display.set_caption( "Title Screen" )
font = pygame.font.Font( None, 50 )
text1 = font.render( "The Owl and the Pussy-cat went to sea", 1, WHITE)
text2 = font.render( " In a beautiful pea-green boat,", 1, WHITE)
text3 = font.render( "They took some honey, and plenty of money,", 1, WHITE)
text4 = font.render( " Wrapped up in a five-pound note.", 1, WHITE)
title_lines = [ text1, text2, text3, text4 ]
title_delay = 2000 # Milliseconds between title advances
title_count = 4 # How many titles are in the animation
title_index = 0 # what is the currently displayed title
title_next_time = title_delay # clock starts at 0, time for first title
while True:
clock = pygame.time.get_ticks() # time now
# Handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
# paint the screen
screen.fill( BLACK ) # paint it black
# Write the current title, unless we've seen them all
if ( title_index < title_count ):
screen.blit( title_lines[ title_index ], ( 10, 10 ) )
# Is it time to update to the next title?
if ( clock > title_next_time ):
title_next_time = clock + title_delay # some seconds in the future
title_index += 1 # advance to next title-image
pygame.display.flip()

How to show text when true

I want to show a text on the screen when a variable changes to True. The Text "Game Over" is show for a very short period of time with this code but I disappears after less than one second.
import pygame
import random
import time
import math
# Initialize pygame
pygame.init()
# Create window (width, height)
screen1 = pygame.display.set_mode(((800, 600)))
ScreenHeight = screen1.get_height()
ScreenWidth = screen1.get_width()
#Game Over text
go_font = pygame.font.Font('freesansbold.ttf', 128)
go_text = "GAME OVER"
go_textX = 300
go_textY = 300
def show_gameover(go_textX, go_textY):
gameover_text = font.render(go_text, True, (105, 105, 105))
screen1.blit(gameover_text, (go_textY,go_textY))
# Variable to track gameover
gameover = False
while running:
if gameover:
show_gameover(go_textX, go_textY)
# Insert Background
screen1.blit(background, (0, 0))
i = 0
for obs in obstacle_list:
obs.spawn_obstacle()
obs.update_y()
outOfBounds = obs.out_of_bounds(playerX, playerY)
if outOfBounds:
obstacle_list.pop(i)
collision = obs.collision_detection(playerX, playerY)
if collision:
gameover = True
show_gameover(go_textX, go_textY) #Show Gameover-text
i += 1
# Update after each iteration of the while-loop
pygame.display.update()
You have to draw the text after the background. If you draw the text before drawing the background, it will be hidden from the background. Draw it just before updating the display. So it is drawn over all other objects in the scene.
while running:
# Insert Background
screen1.blit(background, (0, 0))
# [...]
if gameover:
show_gameover(go_textX, go_textY)
# Update after each iteration of the while-loop
pygame.display.update()

Why text display for 2 seconds in pygame

Text wchich I display is displaying for only around 2 sec. I want that it will display while I click to other area
elif msg[0:7] == 'YOU WIN' and Message_id == '200':
print('You Win')
textSurface = font.render('You Win', True, (0, 0, 0))
largeText = pygame.font.Font('freesansbold.ttf', 115)
TextSurf = pygame.font.render('You Win', True, (0, 0, 0))
TextRect = textSurface.get_rect()
TextRect.center = ((600 / 2), (700 // 2))
surface.blit(TextSurf, TextRect)
grid.draw(surface)
pygame.display.flip()
break
If you want something to be drawn permanently, you need to draw it in the application loop. The typical PyGame application loop has to:
handle the events by either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by either pygame.display.update() or pygame.display.flip()
Create the text surface at initialization:
winTextSurf = font.render('You Win', True, (0, 0, 0))
winTextRect = winTextSurf.get_rect(topleft = (600 // 2, 700 // 2)
Add a variable that indicates the text needs to be drawn:
drawWinText = Fasle
Set the variable if the text needs to be drawn:
elif msg[0:7] == 'YOU WIN' and Message_id == '200':
drawWinText = True
break
When you no longer want the text to be drawn, you need to reset the value.
drawWinText = False
Draw the text in the main application loop depending on the status of drawWinText:
while run:
# [...]
if drawWinText:
surface.blit(winTextSurf, winTextRect)
pygame.display.flip()
See the answers to question Python - Pygame - rendering translucent text for how to draw transparent text.

How do you make the string appear after hitting the return key

I am creating a flashcard game for my kid. Its about Dinos. I am having trouble making "Congrats, You got it right" appear on the screen. I have moved my code all over the place but no luck. Can someone please help me out.
To be clear, What I want to happen is when the user presses the number 1,2,3 on the keypad, and if the key is the correct answer that correlates to the question, the message "Congrats, You got it right!" should appear on the screen.
I know the keydown event right now is the return key, but I did that for testing purposes only. This is also the same for testtext variable. I was using that variable to see if I could print "Hello WOrld" to the screen.
I do have a feeling it has something to do with the loop that is running. My guess would be is that it does show up for a fraction of a second but disappears before anyone can see it.
import pygame, random
pygame.font.init()
pygame.init()
font = pygame.font.Font(None, 48)
#Created the window display
size = width, height = 800,800
screen = pygame.display.set_mode(size)
#Loads the images of the starting game Trex
#t_rex = pygame.image.load('trex1.png')
##Places the image on the screen
#screen.blit(t_rex,(150,50))
count = 0
score = 0
active = False
testtext = font.render("Hello WOrld", True, (250, 250, 250))
#The below code keeps the display window open until user decides to quie app
crashed = False
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_RETURN:
screen.blit(testtext, (200,699))
while count < 2:
screen.fill(0)
dinoQuestions = ["Does a t-rex eat meat?\n","Does a trycerotopes have 3 horns?\n"]
dinoAnswer = ["Yes\n", "No\n","Maybe\n"]
wordnum = random.randint(0, len(dinoQuestions)-1)
mainpic = pygame.image.load("trex1.png")
screen.blit(mainpic, (150, 20))
options = [random.randint(0, len(dinoAnswer)-1),random.randint(0, len(dinoAnswer)-1)]
options[random.randint(0,1)] = wordnum
question_display = font.render(dinoQuestions[wordnum].rstrip('\n'),True, (255, 255, 255))
text1 = font.render('1 - ' + dinoAnswer[options[0]].rstrip('\n'),True, (255, 255, 255))
text2 = font.render('2 - ' + dinoAnswer[options[1]].rstrip('\n'),True, (255, 255, 255))
#the below code is for testing purposes only
screen.blit(question_display,(200, 590))
screen.blit(text1, (200, 640))
screen.blit(text2, (200, 690))
count = count + 1
pygame.display.flip()
The blit to your screen surface you perform when handling a Return key down event is overwritten when you later call screen.fill(0).
I've rearranged your code a little and added displaying a result on appropriate key press.
import pygame
import random
pygame.init()
pygame.font.init()
font = pygame.font.Font(None, 48)
size = width, height = 800,800
screen = pygame.display.set_mode(size) #Created the window display
count = 0
score = 0
active = False
white = pygame.color.Color("white")
black = pygame.color.Color("black")
green = pygame.color.Color("green")
# load/create static resources once
mainpic = pygame.image.load("trex1.png")
testtext = font.render("Hello World", True, (250, 250, 250))
correct_text = font.render("Correct! Well Done!", True, green)
clock = pygame.time.Clock() # for limiting FPS
dinoQuestions = ["Does a t-rex eat meat?","Does a triceratops have 3 horns?"]
dinoAnswer = ["Yes", "No","Maybe"]
# initialise state
show_hello = False
show_correct = False
update_questions = True # need to update questions on the first iteration
finished = False
while not finished:
for event in pygame.event.get():
if event.type == pygame.QUIT:
finished = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
show_hello = not show_hello # toggle flag for later display
elif event.key == pygame.K_SPACE:
update_questions = True
elif event.key in [pygame.K_1, pygame.K_2]:
# an answer has been selected
# pygame.K_1 is 0, pygame.K_2 is 1
if dinoAnswer[event.key - pygame.K_1] == "Yes":
show_correct = True
count += 1
else:
show_correct = False
screen.fill(black)
screen.blit(mainpic, (150, 20))
if show_hello:
screen.blit(testtext, (200,199))
if show_correct:
screen.blit(correct_text, (200, 300))
if update_questions:
random.shuffle(dinoQuestions)
random.shuffle(dinoAnswer)
question_display = font.render(dinoQuestions[0],True, white)
text1 = font.render('1 - ' + dinoAnswer[0],True, white)
text2 = font.render('2 - ' + dinoAnswer[1],True, white)
update_questions = False
show_correct = False
# Display the Question
screen.blit(question_display,(200, 590))
screen.blit(text1, (200, 640))
screen.blit(text2, (200, 690))
# count = count + 1
pygame.display.flip()
clock.tick(60)
Hopefully this is enough of a framework for you to extend.
Let me know if you have any questions about any portions of the code.
I am a bit confused about what your exact problem is, so I'm going to try to answer. You say that you want the words "Congrats, , you got it right!", so I can help you with what went wrong. You blit the testtext before you color the screen, so each time the loop loops, it displays the testtext but then almost instantly covers it up with screen.fill(0). To make it better, you should put the blitting of the text after the screen is colored. The best way to do this is to put it right at the start of the loop, or making another event detector after the current position of the screen.fill in the code.
Also, I would get rid of the stacked while loop, and instead replace it with if statement because it is already in the while loop.
Is this what you were looking for?

How do I display text in a grid-like structure in Pygame?

I'm new to pygame and currently I'm working on creating a memory game where the computer displays boxes at random positions for like a second and then the user has to click on where he/she thinks those boxes are. It's kind of like this game:
However I'm not really sure how to make the computer display the boxes with like a letter or symbol e.g. 'T' or '%'. (I've already made the grid).
Could anyone please help? It would be really appreciated.
import pygame
size=[500,500]
pygame.init()
screen=pygame.display.set_mode(size)
# Colours
LIME = (0,255,0)
RED = (255, 0, 0)
BLACK = (0,0,0)
PINK = (255,102,178)
SALMON = (255,192,203)
WHITE = (255,255,255)
LIGHT_PINK = (255, 181, 197)
SKY_BLUE = (176, 226, 255)
screen.fill(BLACK)
# Width and Height of game box
width=50
height=50
# Margin between each cell
margin = 5
# Create a 2 dimensional array. A two dimesional
# array is simply a list of lists.
grid=[]
for row in range(20):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(20):
grid[row].append(0) # Append a cell
# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[1][5] = 1
# Set title of screen
pygame.display.set_caption("Spatial Recall")
#Loop until the user clicks the close button.
done=False
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
# -------- Main Program Loop -----------
while done==False:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
if event.type == pygame.MOUSEBUTTONDOWN:
# User clicks the mouse. Get the position
pos = pygame.mouse.get_pos()
# Change the x/y screen coordinates to grid coordinates
column=pos[0] // (width+margin)
row=pos[1] // (height+margin)
# Sete t hat location to zero
grid[row][column]=1
print("Click ",pos,"Grid coordinates: ",row,column)
# Draw the grid
for row in range(10):
for column in range(10):
color = LIGHT_PINK
if grid[row][column] == 1:
color = RED
pygame.draw.rect(screen,color,[(margin+width)*column+margin,(margin+height)*row+margin,width,height])
# Limit to 20 frames per second
clock.tick(20)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.quit ()
In order to display text, you have to go through a series of steps. First you will want to get a font by using the command `pygame.font.Font(font name, size). For example:
arialfont=pygame.font.Font('arial', 12)
All available fonts can be gotten from the command pygame.font.get_fonts(). Remember to initialize pygame (pygame.init()) before any of this.
Next, you will have to use the Font.render(text, antialias, color, background=None). For example:
text=arialfont.render('Hello World!', True, (0, 0, 0))
This will return a surface. You can use it just like you would any other surface. Use text.get_rect() to get its rect, then reposition the rect to put it where you want it to be, and blit it to the window. If you don't know anything about surface objects, just ask me.
Here is a working code.
import pygame, sys
pygame.init()#never forget this line
window=pygame.display.set_mode((100, 100))
font=pygame.font.SysFont('arial', 40)
text=font.render('#', True, (0, 0, 0))
rect=text.get_rect()
window.fill((255, 255, 255))
window.blit(text, rect)
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()

Categories

Resources