so i'm making a basic weather app using pygame and im having a problem with the gui
so all the code works fine but the window doesnt properly show
here is the code:
import ast, sys
import pygame
from pygame.locals import *
import inputbox
import get_info
class Weather():
def __init__(self):
self.zip = '99354'
self.get_info()
pygame.font.init()
self.state = 2
self.font = pygame.font.Font("resources\Sansation_Light.ttf", 16)
self.font_render()
self.bg = pygame.image.load('resources/background.png')
self.refresh = pygame.image.load('resources/button1.png')
self.refresh_r = self.refresh.get_bounding_rect()
self.refresh_r.x, self.refresh_r.y = (155,550)
self.chg_zip = pygame.image.load('resources/button2.png')
self.chg_zip_r = self.chg_zip.get_bounding_rect()
self.chg_zip_r.x, self.chg_zip_r.y = (20,135)
self.main()
def font_render(self):
self.current_img = pygame.image.load('resources/%s.png'%self.weather)
self.cur_temp = self.font.render(self.temp, 0, (255,255,255))
self.cur_weather = self.font.render(self.weather, 0, (255,255,255))
self.updated = self.font.render(self.update[0], 0, (255,255,255))
self.updated2 = self.font.render(self.update[2], 0, (255,255,255))
self.ref_text = self.font.render("Refresh", 0, (255,255,255))
self.zip_text = self.font.render("Change Zip", 0, (255,255,255))
def Draw(self):
self.screen.blit(self.bg,(0,0))
self.screen.blit(self.refresh,(155,550))
self.screen.blit(self.ref_text,(200,560))
self.screen.blit(self.chg_zip,(20,135))
self.screen.blit(self.zip_text,(40,140))
self.screen.blit(self.radar_img,(12,175))
self.screen.blit(self.updated,(100,500))
self.screen.blit(self.updated2,(175,525))
self.screen.blit(self.current_img,(20,20))
self.screen.blit(self.cur_temp,(150,50))
self.screen.blit(self.cur_weather,(150,70))
row = 25
for i in range(0,5):
stat_str = str(self.info[0][i][0])+' : '+ str(self.info[0][i][1])
self.cur_stats = self.font.render(stat_str, 0, (255,255,255))
self.screen.blit(self.cur_stats,(275,row))
row+=25
def button(self):
if self.refresh_r.collidepoint(pygame.mouse.get_pos()) and pygame.mouse.get_pressed()[0]:
self.get_info()
if self.chg_zip_r.collidepoint(pygame.mouse.get_pos()) and pygame.mouse.get_pressed()[0]:
self.state = 1
def get_zip(self):
self.screen.blit(self.bg,(0,0))
self.zip = inputbox.ask(self.screen,"Zipcode")
self.__init__()
self.screen.blit(self.bg,(0,0))
self.state = 2
def get_info(self):
get_info.get_info(self.zip)
print "done"
with open('info.txt','r') as info:
fore_info = info.read()
weather = ast.literal_eval(fore_info)
current = weather[0]
self.info = weather[1]
forecast = weather[2]
self.place = weather[3]
self.update = self.place.strip().split('.')
self.temp = current[0]
self.weather = current[1]
self.radar_img = pygame.image.load('radar.jpg')
def main(self):
clock = pygame.time.Clock()
self.screen = pygame.display.set_mode((475,600))
pygame.display.set_caption('Weather')
while True:
clock.tick(45)
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
if self.state == 1:
self.get_zip()
else:
self.Draw()
self.button()
Weather()
i know my code is very sloppy and not the best but it still works except when i run it this is what the window looks like:
it shows what ever is behind it until you drag another window over it or you min and max it then it shows what i should
so how should i change my code so that it pops up and shows properly
It's probably because you never call pygame.display.flip()
Related
A few days ago I started making my first professional pygame (didn t do any pygame ever before), so for the first time I made a main menu, for the actual game, after that the game, so I have 2 files in that project(main menu and the game).
But after some seconds I realised i don t know how to start the game from the main menu by clicking the START button. SO I NEED SOME HELP......
I will let you down my main menu code.
import pygame
import pygame.freetype
from pygame.sprite import Sprite
from pygame.rect import Rect
from enum import Enum
from pygame.sprite import RenderUpdates
BLUE = (106, 159, 181)
WHITE = (255, 255, 255)
def create_surface_with_text(text, font_size, text_rgb, bg_rgb):
""" Returns surface with text written on """
font = pygame.freetype.SysFont("Courier", font_size, bold=True)
surface, _ = font.render(text=text, fgcolor=text_rgb, bgcolor=bg_rgb)
return surface.convert_alpha()
class UIElement(Sprite):
""" An user interface element that can be added to a surface """
def __init__(self, center_position, text, font_size, bg_rgb, text_rgb, action=None):
"""
Args:
center_position - tuple (x, y)
text - string of text to write
font_size - int
bg_rgb (background colour) - tuple (r, g, b)
text_rgb (text colour) - tuple (r, g, b)
action - the gamestate change associated with this button
"""
self.mouse_over = False
default_image = create_surface_with_text(
text=text, font_size=font_size, text_rgb=text_rgb, bg_rgb=bg_rgb
)
highlighted_image = create_surface_with_text(
text=text, font_size=font_size * 1.2, text_rgb=text_rgb, bg_rgb=bg_rgb
)
self.images = [default_image, highlighted_image]
self.rects = [
default_image.get_rect(center=center_position),
highlighted_image.get_rect(center=center_position),
]
self.action = action
super().__init__()
#property
def image(self):
return self.images[1] if self.mouse_over else self.images[0]
#property
def rect(self):
return self.rects[1] if self.mouse_over else self.rects[0]
def update(self, mouse_pos, mouse_up):
""" Updates the mouse_over variable and returns the button's
action value when clicked.
"""
if self.rect.collidepoint(mouse_pos):
self.mouse_over = True
if mouse_up:
return self.action
else:
self.mouse_over = False
def draw(self, surface):
""" Draws element onto a surface """
surface.blit(self.image, self.rect)
class Player:
""" Stores information about a player """
def __init__(self, score=0, lives=3, current_level=1):
self.score = score
self.lives = lives
self.current_level = current_level
def main():
pygame.init()
screen = pygame.display.set_mode((800, 600))
game_state = GameState.TITLE
while True:
if game_state == GameState.TITLE:
game_state = title_screen(screen)
if game_state == GameState.NEWGAME:
player = Player()
game_state = play_level(screen, player)
if game_state == GameState.NEXT_LEVEL:
player.current_level += 1
game_state = play_level(screen, player)
if game_state == GameState.QUIT:
pygame.quit()
return
def title_screen(screen):
start_btn = UIElement(
center_position=(400, 400),
font_size=30,
bg_rgb=BLUE,
text_rgb=WHITE,
text="Start",
action=GameState.NEWGAME,
)
quit_btn = UIElement(
center_position=(400, 500),
font_size=30,
bg_rgb=BLUE,
text_rgb=WHITE,
text="Quit",
action=GameState.QUIT,
)
buttons = RenderUpdates(start_btn, quit_btn)
return game_loop(screen, buttons)
def play_level(screen, player):
return_btn = UIElement(
center_position=(140, 570),
font_size=20,
bg_rgb=BLUE,
text_rgb=WHITE,
text="Return to main menu",
action=GameState.TITLE,
)
nextlevel_btn = UIElement(
center_position=(400, 400),
font_size=30,
bg_rgb=BLUE,
text_rgb=WHITE,
text=f"Next level ({player.current_level + 1})",
action=GameState.NEXT_LEVEL,
)
buttons = RenderUpdates(return_btn, nextlevel_btn)
return game_loop(screen, buttons)
def game_loop(screen, buttons):
""" Handles game loop until an action is return by a button in the
buttons sprite renderer.
"""
while True:
mouse_up = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
mouse_up = True
screen.fill(BLUE)
for button in buttons:
ui_action = button.update(pygame.mouse.get_pos(), mouse_up)
if ui_action is not None:
return ui_action
buttons.draw(screen)
pygame.display.flip()
class GameState(Enum):
QUIT = -1
TITLE = 0
NEWGAME = 1
NEXT_LEVEL = 2
if __name__ == "__main__":
main()
Thank you in advice!!!!
i have two ideas:
1st:
just import it. When you import it it will be executed.
import importlib
importlib.import("name of you file without extension") # i dont know the command
2nd:
use
exec()
exec(open("filename.py").read())
or
with open("file.py", "r") as f:
exec(f.read())
ywc
I have a simple project that display a "button" with an image,a text and a background color:
import os
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide"
import pygame, sys
from pygame.locals import *
import requests
import io
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GRAY = (200, 200, 200)
class Main_window:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((800, 600))
def draw(self):
Btn1 = Button(0,0,200,200,"hello",color=RED, text="test",text_color=BLACK)
def mainLoop(self):
done = False
while not done:
eventlist = pygame.event.get()
for ev in eventlist:
if ev.type == QUIT:
done = True
if ev.type == MOUSEBUTTONDOWN:
Button.getButton(ev)
pygame.quit()
class Button:
Buttons = []
def __init__(self, left, top, w, h,function,color=RED, text="", text_color = BLACK):
self.left = left
self.top = top
self.w = w
self.h = h
self.right = self.left+w
self.bottom = self.top+h
self.function = function
surf1 = pygame.Surface((w, h))
surf1.fill(color)
rect1 = pygame.Rect(left, top, w, h)
main.screen.blit(surf1, rect1)
Button.Buttons.append(self)
if text != "":
font1 = pygame.font.SysFont('chalkduster.ttf', 72)
text1 = font1.render(text, True, text_color)
text_rect = text1.get_rect(center=(int(w/2), int(h/2)))
main.screen.blit(text1, text_rect)
image_url = "https://image.flaticon.com/icons/png/512/31/31990.png"
r = requests.get(image_url)
img = io.BytesIO(r.content)
image = pygame.image.load(img)
image = pygame.transform.scale(image, (w, h))
main.screen.blit(image, (0, 0))
pygame.display.flip()
def getButton(event):
for i in Button.Buttons:
x, y = event.pos
if x>=i.left and x<=i.right and y<=i.bottom and y>=i.top:
eval(i.function+"()")
def hello():
print("hello")
main = Main_window()
main.draw()
main.mainLoop()
that's works fine but the problem is that when i launch the game it load the main window, wait some time(something like 1 second) and then load the button.I tried to add more button and it loaded them one at a time.I don't undestand why.
Two Fixes
Use a local image rather than an image sent with requests
It loads slowly maybe because of the draw function of the MainWindow class.
Try this in the main loop function
def mainLoop(self):
done = False
while not done:
eventlist = pygame.event.get()
for ev in eventlist:
if ev.type == QUIT:
done = True
if ev.type == MOUSEBUTTONDOWN:
Button.getButton(ev)
self.draw()
pygame.display.flip()
pygame.quit()
And at the end
main = Main_window()
main.mainLoop()
So you don't have to call main.draw() because it is already being called in the main loop.
Everything works fine until a .mp3 file is loaded with mixer.music.load(). After that, there are buttons on the window that I have created are still responsive, but the window itself is unresponsive. I cannot drag the window around, and I cannot use the x button to close the window. They don't highlight as if you could press them at all after the music is loaded. I know the main loop is still running because my buttons highlight when the mouse is colliding with them as they should. I just don't know why the window itself is not responding.
What is weird is I have a load button that opens a tkinter filedialog to get a directory, if I click on that and just close the filedialog, the pygame main window becomes responsive again like normal.
import os
import pygame as pg
import tkinter.filedialog
import tkinter
from pygame import mixer
pg.init()
WIDTH, HEIGHT = 500, 800
HW = WIDTH // 2
HH = HEIGHT // 2
win = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption("Music Player")
CLOCK = pg.time.Clock()
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
def play_song(directory, song_list):
mixer.init()
mixer.music.load(os.path.join(directory, song_list[0]))
pg.mixer.music.play()
def get_files(directory):
file_list = []
for entry in os.listdir(directory):
file = os.path.join(directory, entry)
ext = os.path.splitext(entry)[-1].lower()
if os.path.isfile(file) and ext == '.mp3': # adds only files, that are .mp3
file_list.append(entry)
return file_list
def get_directory():
tkinter.Tk().withdraw() # Without this a blank tkinter window will appear.
try:
directory = tkinter.filedialog.askdirectory() # This opens the file browser.
files_list = get_files(directory)
return directory, files_list
except FileNotFoundError:
return 0, []
class Button(object):
def __init__(self, pic, hover, click, x, y):
self.pic = pic
self.hover = hover
self.click = click
self.x = x
self.y = y
self.w = self.pic.get_width()
self.h = self.pic.get_height()
self.hw = self.w // 2
self.hh = self.h // 2
def collide(self, mouse_x, mouse_y):
if mouse_x > self.x and mouse_x < self.x + self.w:
if mouse_y > self.y and mouse_y < self.y + self.h:
return True
def draw(self, win1, clicked=False):
mouse_pos = pg.mouse.get_pos()
if clicked:
win1.blit(self.click, (self.x, self.y))
elif self.collide(mouse_pos[0], mouse_pos[1]):
win1.blit(self.hover, (self.x, self.y))
else:
win1.blit(self.pic, (self.x, self.y))
play_idle = pg.image.load('play.png')
play_hover = pg.image.load('play_hover.png')
play_click = pg.image.load('play_click.png')
play = Button(play_idle, play_hover, play_click, HW - 52, HEIGHT - 152)
pause_idle = pg.image.load('pause.png')
pause_hover = pg.image.load('pause_hover.png')
pause_click = pg.image.load('pause_click.png')
pause = Button(pause_idle, pause_hover, pause_click, HW - 52, HEIGHT - 152)
skip_idle = pg.image.load('skip.png')
skip_hover = pg.image.load('skip_hover.png')
skip_click = pg.image.load('skip_click.png')
skip = Button(skip_idle, skip_hover, skip_click, WIDTH - 152, HEIGHT - 152)
load_idle = pg.image.load('load.png')
load_hover = pg.image.load('load_hover.png')
load_click = pg.image.load('load_click.png')
load = Button(load_idle, load_hover, load_click, 50, 50)
def draw(win, clicked_play, clicked_load, playing):
win.fill(WHITE)
if playing:
pause.draw(win, clicked_play)
else:
play.draw(win, clicked_play)
skip.draw(win)
load.draw(win, clicked_load)
pg.display.update()
def main():
directory, song_list = '', []
CLOCK.tick(60)
run = True
while run:
clicked_play = False
clicked_load = False
loaded = False
playing = mixer.music.get_busy()
events = pg.event.get()
for event in events:
if event.type == pg.QUIT:
run = False
if event.type == pg.MOUSEBUTTONDOWN:
print('button down')
if event.button == 1:
mouse_pos = pg.mouse.get_pos()
if load.collide(mouse_pos[0], mouse_pos[1]):
# Pause music
clicked_load = True
draw(win, clicked_play, clicked_load, playing)
directory, song_list = get_directory()
if play.collide(mouse_pos[0], mouse_pos[1]) and not playing:
clicked_play = True
if len(song_list) > 0:
play_song(directory, song_list)
print('playing')
if pause.collide(mouse_pos[0], mouse_pos[1]) and playing:
clicked_play = False
pg.mixer.music.stop()
print('pause')
draw(win, clicked_play, clicked_load, playing)
pg.display.quit()
pg.quit()
main()
I found a solution. It was a threading issue. Thank you to #stovfl for pointing me in the right direction.
with concurrent.futures.ThreadPoolExecutor() as executor:
future = executor.submit(get_directory)
return_value = future.result()
get_directory is a function using tkinter.
I am trying to allow the user to change the color of the background, but my program is saying that my PlayerIG.hudBack and hudText are not valid color arguments.
I don't want to use a confusing amount of if statements.
Any help would be great thanks!
import pygame, time, os, pickle
from pygame.locals import*
pygame.font.init()
win = pygame.display.set_mode((600, 320))
pygame.display.set_caption("PLAYER HUD")
font = pygame.font.SysFont("Rockwell", 30)
clock = pygame.time.Clock()
white = ((255,255,255))
blue = ((0,0,255))
green = ((0,255,0))
red = ((255,0,0))
black = ((0,0,0))
orange = ((255,100,10))
yellow = ((255,255,0))
blue_green = ((0,255,170))
marroon = ((115,0,0))
lime = ((180,255,100))
pink = ((255,100,180))
purple = ((240,0,255))
gray = ((127,127,127))
magenta = ((255,0,230))
brown = ((100,40,0))
forest_green = ((0,50,0))
navy_blue = ((0,0,100))
rust = ((210,150,75))
dandilion_yellow = ((255,200,0))
highlighter = ((255,255,100))
sky_blue = ((0,255,255))
light_gray = ((200,200,200))
dark_gray = ((50,50,50))
tan = ((230,220,170))
coffee_brown =((200,190,140))
moon_glow = ((235,245,255))
class Player:
def __init__(self, name):
self.name = name
self.gold = 0
self.hudBack = "black"
self.hudText = "orange"
self.option1 = False
self.option = 0
PlayerIG = Player("Player")
def redrawGameWindow():
if os.path.exists("savefile") == True:
with open('savefile', 'rb') as f:
PlayerIG = pickle.load(f)
win.fill(PlayerIG.hudBack)
text1 = font.render("GOLD:", 1, PlayerIG.hudText)
text2 = font.render(str(PlayerIG.gold), 1, PlayerIG.hudText)
win.blit(text1, (0, 0))
win.blit(text2, (70, 0))
pygame.display.update()
run = True
while run:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
pass
redrawGameWindow()
pygame.quit()
You only need one set of parentheses around the RGB values, like so:
moon_glow = (235,245,255)
I'm just learning Python, and as one of the basic challenges that were suggested to me by friends I've been working on an alarm clock. I successfully made an alarm clock that played a .wav sound at a predetermined time. Now I've been using Pygame for a GUI, and it all worked great, until I had to set the buttons to adjust the alarm time. See when I compare the alarm time to the clock time, the clock time is in string form, so the alarm time has to be as well. But the buttons are unable to + or - from a string, so I'm kind of stuck. I tried ways of turning it into a string, but everything has been fairly unsuccessful so far. Wondering if anyone here had a suggestion.
Here's the code:
#!/usr/bin/python
import os.path, sys, datetime, time
import os, sys, math
import pygame, random
from pygame.locals import *
main_dir = os.path.split(os.path.abspath(__file__))[0]
data_dir = os.path.join(main_dir, 'data')
currenttime = datetime.datetime.now()
clocktime = currenttime.strftime("%H:%M")
alarmtime = "13:23"
pygame.init()
#Screen and background
width, height = 600, 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Alarm Clock")
background = pygame.image.load(os.path.join(data_dir, 'diamondplate.jpg'))
background = pygame.transform.scale(background, (width, height))
#Current time
font = pygame.font.Font(None, 250)
text = font.render("%s" % clocktime, True, (255,140,0), (0,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery - 200
#Alarm time
text2 = font.render("%s" % '00:00', True, (255,140,0), (0,0,0))
text2Rect = text2.get_rect()
text2Rect.centerx = screen.get_rect().centerx
text2Rect.centery = screen.get_rect().centery + 200
#Alarm noise
def alarmsound(file_path=os.path.join(main_dir, 'data', 'boom.wav')):
pygame.mixer.init(11025)
sound = pygame.mixer.Sound(file_path)
channel = sound.play()
pygame.time.wait(1000)
#Image load function
def load_image(file):
file = os.path.join(data_dir, file)
surface = pygame.image.load(file)
return surface.convert_alpha()
#Hour arrow up
class Hourup(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowup.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottomleft = text2Rect.topleft
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Hour arrow down
class Hourdown(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowdown.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottom = text2Rect.top
self.rect.left = 159
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Minute arrow up
class Minuteup(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowup.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottomright = (442,414)
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Minute arrow down
class Minutedown(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self,self.groups)
image = load_image('arrowdown.png')
image = pygame.transform.scale(image, (85,85))
self.image = image
self.rect = self.image.get_rect()
surface = pygame.display.get_surface()
self.area = surface.get_rect()
self.rect.bottomright = text2Rect.topright
def click_check(self,eventpos):
if self.rect.collidepoint(eventpos):
pass
def update(self):
pass
#Groups
allsprites = pygame.sprite.Group()
Hourup.groups = allsprites
Hourdown.groups = allsprites
Minutedown.groups = allsprites
Minuteup.groups = allsprites
hourup = Hourup()
hourdown = Hourdown()
minutedown = Minutedown()
minuteup = Minuteup()
clickableobjects = [hourup, hourdown, minutedown, minuteup]
def main():
while 1:
currenttime = datetime.datetime.now()
clocktime = currenttime.strftime("%H:%M")
screen.blit(background,(0,0))
text = font.render("%s" % clocktime, True, (255,140,0), (0,0,0))
text2 = font.render("%s" % alarmtime, True, (255,140,0), (0,0,0))
screen.blit(text,textRect)
screen.blit(text2,text2Rect)
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
sys.exit()
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
for object in clickableobjects:
object.click_check(event.pos)
if clocktime == alarmtime and soundcheck = False:
alarmsound()
soundcheck = True
allsprites.draw(screen)
allsprites.update()
pygame.display.update()
pygame.display.flip
if __name__ == '__main__':
main()
You are looking for strptime() which will convert a string to a datetime instance.
see here for how to properly use it.
Comparing two datetime instances will give you a timedelta instance which you can read about here. Essentially it will give you the difference between the two times to the nearest milisecond.
Learn everything you can about the datetime, time, and calendar modules. Once you learn those dealing with times and dates in python becomes really easy.