Text box render on top of main code in pygame? - pygame

I have implemented text box code to my simulation but now it is not rendering the main code, or rendering on top of my main code so nothing is displayed but the box :(
Here is my text box code :
def textbox(font20):
input_box = pygame.Rect(300,225,400,100)
color_inactive =(TURQUOISE)
color_active = (0,255,249)
color = color_inactive
active = False
text = ""
done = False
font = font20
while not done:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if input_box.collidepoint(event.pos):
active = not active
else:
active = False
color = color_active if active else color_inactive
if event.type == pygame.KEYDOWN:
if active:
if event.key == pygame.K_RETURN:
print(text)
text = ""
done = True
elif event.key == pygame.K_BACKSPACE:
text = text[:-1]
else:
text += event.unicode
# Render the current text.
text_surface = font.render(text, True, color)
# Resize the box if the text is too long.
width = max(200, text_surface.get_width()+10)
input_box.w = width
# Blit the text.
screen.blit(text_surface, (input_box.x+5, input_box.y+5))
# Blit the input_box rect.
pygame.draw.rect(screen, color, input_box, 2)
pygame.display.flip()
I also screen.blit to turquoise at the bottom where I draw the screen and flip it.

Did you remember to click in the box? ;)
There's also a bunch of minor issues:
The code doesn't have a definition for TURQUOISE.
The loop didn't handle the pygame.QUIT event.
It also needs to propagate this event to the outer-loop
As the box grew, it made a mess, I added a black rectangle to erase the old.
It did not return the text value.
With all these, quite minor, bugs fixed, it works pretty well. But just remember to click in the box first!
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
### initialisation
pygame.init()
screen = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
pygame.display.set_caption("Text Box Test")
BLACK = (0,0,0)
TURQUOISE = (0,154,196)
CYAN = (0,255,249)
def textbox(font20):
#input_box = pygame.Rect(300,225,400,100)
input_box = pygame.Rect(10,10,400,100)
color_background = BLACK # for erasing
color_inactive = TURQUOISE
color_active = CYAN
color = color_inactive
active = False
text = ""
done = False
font = font20
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.event.post( pygame.event.Event( pygame.QUIT ) ) # re-send the quit event to the next loop
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
if input_box.collidepoint(event.pos):
active = not active
else:
active = False
color = color_active if active else color_inactive
elif event.type == pygame.KEYDOWN:
if active:
if event.key == pygame.K_RETURN:
print(text)
#text = ""
done = True
elif event.key == pygame.K_BACKSPACE:
text = text[:-1]
else:
text += event.unicode
print( "DEBUG: text is now [%s]" % ( text ) )
# Render the current text.
text_surface = font.render(text, True, color)
# Resize the box if the text is too long.
width = max(200, text_surface.get_width()+10)
input_box.w = width
# Blit the input_box rect.
pygame.draw.rect(screen, color_background, input_box) # filled box to clear the old one
pygame.draw.rect(screen, color, input_box, 2)
# Blit the text.
screen.blit(text_surface, (input_box.x+5, input_box.y+5))
pygame.display.flip()
return text
font = pygame.font.SysFont('', 24)
textbox( font )
pygame.quit()

Related

User input recorded from multiple text boxes and put into MySQL

I'm running into a brick wall and have spent multiple hours trying to research how to do this and I'm at the point I'm not sure if I'm asking the right question.
I have a page for recording user input in multiple boxes. I've made a separate file for my text box function which feeds into the main page. I want to be able to click next and record all the use input from the text boxes into a MySQL database.
The problem I'm running into seems to be that the main page doesn't know there's user input just that there is a text box, so I can't record anything, while if I change the text input file it defeats the purpose of creating one so that I can use text boxes anywhere.
Main page
import pygame
import Test
import button
import sys
import mysql.connector
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Main Page")
icon = pygame.image.load('icons8-robber-32.png')
pygame.display.set_icon(icon)
colour_active = pygame.Color('orange')
colour_inactive = pygame.Color('Yellow')
font = pygame.font.Font(None, 32)
start_image = pygame.image.load('play.png').convert_alpha()
exit_image = pygame.image.load('exit.png').convert_alpha()
menu_image = pygame.image.load('menu.png').convert_alpha()
back_image = pygame.image.load('back.png').convert_alpha()
next_image = pygame.image.load('next.png').convert_alpha()
def register():
input_box1 = Test.inputBox(210, 105, 140, 32, "First Name: ")
input_box2 = Test.inputBox(210, 160, 140, 32)
input_boxes = [input_box1, input_box2]
back_button = button.Button(100, 450, back_image, 0.2)
next_button = button.Button(450, 450, next_image, 0.2)
done = False
while not done:
for event in pygame.event.get():
for box in input_boxes:
box.handle_event(event)
for box in input_boxes:
box.update()
screen.fill((30, 30, 30))
for box in input_boxes:
box.draw(screen)
if back_button.draw(screen):
print("no")
if next_button.draw(screen):
sys.exit()
pygame.display.update()
start_button = button.Button(100, 150, start_image, 0.2)
exit_button = button.Button(250, 150, exit_image, 0.2)
menu_button = button.Button(400, 150, menu_image, 0.2)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((150, 255, 100))
if start_button.draw(screen):
print("no")
if exit_button.draw(screen):
sys.exit()
if menu_button.draw(screen):
register()
pygame.display.update()
pygame.QUIT()
sys.exit()
Text box file
import pygame
pygame.init()
colour_active = pygame.Color('orange')
colour_inactive = pygame.Color('Yellow')
font = pygame.font.Font(None, 32)
class inputBox():
def __init__(self, x, y, w, h, text=''):
self.rect = pygame.Rect(x,y,w,h)
self.color = colour_inactive
self.text = text
self.text_surface = font.render(text, True, self.color)
self.active = False
def handle_event(self,event):
if event.type == pygame.MOUSEBUTTONDOWN:
if self.rect.collidepoint(event.pos):
self.active = not self.active
else:
self.active = False
self.color = colour_active if self.active else colour_inactive
if event.type == pygame.KEYDOWN:
if self.active:
if event.key == pygame.K_RETURN:
print(self.text)
elif event.key == pygame.K_BACKSPACE:
self.text = self.text [:-1]
else:
self.text += event.unicode
self.text_surface = font.render(self.text, True, self.color)
def update(self):
self.rect.w = max(100, self.text_surface.get_width() + 10)
def draw(self, screen):
screen.blit(self.text_surface, (self.rect.x+5, self.rect.y+5))
pygame.draw.rect(screen, self.color, self.rect, 2)
You do not need the self.text file in the main code. So instead of writing input_box1.self.text, it was just input_box1.text.

What's the most convenient way to add buttons in pygame with text

Following up my last question, for my school assignment, I am developing a game. My concept includes the uses of buttons in this game so I was wondering what is the most convenient way to add buttons in pygame? Also, if you have suggestions for resources which can help me in cases like this, please let me know. Thanks
Here's my Code:
# Program: Import Library, Pygame, for initialization of this program
import pygame
# Initialize the game engine
pygame.init()
# Define Colours
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
GREEN = ( 0, 255, 0)
RED = ( 255, 0, 0)
BLUE = ( 0, 0, 255)
display_width = 1080
display_height = 720
size = (display_width, display_height)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("MiniConomy Trivia, for Adults")
# Button Program
class Button:
def __init__(self, size, text, pos, bgColor=(0, 255, 0), textColor=(0, 0, 0)):
self.pos = pos
self.size = size
self.text = text
self.font = pygame.font.Font(pygame.font.get_default_font(), size[1])
self.textSurf = self.font.render(f"{text}", True, textColor)
self.button = pygame.Surface((size[0], size[1])).convert()
self.button.fill(bgColor)
def render(self, window):
window.blit(self.button, (self.pos[0], self.pos[1]))
window.blit(self.textSurf, (self.pos[0]+1, self.pos[1]+5))
def clicked(self, events):
mousePos = pygame.mouse.get_pos()# get the mouse position
for event in events:
if self.button.get_rect(topleft=self.pos).collidepoint(mousePos[0], mousePos[1]):
if event.type == pygame.MOUSEBUTTONDOWN:
return True
return False
# Setting a Title Screen
def text_objects(text, font):
textSurface = font.render(text, True, BLACK)
return textSurface, textSurface.get_rect()
largeText = pygame.font.Font('freesansbold.ttf', 90)
# Creating a Title Screen
TextSurf, TextRect = text_objects("MiniConomy", largeText)
TextRect.center = (540,150)
# Play Button
button = Button([280,50], "Let's Begin", [380,302])
button2 = Button([280, 50], "Second Button", [380, 302])
#Loop until the user clicks the close button
done = False
# -------- Main Program Loop -----------
while done == False:
events = pygame.event.get()
for event in events: # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
# Set the screen background
screen.fill(BLUE)
screen.blit(TextSurf, TextRect)
while True:
# Button 1 Control
button.render(screen)
if button.clicked(events):
print("Game Logic goes here")
pygame.display.flip()
button2.render(screen)
if button2.clicked(events):
print("Game Logic Here")
pygame.display.flip()
pygame.quit()
quit()
The most convenient way to add a button would be to make a button class. I know you are not using OOP with your code, but taking a class approach would allow you to make multiple buttons with a single class acting as a template for each button.
Lets start by making a class.
Fist we will make an init function to initialise all the attribute variables of our button.
class Button:
def __init__(self, size, text, pos):
self.pos = pos
self.size = size
self.text = text
self.font = pygame.font.Font(pygame.font.get_default_font(), size/2)
self.button = pygame.Surface(size[0], size[1]).convert()
Then we will add methods to our class to give our class some behaviour. We want to render our button, then we want to be able to click our button.
def render(self, window):
window.blit(self.button, (self.pos[0], self.pos[1]))
window.blit(self.textSurf, (self.pos[0]+1, self.pos[1]+5))
def clicked(self, events):
mousePos = pygame.mouse.get_pos()# get the mouse position
for event in events:
if self.button.get_rect(topleft=self.pos).collidepoint(mousePos[0], mousePos[1]):
if event.type == pygame.MOUSEBUTTONDOWN:
return True
return False
With this implemented, your code becomes:
# Program: Import Library, Pygame, for initialization of this program
import pygame
# Initialize the game engine
pygame.init()
# Define Colours
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
GREEN = ( 0, 255, 0)
RED = ( 255, 0, 0)
BLUE = ( 0, 0, 255)
display_width = 1080
display_height = 720
size = (display_width, display_height)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("MiniConomy Trivia, for Adults")
class Button:
def __init__(self, size, text, pos, bgColor=(255, 255, 255), textColor=(0, 0, 0)):
self.pos = pos
self.size = size
self.text = text
self.font = pygame.font.Font(pygame.font.get_default_font(), size[1])
self.textSurf = self.font.render(f"{text}", True, textColor)
self.button = pygame.Surface((size[0], size[1])).convert()
self.button.fill(bgColor)
def render(self, window):
window.blit(self.button, (self.pos[0], self.pos[1]))
window.blit(self.textSurf, (self.pos[0]+1, self.pos[1]+5))
def clicked(self, events):
mousePos = pygame.mouse.get_pos()# get the mouse position
for event in events:
if self.button.get_rect(topleft=self.pos).collidepoint(mousePos[0], mousePos[1]):
if event.type == pygame.MOUSEBUTTONDOWN:
return True
return False
# Setting a Title Screen
def text_objects(text, font):
textSurface = font.render(text, True, BLACK)
return textSurface, textSurface.get_rect()
largeText = pygame.font.Font('freesansbold.ttf', 100)
# Creating a Title Screen
TextSurf, TextRect = text_objects("MiniConomy", largeText)
TextRect.center = (540,150)
# Play Button
button = Button([250, 50], "A button", [50, 50])
#Loop until the user clicks the close button
done = False
# -------- Main Program Loop -----------
while done == False:
events = pygame.event.get()
for event in events: # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
# Set the screen background
screen.fill(BLUE)
screen.blit(TextSurf, TextRect)
button.render(screen)
if button.clicked(events):
print("Your game start logic goes here")
pygame.display.flip()
Now obviously, there is a lot of potential to add extra features to our button class, like color changing when mouse is over the button and things like that. Just to show you the benefits of using a class. Now if you want another button, you can simply make another instance of button class
anotherButton = Button([300, 500], "Second Button", [500, 500])
and in main loop call:
while True:
anotherButton.render(screen)
anotherButton.clicked(events)
And BOOM, you have a second button. Hope i could help.
Edit: Answer to the difficulties you were having. Couple of things.
First, Both buttons are in the same position. Change that.
button = Button([280,50], "Let's Begin", [380,302])
button2 = Button([280, 50], "Second Button", [380, 302])
Third argument is position and as you can see, they are the same.
Second, You already have a while True loop so there is no reason why you should add another while True loop. Just use the first while loop, that is why it is called a game loop
Third, You call pygame.display.flip() twice. This function is responsible for updating the screen every frame. Calling it twice means you are trying to update it twice every frame, which can cause unwanted problems.
while not done:
events = pygame.event.get()
for event in events: # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
# Set the screen background
screen.fill(BLUE)
screen.blit(TextSurf, TextRect)
# Button 1 Control
button.render(screen)
if button.clicked(events):
print("Game Logic goes here")
button2.render(screen)
if button2.clicked(events):
print("Game Logic Here")
pygame.display.flip()

Change colour of sprite rect from group

I have a group of rects, they display in a row. I want them to change their colour when they have been clicked, until they are clicked again
I have this code so far to create the sprites:
class DrawableRect(pygame.sprite.Sprite):
def __init__(self,color,width,height,value=0):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.rect = self.image.get_rect()
self.value = value
self.x = 0
self.y = 0
def change_value(self,color,value):
self.image.fill(color)
self.value=value
def DrawRects(start_x, start_y, rect_spacing, colour_list):
current_x_pos = start_x
for rect_num in range(0,8):
rect = DrawableRect(colour_list[rect_num], boxW, boxH)
rect.rect.x = current_x_pos
rect.rect.y = start_y
current_x_pos = current_x_pos + rect.rect.width + rect_spacing
rects.add(rect)
rects.draw(screen)
The idea of the app is for each rectangle to represent a bit, and when pressed it alternates between 0 and 1, the makeup of each bit displays the decimal equivalent somewhere.
I read that groups are unordered therefore indexing wouldn't work, is that true?
Here's an example I've modified to suit your purposes. I have a bunch of sprites (coloured rectangles) in a sprite group and I change* the colour of any sprite that collides with the mouse pointer when a mouse button is pressed.
Here's the code, you're probably most interested in the change_color() method and the MOUSEBUTTONUP event handling code.
import random
import pygame
screen_width, screen_height = 640, 480
def get_random_position():
"""return a random (x,y) position in the screen"""
return (random.randint(0, screen_width - 1), #randint includes both endpoints.
random.randint(0, screen_height - 1))
color_list = ["red", "orange", "yellow", "green", "cyan", "blue", "blueviolet"]
colors = [pygame.color.Color(c) for c in color_list]
class PowerUp(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
width, height = 64, 32
self.image = pygame.Surface([width, height])
self.clicked = False # track whether we've been clicked or not
# initialise color
self.color = random.choice(colors)
self.image.fill(self.color)
# Fetch the rectangle object that has the dimensions of the image
self.rect = self.image.get_rect()
# then move to a random position
self.update()
def update(self):
#move to a random position
self.rect.center = get_random_position()
def random_color(self):
# randomise color
self.clicked = not self.clicked
if self.clicked:
color = random.choice(colors)
else:
color = self.color
self.image.fill(color)
if __name__ == "__main__":
pygame.init()
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Sprite Color Switch Demo')
clock = pygame.time.Clock() #for limiting FPS
FPS = 60
exit_demo = False
pygame.key.set_repeat(300, 200)
#create a sprite group to track the power ups.
power_ups = pygame.sprite.Group()
for _ in range(10):
power_ups.add(PowerUp()) # create a new power up and add it to the group.
# main loop
while not exit_demo:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit_demo = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
exit_demo = True
elif event.key == pygame.K_SPACE:
power_ups.update()
elif event.type == pygame.MOUSEBUTTONUP:
# check for collision
for p in power_ups:
if p.rect.collidepoint(event.pos): # maybe use event?
p.random_color()
screen.fill(pygame.Color("black")) # use black background
power_ups.draw(screen)
pygame.display.update()
clock.tick(FPS)
pygame.quit()
quit()
Let me know if you have any questions. Obviously this doesn't do row alignment of the sprites, I think you have a handle on that. I would suggest that you have all of your screen drawing operations in one place so your code can be clearer.
*The new colour is randomised from a short list, so there's a 14% chance it won't change from the starting colour.

Pygame making a selection like in stategy games

So I made this in order to select an area like in strategy games, however
the screen keeps blinking, is there a way to solve this?
import pygame
from pygame.locals import *
WHITE = (255,255,255)
BLUE = (0,0,255)
pygame.init()
window = pygame.display.set_mode((640, 480))
window.fill(WHITE)
pygame.display.flip()
LEFT_CLIC = 1
mouse_tracking = False
draw_area = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
continuer = 0
if event.type == MOUSEBUTTONDOWN:
if event.button == LEFT_CLIC:
x_start, y_start = event.pos
x_end, y_end = event.pos
mouse_tracking = True
draw_area = True
if event.type == MOUSEMOTION and mouse_tracking:
x_end, y_end = event.pos
if event.type == MOUSEBUTTONUP:
if event.button == LEFT_CLIC:
x_end, y_end = event.pos
mouse_tracking = True
draw_area = False
if draw_area:
width = x_end-x_start
height = y_end-y_start
pygame.draw.rect(window, BLUE, (x_start, y_start, width, height))
pygame.display.flip()
window.fill(WHITE)
pygame.display.flip()
So it's pretty simple, record coordinates when there is a clic, then follow the mouse until the clic is done.
Thanks.
There should be only one pygame.display.flip() call per frame, otherwise you get this flickering, so remove one of them. Also, fill the screen before you draw the rect.
window.fill(WHITE)
if draw_area:
width = x_end-x_start
height = y_end-y_start
pygame.draw.rect(window, BLUE, (x_start, y_start, width, height))
pygame.display.flip()

How to cycle 3 images on a rect button?

Just started learning Python/Pygame watching videos and reading to learn . I would like to see a example code to cycle 3 images on a rect button from a mouse press and return to first image. Really I want the pictures to be three options and return different results. So be able to cycle image be able to select option and option when triggered execute choice.
Example
import pygame
pygame.init()
screen = pygame.display.set_mode((300,200))
# three images
images = [
pygame.Surface((100,100)),
pygame.Surface((100,100)),
pygame.Surface((100,100)),
]
images[0].fill((255,0,0))
images[1].fill((0,255,0))
images[2].fill((0,0,255))
# image size and position
images_rect = images[0].get_rect()
# starting index
index = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# check mouse position and pressed button
if event.button == 1 and images_rect.collidepoint(event.pos):
# cycle index
index = (index+1) % 3
screen.blit(images[index], images_rect)
pygame.display.flip()
pygame.quit()
Example using class - to create many buttons
import pygame
class Button(object):
def __init__(self, position, size):
self._images = [
pygame.Surface(size),
pygame.Surface(size),
pygame.Surface(size),
]
self._images[0].fill((255,0,0))
self._images[1].fill((0,255,0))
self._images[2].fill((0,0,255))
self._rect = pygame.Rect(position, size)
self._index = 0
def draw(self, screen):
screen.blit(self._images[self._index], self._rect)
def event_handler(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and self._rect.collidepoint(event.pos):
self._index = (self._index+1) % 3
pygame.init()
screen = pygame.display.set_mode((320,110))
button1 = Button((5, 5), (100, 100))
button2 = Button((110, 5), (100, 100))
button3 = Button((215, 5), (100, 100))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
button1.event_handler(event)
button2.event_handler(event)
button3.event_handler(event)
button1.draw(screen)
button2.draw(screen)
button3.draw(screen)
pygame.display.flip()
pygame.quit()
If I understood the question correctly, you need a single button that changes the look every time you click on it, and changes its relative function accordingly.
You should be able to solve your problem by creating a class that takes two list and a counter
1) list of images
2) list of functions
3) the counter tells you which image/function is selected.
The functions needs to be built in the class, but you can provide the image that you want in the class argument (actually, you could pass them as arguments, but I don't think is worth it).
Here is the code, I commented some lines with their intended meaning (in line comments)
import pygame
import sys
pygame.init()
width = 600
height = 400
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Magic Buttons")
background = pygame.Surface(screen.get_size())
clock = pygame.time.Clock()
class Buttons:
def __init__(self, posX, posY, image1, image2, image3):
self.image_list = [image1, image2, image3] # static list of images
self.function_list = [self.button_function_1,self.button_function_2,self.button_function_3 ]
self.rect_position = (posX, posY) # this is a tuple to identify the upper left corner of the rectangle of the image
self.button_type = 0 # initial value of the button, both for the function and the image
self.image = pygame.image.load(self.image_list[0]) #default image, index number 0 of image_list
self.rect = pygame.Rect(posX, posY, self.image.get_width(), self.image.get_height()) # create a rectangle object same size of the images
def check(self, pos):
if self.rect.collidepoint(pos) ==True:
self.change_button()
else:
pass
def change_button(self):
self.button_type = (self.button_type +1)%3
self.image = pygame.image.load(self.image_list[self.button_type ]) # load the image relative to button_type
self.function_list[self.button_type -1]() # execute the function relative to the new value of button_type
self.draw_button()
def draw_button(self):
screen.blit(self.image, self.rect_position) # blit the new button image
def button_function_1(self):
print ("function 1 in action")
def button_function_2(self):
print ("function 2 in action")
def button_function_3(self):
print ("function 3 in action")
multibutton = Buttons(100,100,"button1.png","button2.png","button3.png") # create an istance of the button in the x=100, y = 100, with the three image button
while True:
background.fill((0,0,0))
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONUP:
pos = pygame.mouse.get_pos() # fetch the position of the mouse
multibutton.check(pos) # check if the mouse is on the button
multibutton.draw_button()
pygame.display.flip()