A few things first:
I am using Windows 10 Home edition
I am using Python 3.7
I am using pygame 1.9.4
My IDE is Visual Studio Code, with IDLE as the backup
I am currently designing a GUI using pygame. NOTE: the code is NOT done yet.
When I run a debug session in VS Code, it (mostly) works as expected, but when I try to click on the start button, pygame does not respond and shows not responding.
I've also noticed this with other pygame scripts I've made, where the pygame window freezes when clicked or moved.
Any help would be appreciated.
Here's the code:
# Import modules
import sys, pygame, time, math
from time import sleep
from PIL import Image
# Display background image
image = 'asdf.png'
change = 2
img = Image.open('asdf.png')
width = img.width * change
height = img.height * change
print(width)
print(height)
screen = pygame.display.set_mode((width,height))
background = pygame.image.load(image).convert()
newscreen = pygame.transform.scale(background, (width, height))
screen.blit(newscreen, (0,0))
pygame.display.update()
# start button
pygame.draw.rect(newscreen, (255,120,0), pygame.Rect(width/4,height-height/4, width/2, height/7))
screen.blit(newscreen, (0,0))
pygame.display.update()
pygame.init()
myFont = pygame.font.SysFont("Times New Roman", 100)
text = myFont.render("START", False, (0, 0, 0))
screen.blit(text, (width/4+8,height-height/4-10))
pygame.display.update()
pygame.image.save(newscreen, 'background.png')
pygame.image.save(text, 'starttext.png')
# i button
pygame.draw.rect(newscreen, (255,0,120), pygame.Rect(width - 50, 10, 40,40))
screen.blit(newscreen,(0,0))
pygame.display.update()
myFont = pygame.font.SysFont("Times New Roman", 25)
ibutton = myFont.render("i", False, (0, 0, 0))
screen.blit(ibutton, (width-32,17))
pygame.display.update()
# Mouse click
while True:
left,right,center = pygame.mouse.get_pressed()
if left == True:
if event.type == MOUSEBUTTONUP:
x,y = pygame.mouse.get_pos()
if ((width/4) <= x <= ((width/4) + (width/2))) and ((height-height/4) <= y <= ((height-height/4) + height/76)):
#move to next screen
break
time.sleep(5)
This is NOT similar to the linked problem because my program is for a GUI, and it requires mouse click events.
This answer by Ted Klein Bergamn explains why the window becomes unresponsive: https://stackoverflow.com/a/42719689/6220679
This is how pygame.event.get should be used:
running = True
while running:
for event in pygame.event.get():
# This lets you quit by pressing the X button of the window.
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # 1 = left mouse button, 2 = middle, 3 = right.
print('mouse up')
x,y = pygame.mouse.get_pos()
if ((width/4) <= x <= ((width/4) + (width/2))) and ((height-height/4) <= y <= ((height-height/4) + height/76)):
#move to next screen
running = False
In your case (for a simple GUI app) pygame.event.wait would probably be a good choice (it lets the program sleep while no event is in the queue).
running = True
while running:
event = pygame.event.wait()
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
print('mouse up')
x,y = pygame.mouse.get_pos()
if ((width/4) <= x <= ((width/4) + (width/2))) and ((height-height/4) <= y <= ((height-height/4) + height/76)):
#move to next screen
running = False
Related
I'm trying to write a script where it has a control panel and you can select what application u want to open only problem is that it opens that application multiple times please help only want to open it once.
I think the problem is that it checks if my mouse button is pressed multiple times a second and since my mouse is only being pressed for a second and it checks a couple times a second it does the if statement and completes it and opens the application multiple times.
# Importing Modules/Libraries.
import pygame
import subprocess
pygame.init()
pygame.font.init()
# Color Variables.
white_color = "#FFFFFF"
# Control Panel Variables.
ctrlpanel_run = True
ctrlpanel_program_select = True
ctrlpanel_program_select_input = True
# Main Arguments.
root = pygame.display.set_mode((700,400))
pygame.display.set_caption("AutoDraw Control Panel")
root.fill("#333333")
# Draws Control panel Program Select Screen.
if ctrlpanel_program_select == True:
title_font = pygame.font.Font("./fonts/Exo-Bold.otf", 100)
button_font = pygame.font.Font("./fonts/Exo-Bold.otf", 45)
title_text = button_font.render("What Application?", True, white_color)
root.blit(title_text, (165, 100))
paint_button_rect = pygame.draw.rect(root, '#006EE6', pygame.Rect(70,200,200,90))
paint3d_button_rect = pygame.draw.rect(root, '#006EE6', pygame.Rect(430,200,200,90))
paint_button_text = button_font.render("Paint", True, white_color)
root.blit(paint_button_text, (120, 225.5))
paint3d_button_text = button_font.render("Paint 3D", True, white_color)
root.blit(paint3d_button_text, (447, 225.5))
# Control panel Program Select Screen Input /// And Variables for Mouse positions and inputs.
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_l, mouse_m, mouse_r = pygame.mouse.get_pressed()
print(mouse_x, mouse_y)
while ctrlpanel_run:
pygame.display.flip()
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_l, mouse_m, mouse_r = pygame.mouse.get_pressed()
print(mouse_x, mouse_y)
for event in pygame.event.get():
if event.type == pygame.QUIT:
ctrlpanel_run = False
break
if ctrlpanel_program_select_input == True:
if mouse_x > 69 and mouse_x < 270:
if mouse_y > 199 and mouse_y < 290:
if mouse_l:
subprocess.call(["cmd", "/c", "start", "/max", "C:\Windows\System32\mspaint.exe"])
You know the problem already, as you state in your question. The solution is to stop checking for the mouse click as long as mouse_l == True. So something like this:
Initialize a click_detected boolean variable before your main loop. Then inside the loop:
if ctrlpanel_program_select_input == True:
if mouse_x > 69 and mouse_x < 270:
if mouse_y > 199 and mouse_y < 290:
if mouse_l:
click_detected = True
if not mouse_l and click_detected:
click_detected = False
subprocess.call(["cmd", "/c", "start", "/max", "C:\Windows\System32\mspaint.exe"])
This should open the application when you let go of the button, instead of when you press the button.
Instead of checking the state of mouse buttons, you could use events generated by pressing or releasing the buttons.
You've already defined Rects for your buttons, so you can use collidepoint() to see if the mouse was clicked in the button.
for event in pygame.event.get():
if event.type == pygame.QUIT:
ctrlpanel_run = False
break
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # Left-click
if paint_button_rect.collidepoint(event.pos):
subprocess.call(["cmd", "/c", "start", "/max", r"C:\Windows\System32\mspaint.exe"])
elif paint3d_button_rect.collidepoint(event.pos)
# launch Paint 3D
This is my python code, using pygame. When I pressed my mouse down, scene 1 does not switch to scene 2. I am coming from Code HS, so the scene switch is from the Tell A Story project. I realized that code is not the same as pygame's. So I used pygame docs and see what I can learn from that, but nothing still. Please can any one help me. Thank you.
import pygame as pg
pg.init()
win = pg.display.set_mode((500,500))
pg.display.set_caption('Scene Switcher')
center_x = 250 - 130
center_y = 250
black= (0,0,0)
red = (255,0,0)
blue = (0,0,255)
def ct(font, size, text, color):
mf = pg.font.Font(font, size)
t = mf.render(text, True, color)
return t
def draw_scene1():
print("This is Scene 1")
txt = ct("SB.ttf", 40, "Hello World!", black)
win.blit(txt, (center_x,center_y))
def draw_scene2():
print("This is scene 2")
txt2 = ct("SB.ttf", 40, "scene2 ", black)
win.blit(txt2, (center_x,center_y))
while True:
win.fill(red)
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
quit()
mouses = pg.mouse.get_pressed()
scene_counter = 0
# When this function is called the next scene is drawn.
def draw_next_screen():
global scene_counter
scene_counter += 1
if scene_counter == 1:
draw_scene1()
else:
draw_scene2()
if mouses:
draw_next_screen()
pg.display.update()
You have to initialize scene_counter before the application loop rather than in the application loop.
The pygame.mouse.get_pressed() returns a list of Boolean values that represent the state (True or False) of all mouse buttons. The state of a button is True as long as a button is held down. Therefor the scene_counter is continuously incremented in each frame as long a mouse button is hold down.
The MOUSEBUTTONDOWN event occurs once when you click the mouse button and the MOUSEBUTTONUP event occurs once when the mouse button is released. Increment the counter when the MOUSEBUTTONDOWN event occurs:
scene_counter = 0
run = True
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
elif event.type == pg.MOUSEBUTTONDOWN:
scene_counter += 1
win.fill(red)
if scene_counter == 0:
draw_scene1()
else:
draw_scene2()
pg.display.update()
pg.quit()
This question already has answers here:
Pygame mouse clicking detection
(4 answers)
Closed 1 year ago.
I am trying to make buttons using rect in Pygame. I started with the red quit button and checked if a click was inside the boundingbox of the button.
import pygame
"""import nemesis.py;"""
pygame.init();
screen = pygame.display.set_mode((400,300));
pygame.display.set_caption("menu");
menuAtivo = True;
start_button = pygame.draw.rect(screen,(0,0,240),(150,90,100,50));
continue_button = pygame.draw.rect(screen,(0,244,0),(150,160,100,50));
quit_button = pygame.draw.rect(screen,(244,0,0),(150,230,100,50));
pygame.display.flip();
while menuAtivo:
for evento in pygame.event.get():
print(evento);
if evento.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pos() >= (150,230):
if pygame.mouse.get_pos() <= (250,280):
pygame.quit();
When using rects in pygame, it's best to use the in built collision detection.
here is an example code on how to do it hope it helps you solve your problem.
Before that though i'd like to mention you should render/draw your objects withing the while loop or the wont show up.
import pygame
import sys
def main():
pygame.init()
clock = pygame.time.Clock()
fps = 60
size = [200, 200]
bg = [255, 255, 255]
screen = pygame.display.set_mode(size)
button = pygame.Rect(100, 100, 50, 50) # creates a rect object
# The rect method is similar to a list but with a few added perks
# for example if you want the position of the button you can simpy type
# button.x or button.y or if you want size you can type button.width or
# height. you can also get the top, left, right and bottom of an object
# with button.right, left, top, and bottom
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos # gets mouse position
# checks if mouse position is over the button
if button.collidepoint(mouse_pos):
# prints current location of mouse
print('button was pressed at {0}'.format(mouse_pos))
screen.fill(bg)
pygame.draw.rect(screen, [255, 0, 0], button) # draw button
pygame.display.update()
clock.tick(fps)
pygame.quit()
sys.exit
if __name__ == '__main__':
main()
Another good way to create buttons on pygame (in python) is by installing the package called pygame_widgets (pip3 install pygame_widgets) on Mac or Linux and (pip install pygame_widgets) on Windows. And also make sure you have pip installed otherwise, it is not going to work.
# Importing Modules
import pygame as pg
import pygame_widgets as pw
# creating screen
pg.init()
screen = pg.display.set_mode((800, 600))
running = True
button = pw.Button(
screen, 100, 100, 300, 150, text='Hello',
fontSize=50, margin=20,
inactiveColour=(255, 0, 0),
pressedColour=(0, 255, 0), radius=20,
onClick=lambda: print('Click')
)
while running:
events = pg.event.get()
for event in events:
if event.type == pg.QUIT:
running = False
button.listen(events)
button.draw()
pg.display.update()
Hope this helps you.
TKS GUYS,
Here is my answer :
import pygame
pygame.init();
screen = pygame.display.set_mode((400,300));
pygame.display.set_caption("menu");
menuAtivo = True;
start_button = pygame.draw.rect(screen,(0,0,240),(150,90,100,50));
continue_button = pygame.draw.rect(screen,(0,244,0),(150,160,100,50));
quit_button = pygame.draw.rect(screen,(244,0,0),(150,230,100,50));
pygame.display.flip();
def startGame():
screen.fill((0,0,0));
pygame.display.flip();
import nemesis.py;
while menuAtivo:
for evento in pygame.event.get():
print(evento);
if evento.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pos()[0] >= 150 and pygame.mouse.get_pos()[1] >= 230:
if pygame.mouse.get_pos()[0] <= 250 and pygame.mouse.get_pos()[1] <= 280:
pygame.quit();
if pygame.mouse.get_pos()[0] >= 150 and pygame.mouse.get_pos()[1] >= 90:
if pygame.mouse.get_pos()[0] <= 250 and pygame.mouse.get_pos()[1] <= 140:
startGame();
I think the main problem in your code is that you compare pygame.mouse.get_pos() directly with a Tuple, which is ambiguous. You should try testing x then y separately:
while menuAtivo:
for evento in pygame.event.get():
print(evento);
if evento.type == pygame.MOUSEBUTTONDOWN:
if pygame.mouse.get_pos()[0] >= 150 and pygame.mouse.get_pos()[1] >= 230:
if pygame.mouse.get_pos()[0] <= 250 and pygame.mouse.get_pos()[1] <= 280:
pygame.quit();
I have already provided an answer on the above. Here is my another answer without the module pygame_widgets:
import pygame
import sys
# initializing the constructor
pygame.init()
# screen resolution
res = (720,720)
# opens up a window
screen = pygame.display.set_mode(res)
# white color
color = (255,255,255)
# light shade of the button
color_light = (170,170,170)
# dark shade of the button
color_dark = (100,100,100)
# stores the width of the
# screen into a variable
width = screen.get_width()
# stores the height of the
# screen into a variable
height = screen.get_height()
# defining a font
smallfont = pygame.font.SysFont('Corbel',35)
# rendering a text written in
# this font
text = smallfont.render('quit' , True , color)
while True:
for ev in pygame.event.get():
if ev.type == pygame.QUIT:
pygame.quit()
#checks if a mouse is clicked
if ev.type == pygame.MOUSEBUTTONDOWN:
#if the mouse is clicked on the
# button the game is terminated
if width/2 <= mouse[0] <= width/2+140 and height/2 <= mouse[1] <= height/2+40:
pygame.quit()
# fills the screen with a color
screen.fill((60,25,60))
# stores the (x,y) coordinates into
# the variable as a tuple
mouse = pygame.mouse.get_pos()
# if mouse is hovered on a button it
# changes to lighter shade
if width/2 <= mouse[0] <= width/2+140 and height/2 <= mouse[1] <= height/2+40:
pygame.draw.rect(screen,color_light,[width/2,height/2,140,40])
else:
pygame.draw.rect(screen,color_dark,[width/2,height/2,140,40])
# superimposing the text onto our button
screen.blit(text , (width/2+50,height/2))
# updates the frames of the game
pygame.display.update()
Hope This Helps if pygame_widgets (pip install pygame_widgets) module could not be installed in your python version.
this is my solution
class button():
def __init__(self, color, x,y,width,height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self,win,outline=None):
#Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
pygame.draw.rect(win, self.color, (self.x,self.y,self.width,self.height),0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 60)
text = font.render(self.text, 1, (0,0,0))
win.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))
def isOver(self, pos):
#Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
return False
I am trying to create a menu screen for my game. At the moment im using sprites for buttons and everything works well, and I can create an infinite amount of buttons (currently I just have Start and Options), but only the first button I call appears on the screen. I think it has something to do with the while loop in the button class but I am not sure on how to fix it. I am probably making no sense here so if you need me to clarify anything I will. Thanks!
import pygame
import random
import time
pygame.init()
#colours
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,155,0)
blue = (50,50,155)
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Numeracy Ninjas')
clock = pygame.time.Clock()
img_button_start = pygame.image.load('Sprites/Buttons/button_start.png')
img_button_options = pygame.image.load('Sprites/Buttons/button_options.png')
gameDisplay.fill(white)
class Button(pygame.sprite.Sprite):
def __init__(self, sprite, buttonX, buttonY):
super().__init__()
gameDisplay.blit(sprite, (buttonX, buttonY))
pygame.display.update()
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
print(x, y)
if x <= (150 + buttonX) and x >=(0 + buttonX) and y <= (75 + buttonY) and y >= (0 + buttonY):
print('clicked on button')
def gameIntro():
button_start = Button(img_button_start, 27, 0)
button_options = Button(img_button_options, 27, 500)
gameIntro()
In the constructor of your Button class, you have an infinite loop. This means you never get to the code part where you make your second Button.
def gameIntro():
button_start = Button(img_button_start, 27, 0) #stuck in infinite loop
print('This print statement is never reached')
button_options = Button(img_button_options, 27, 500)
Instead, what you want to do is initialize two Buttons, and then have a main game loop in your gameIntro() method that checks for events. If a mousebuttondown event occured, you want to pass the event (or even just the event position, if you don't care which mouse button was clicked) to a function of button that checks whether this instance of button was clicked and then handles the input (possibly by returning something which you handle in the main game loop).
Note that I haven't run the following code, I'm just trying to give you an idea how it should be structured:
class Button(pygame.sprite.Sprite):
def __init__(self, image, buttonX, buttonY):
super().__init__()
self.image = image
self.rect = image.getRect()
self.rect.x = buttonX
self.rect.y = buttonY
def wasClicked(event):
if self.rect.collidepoint(event.pos):
return True
def gameIntro():
#initialize buttons
buttons = pygame.sprite.Group() #make a group to make drawing easier
button_start = Button(img_button_start, 27, 0)
button_options = Button(img_button_options, 27, 500)
#draw buttons to display
buttons.draw(gameDisplay)
pygame.display.update()
#main game loop
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
#check for every button whether it was clicked
for btn in buttons:
if btn.wasClicked():
#do something appropriate
if event.type == pygame.QUIT:
pygame.quit()
I want to create a pygame window that doesn't have a frame and that moves when the user clicks on it and moves the mouse.
I tried this script but when I click on the windows, '0' is printed but not '1'
Something is wrong in my script.
# coding : utf-8
import pygame
from pygame.locals import *
from random import randint
from os import environ
from math import sqrt
pygame.init()
max_fps = 250
clock = pygame.time.Clock()
window_size_x, window_size_x = 720, 360
infos = pygame.display.Info()
environ['SDL_VIDEO_WINDOW_POS'] = str(int(infos.current_w / 2)) + ',' + str(int(infos.current_h / 2)) # center the window
screen = pygame.display.set_mode((window_size_x, window_size_x), pygame.NOFRAME)
def move_window(): # move the windows when custom bar is hold
window_x, window_y = eval(environ['SDL_VIDEO_WINDOW_POS'])
mouse_x, mouse_y = pygame.mouse.get_pos()
dist_x , dist_y = mouse_x - window_x, mouse_y - window_y # calculate the distance between mouse and window origin
for event in pygame.event.get():
if event.type != MOUSEBUTTONUP: # while bar is hold
print('1')
mouse_x, mouse_y = pygame.mouse.get_pos()
environ['SDL_VIDEO_WINDOW_POS'] = str(mouse_x - dist_x) + ',' + str(mouse_x - dist_x)
screen = pygame.display.set_mode((window_size_x, window_size_x), pygame.NOFRAME) # rebuild window
def main():
run = True
while run :
screen.fill((255, 255, 255))
pygame.display.update()
clock.tick(60) # build frame with 60 frame per second limitation
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
print('0')
move_window()
if __name__ == '__main__':
main()
Write a function, which moves the window from dependent on a previous mouse position (start_x, start_y) and a mouse position (new_x, new_y)
def move_window(start_x, start_y, new_x, new_y):
global window_size_x, window_size_y
window_x, window_y = eval(environ['SDL_VIDEO_WINDOW_POS'])
dist_x, dist_y = new_x - start_x, new_y - start_y
environ['SDL_VIDEO_WINDOW_POS'] = str(window_x + dist_x) + ',' + str(window_y + dist_y)
# Windows HACK
window_size_x += 1 if window_size_x % 2 == 0 else -1
screen = pygame.display.set_mode((window_size_x, window_size_y), pygame.NOFRAME)
In this function is a very important line:
window_size_x += 1 if window_size_x % 2 == 0 else -1
this line changes the width of the window from alternately by +1 and -1. On Windows systems there seems to be a bug, which ignores the new position parameter, if the size of the window didn't change.
This "hack" is a workaround, which slightly change the size of the window whenever the position is changed.
A different approach, with no flickering, may look as follows. Note, though, that this version is significantly slower:
def move_window(start_x, start_y, new_x, new_y):
global window_size_x, window_size_y
buffer_screen = pygame.Surface((window_size_x, window_size_y))
buffer_screen.blit(pygame.display.get_surface(), pygame.display.get_surface().get_rect())
window_x, window_y = eval(environ['SDL_VIDEO_WINDOW_POS'])
dist_x, dist_y = new_x - start_x, new_y - start_y
environ['SDL_VIDEO_WINDOW_POS'] = str(window_x + dist_x) + ',' + str(window_y + dist_y)
window_size_x += 1 if window_size_x % 2 == 0 else -1
screen = pygame.display.set_mode((window_size_x, window_size_y), pygame.NOFRAME)
screen.blit(buffer_screen, buffer_screen.get_rect())
pygame.display.flip()
Change the position on MOUSEMOTION and MOUSEBUTTONUP:
def main():
run = True
pressed = False
start_pos = (0,0)
while run :
# [...]
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
pressed = True
start_pos = pygame.mouse.get_pos()
elif event.type == MOUSEMOTION:
if pressed:
new_pos = pygame.mouse.get_pos()
move_window(*start_pos, *new_pos)
pygame.event.clear(pygame.MOUSEBUTTONUP)
elif event.type == MOUSEBUTTONUP:
pressed = False
new_pos = pygame.mouse.get_pos()
move_window(*start_pos, *new_pos)
Full example program:
# coding : utf-8
import pygame
from pygame.locals import *
from os import environ
pygame.init()
clock = pygame.time.Clock()
window_size_x, window_size_y = 720, 360
infos = pygame.display.Info()
environ['SDL_VIDEO_WINDOW_POS'] = str(int(infos.current_w/2)) + ',' + str(int(infos.current_h/2))
screen = pygame.display.set_mode((window_size_x, window_size_x), pygame.NOFRAME)
def move_window(start_x, start_y, new_x, new_y):
global window_size_x, window_size_y
window_x, window_y = eval(environ['SDL_VIDEO_WINDOW_POS'])
dist_x, dist_y = new_x - start_x, new_y - start_y
environ['SDL_VIDEO_WINDOW_POS'] = str(window_x + dist_x) + ',' + str(window_y + dist_y)
window_size_x += 1 if window_size_x % 2 == 0 else -1
screen = pygame.display.set_mode((window_size_x, window_size_y), pygame.NOFRAME)
def main():
run = True
pressed = False
start_pos = (0,0)
while run :
screen.fill((255, 255, 255))
pygame.display.update()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
if event.type == MOUSEBUTTONDOWN:
pressed = True
start_pos = pygame.mouse.get_pos()
elif event.type == MOUSEMOTION:
if pressed:
new_pos = pygame.mouse.get_pos()
move_window(*start_pos, *new_pos)
pygame.event.clear(pygame.MOUSEBUTTONUP)
elif event.type == MOUSEBUTTONUP:
pressed = False
new_pos = pygame.mouse.get_pos()
move_window(*start_pos, *new_pos)
if __name__ == '__main__':
main()
This solution no longer works under Windows systems and with Pygame 2.0. The position of a window can, however, be changed with the WINAPI function MoveWindow:
import pygame
from ctypes import windll
pygame.init()
screen = pygame.display.set_mode((400, 400), pygame.NOFRAME)
clock = pygame.time.Clock()
def moveWin(new_x, new_y):
hwnd = pygame.display.get_wm_info()['window']
w, h = pygame.display.get_surface().get_size()
windll.user32.MoveWindow(hwnd, new_x, new_y, w, h, False)
window_pos = [100, 100]
moveWin(*window_pos)
run = True
while run :
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
elif event.type == pygame.MOUSEMOTION:
if pygame.mouse.get_pressed()[0]:
window_pos[0] += event.rel[0]
window_pos[1] += event.rel[1]
moveWin(*window_pos)
screen.fill((255, 255, 255))
pygame.display.update()
clock.tick(60)
This code use only one for event loop with MOUSEBUTTONDOWN to set moving = True, MOUSEBUTTONUP to set moving = False and MOUSEMOTION which changes window's position when moving is True.
After move I use pygame.event.clear(pygame.MOUSEBUTTONUP) to remove this type of events because new window was getting this even and it was stoping window.
import pygame
from os import environ
# --- constants --- (UPPER_CASE_NAMES)
WINDOW_WIDTH = 720
WINDOW_HEIGHT = 360
# --- main ---
def main():
pygame.init()
infos = pygame.display.Info()
environ['SDL_VIDEO_WINDOW_POS'] = '{},{}'.format(infos.current_w//2, infos.current_h//2) # center the window
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.NOFRAME)
moving = False
clock = pygame.time.Clock()
run = True
while run:
screen.fill((255, 255, 255))
pygame.display.update()
clock.tick(60) # build frame with 60 frame per second limitation
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if not moving:
print('MOUSEBUTTONDOWN')
moving = True
# remeber start distance
#window_x, window_y = eval(environ['SDL_VIDEO_WINDOW_POS'])
window_x, window_y = map(int, environ['SDL_VIDEO_WINDOW_POS'].split(','))
dist_x = event.pos[0] # mouse x
dist_y = event.pos[1] # mouse y
elif event.type == pygame.MOUSEBUTTONUP:
if moving:
print('MOUSEBUTTONUP')
moving = False
elif event.type == pygame.MOUSEMOTION:
if moving:
print('moving')
mouse_x, mouse_y = pygame.mouse.get_pos()
diff_x = dist_x - mouse_x
diff_y = dist_y - mouse_y
window_x -= diff_x
window_y -= diff_y
environ['SDL_VIDEO_WINDOW_POS'] = "{},{}".format(window_x, window_y)
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), pygame.NOFRAME) # rebuild window
pygame.event.clear(pygame.MOUSEBUTTONUP) # to remove MOUSEBUTTONUP event which stops moving window
if __name__ == '__main__':
main()
The code's not ready, but I was getting there.
I had to abandon it, but it might help someone save some time.
Press f for full-screen mode. The part that is not done,
supposed to be the window-mode resize part. You must have an in-depth
look at toogle_resize() function for that.
The resize it's taking full desktop resolution and compare it
to the space between clik (MOUSEBUTTONDOWN) and (MOUSEBUTTONUP).
Or at least that's how I wanted it to work. Good luck!
Also the code needs to be optimized, it is raw.
import pyautogui
import pygame
import sys
from pygame.locals import *
from pyinput.mouse import Controller
Mouse controller gets the position on desktop, but I had to run it once more inside the while loop to get the updated values.
mouse = Controller()
standard = current_mouse_position = mouse.position
pygame.init()
Silkscreen = False
blueGray = (73, 111, 135)
width, height = pyautogui.size()
w = width / 4
h = height / 4
ww = width - w
hh = height - h
wi = ww - 4
hi = hh - 4
Set the background and the flags
room = pygame.image.load('img.png')
full_flags = pygame.FULLSCREEN | pygame.SCALED |
pygame.NOFRAME
normal_flags = pygame.NOFRAME | pygame.RESIZABLE |
pygame.SCALED
def toggle_fullscreen(f):
if f:
return pygame.display.set_mode((ww, hh), full_flags)
# pygame.display.set_mode(size, normal_flags) # uncomment
this to see issue being fixed as a workaround
return pygame.display.set_mode((ww, hh), normal_flags)
def toggle_resize(click):
if click:
return pygame.display.set_mode((ww + movement, hh),
normal_flags) # Expands by resize_y
# Set up the drawing window
screen = pygame.display.set_mode((ww, hh), normal_flags)
def bg():
screen.blit(room, (0, 0))
def border():
pygame.draw.rect(screen, blueGray, (0, 0, ww, hh), 2) #
width = 3
clock = pygame.time.Clock()
# Run until the user asks to quit
running = True
while running:
current_mouse_position = mouse.position
# print(current_mouse_position[0])
bg()
mw, mh = pygame.mouse.get_pos() # 0 - 1439(window size)
In the next line, I checked if the mouse is on the window border. Apply only to the left, right border. You must create code for the top, bottom border. Left, right borders, 3 pixels range each side.
if mw <= 3 or (mw > wi and mw < ww):
active = True
moveOne = 0
# print("data", moveOne)
# print(type(moveOne))
moveTwo = 0
# event handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
sys.exit()
# print(mw, mh)
If the user clicks, the standard variable at the beginning of the code it gets the mouse current position. You must run the active bool and check if it is True if you want to start resizing from the border of the window.
The code is very complicated and needs some optimization, but I bet you gonna get it right. Good luck!;)
if event.type == pygame.MOUSEBUTTONDOWN:
standard = current_mouse_position[0]
print(standard)
if event.type == pygame.MOUSEBUTTONUP:
moveTwo = current_mouse_position[0]
movement = standard - moveTwo
print("This is:", moveTwo)
toggle_resize(click=MOUSEBUTTONUP)
active = False
Full-screen handler from here down. Press f for full screen and back to window mode.
if event.type == pygame.KEYDOWN:
Silkscreen = not Silkscreen
if event.key == K_f:
screen = toggle_fullscreen(Silkscreen)
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
border()
# Flip the display
pygame.display.flip()
clock.tick(144) # framerate
# Done! Time to quit.
pygame.quit()'
Here is a version of #Rabbid76's answer for Pygame 2. Note that this example may break as the module _sdl2.video, used to set the window position, is experimental.
move_window.py
import pygame
from pygame._sdl2.video import Window
start_pos = pygame.Vector2(0, 0) #Initial mouse position
pressed = False #Flag that denotes when the mouse is being continuously pressed down
def move_window(window : Window, start_mouse_pos : pygame.Vector2, new_mouse_pos : pygame.Vector2) -> None:
"""Moves the window by the offset between start_mouse_pos and new_mouse_pos"""
screen = pygame.display.get_surface()
buffer_screen = pygame.Surface((window.size[0], window.size[1]))
buffer_screen.blit(screen, screen.get_rect())
window_pos_Vec2 = pygame.Vector2(window.position)
window.position = window_pos_Vec2 + new_mouse_pos - start_mouse_pos
screen.blit(buffer_screen, buffer_screen.get_rect())
pygame.display.flip()
def check_event(window : Window, event : pygame.event, move_area : pygame.Rect = pygame.Rect(-1, -1, 1, 1)) -> None:
"""Takes a window and event and updates the window position accordingly. \n
move_area can be used to set what area of the screen can be clicked in order to move the window. \n
move_area defaults to a dummy rect which is then internally changed to the full window."""
global start_pos, pressed
if move_area == pygame.Rect(-1, -1, 1, 1):
move_area = pygame.Rect((0, 0), window.size)
mouse_pos = pygame.Vector2(pygame.mouse.get_pos())
if move_area.collidepoint(mouse_pos):
if event.type == pygame.MOUSEBUTTONDOWN:
pressed = True
start_pos = mouse_pos
elif event.type == pygame.MOUSEMOTION and pressed:
move_window(window, start_pos, mouse_pos)
elif event.type == pygame.MOUSEBUTTONUP:
pressed = False
move_window(window, start_pos, mouse_pos)
else:
pressed = False
And in your main file:
import pygame
from pygame._sdl2.video import Window
screen = pygame.display.set_mode(...)
window = Window.from_display_module()
#...
while True:
for event in pygame.event.get():
#...
move_window.check_event(window, event)