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
Related
This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
So I'm kinda new at Pygame, and just trying to create easy projects to learn.
I've created a basic rectangle first as player, and I want to implement a system where user clicks to somewhere in screen and game spawns a rectangle at that point. Here's my code:
import pygame
import sys
from pygame import *
from pygame.mouse import get_pos
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
pygame.display.set_caption("Touch To Create Blocks!")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((50,50))
self.surf.fill((220,120,37))
self.rect = self.surf.get_rect()
def update(self,pressed_keys):
if pressed_keys[pygame.K_UP]:
self.rect.move_ip(0,-5)
elif pressed_keys[pygame.K_DOWN]:
self.rect.move_ip(0,5)
elif pressed_keys[pygame.K_LEFT]:
self.rect.move_ip(-5,0)
elif pressed_keys[pygame.K_RIGHT]:
self.rect.move_ip(5,0)
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
elif self.rect.top <= 0:
self.rect.top = 0
elif self.rect.top >= SCREEN_HEIGHT - 50:
self.rect.bottom = SCREEN_HEIGHT
player = Player()
run = True
while run:
for event in pygame.event.get():
if event.type == QUIT:
run = False
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
rectangle = pygame.Rect(mouse_x, mouse_y, 40, 40)
pygame.draw.rect(screen, (255,255,255) , rectangle)
pygame.display.update()
screen.fill((0,0,0))
pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
screen.blit(player.surf,player.rect)
pygame.display.update()
With that code, when I click, a block spawns and disappears immediately. How do I fix this? Thanks for your help.
(Sorry for my bad English)
The problem is that when the user clicks you draw the rectangle
(pygame.draw.rect), update the display (pygame.display.update) and
then, after the for loop, you empty the display
(screen.fill((0,0,0))). This explains why the rectangle disappears
immediately.
Instead of calling pygame.draw.rect each time the user clicks on the
screen, you can instead memorise the rectangle and save it into a
list. Then you have can draw all rectangles you memorised at each
iteration of your main loop.
Here is an implementation of this solution (I have added comments in
the code):
import pygame
import sys
from pygame import *
from pygame.mouse import get_pos
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
pygame.display.set_caption("Touch To Create Blocks!")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((50,50))
self.surf.fill((220,120,37))
self.rect = self.surf.get_rect()
def update(self,pressed_keys):
if pressed_keys[pygame.K_UP]:
self.rect.move_ip(0,-5)
elif pressed_keys[pygame.K_DOWN]:
self.rect.move_ip(0,5)
elif pressed_keys[pygame.K_LEFT]:
self.rect.move_ip(-5,0)
elif pressed_keys[pygame.K_RIGHT]:
self.rect.move_ip(5,0)
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
elif self.rect.top <= 0:
self.rect.top = 0
elif self.rect.top >= SCREEN_HEIGHT - 50:
self.rect.bottom = SCREEN_HEIGHT
player = Player()
run = True
rectangles = list() # list of the rectangles we have to draw
while run:
for event in pygame.event.get():
if event.type == QUIT:
run = False
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
# add a new rectangle to our list of rectangles
mouse_x, mouse_y = pygame.mouse.get_pos()
rectangles.append(pygame.Rect(mouse_x, mouse_y, 40, 40))
screen.fill((0,0,0))
pressed_keys = pygame.key.get_pressed()
player.update(pressed_keys)
screen.blit(player.surf,player.rect)
# draw all the rectangles we memorised
for rectangle in rectangles:
pygame.draw.rect(screen, (255,255,255) , rectangle)
pygame.display.update()
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
import contextlib
with contextlib.redirect_stdout(None):
import pygame
import os
import time
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0,0,255)
z = 0
b = 0
h= 0
pygame.init()
image = []
path = 'E:\Andrew Photos'
pub= open("public.txt","w+")
now = open("nowhere.txt","w+")
sch = open("school.txt","w+")
files = []
for r, d, f in os.walk(path):
for file in f:
if '.jpg' in file:
files.append(os.path.join(r, file))
print (file)
public = []
school = []
nowhere = []
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode((0,0),pygame.FULLSCREEN)
x, y = screen.get_size()
pygame.display.set_caption("Testy Testerson")
# Loop until the user clicks the close button.
done = False
i =0
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
click = 0
# -------- Main Program Loop -----------
while not done:
x, y = screen.get_size()
while i < len(files):
mousex, mousey = pygame.mouse.get_pos()
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# if any mouse button is pressed pygame.MOUSEBUTTONUP
if event.type == pygame.MOUSEBUTTONUP:
click = 0
if event.type == pygame.MOUSEBUTTONDOWN:
# if the left button is pressed
if event.button == 1:
if mousex >= x-50:
if mousey <= 30:
exit(1)
pygame.quit()
done = True
if mousex >= x-300:
if mousey >= y-100:
nowhere.append(files[i])
now.write(files[i])
i = i +1
elif mousex <= 300:
if mousey >=y-100:
pub.write(files[i])
i = i+1
public.append(files[i-1])
elif mousex <=800:
if mousex >= 1100:
if mousey >= y-100:
school.append(files[i])
sch.write(files[i])
i = 1 +1
click = 1
if i == len(files):
pygame.QUIT()
# --- Game logic should go here
# --- Screen-clearing code goes here
# Here, we clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
# If you want a background image, replace this clear with blit'ing the
# background image.
screen.fill(WHITE)
if i >= len(files):
pygame.QUIT
#pygame.draw.rect(screen, RED,(x-50,0,50,30))
if i < len(files):
image = pygame.image.load(files[i])
screen.blit(image, (0,0))
pygame.draw.rect(screen, RED,(x-300,y-100,300,100))
pygame.draw.rect(screen, GREEN,(0,y-100,300,100))
pygame.draw.rect(screen, BLUE,(800,y-100,300,100))
# --- Drawing code should go here
# i = 0
# while i < len(files):
# image = pygame.image.load(files[i])
# screen.blit(image, (0,0))
# pygame.draw.rect(screen, RED,(x-300,y-100,300,100))
# pygame.display.flip()
# if mousex >= x-300:
# if mousey >= y-100:
# if click == 1:
# nowhere.append(files[i])
# time.sleep(1)
# if click == 0:
# i = i+1
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
# Close the window and quit.
clock.tick(60)
pygame.QUIT()
exit()
I am trying to make it so when you click the squares at the bottom, it adds to three separate text files the name of the file that went to each box, but im having some issues, and ive been able to figure out most of them, but cant fix them.
The first click does not work.
The blue rectangle does not function, at all
Nothing ends up in the files at all. I would settle for all of them in the same file with a header and a gap between lists.
Currently i am using 4 random JPG.s to do this, but the goal is to make it so i can sort 2,000 of them.
Alright. so i was in windowed mode instead of fullscreen, but i think the problem was a mistake in the if statements, you had a '<' around the wrong way
this works
if mousex >= x-300:
if mousey >= y-100:
print("red")
i = i +1
elif mousex <= 300:
if mousey >=y-100:
print("green")
i += 1
elif mousex >=500:
if mousex <= 800:
if mousey >= y-100: # this was also 1100 which doesnt help
print("blue")
i = 1 +1
i changed the locations of the buttons as they were going off my screen so this is what i had
pygame.draw.rect(screen, RED,(x-300,y-100,300,100))
pygame.draw.rect(screen, GREEN,(0,y-100,300,100))
pygame.draw.rect(screen, BLUE,(500,y-100,300,100))
I want to click these 2 circle balls and drag them to mouse current mouse position but it is not working.
I just want to click and drag the balls with mouse.
some codes was not added(import pygame,draw a display, colors etc.)
import pygame
window = pygame.display.set_mode((800,400))
clock = pygame.time.Clock()
##bg = pygame.image.load("bgpool.png")
##window.blit(bg,(0,0))
black = (0,0,0)
yellow = (255,255,0)
class Circle:
def __init__(self,x,y,color,radius):
self.x = x
self.y = y
self.color = color
self.radius = radius
pygame.draw.circle(window, color,(x,y),radius)
def quitgame():
pygame.quit()
quit()
def loop():
cikis = False
while not cikis:
for event in pygame.event.get():
if event.type == pygame.QUIT:
cikis = True
pygame.quit()
quit()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
bas = pygame.MOUSEBUTTONDOWN
window.fill((255,255,255))
main_circle = Circle(75,175,black,10)
aim_circle = Circle(375,175,yellow,10)
if click[0] == 1:
if mouse[0] >= main_circle.x and mouse[0] <= main_circle.x + main_circle.radius:
if mouse[1] >= main_circle.y and mouse[1] <= main_circle.y + main_circle.radius:
if click[0] == 1:
main_circle.x == mouse[0]
main_circle.y == mouse[1]
clock.tick(120)
pygame.display.update()
loop()
pygame.quit()
quit()
While click = pygame.mouse.get_pressed() works, it's very much recommended to use Pygame's events, like you have done for pygame.QUIT.
Because you didn't provide much code, I added the bare minimum to make the code runnable, and I commented every modification:
import pygame
pygame.init()
window = pygame.display.set_mode((700, 500))
class Circle:
def __init__(self, x, y, color, radius):
# Changed pos to contain both coordinates
self.pos = (x, y)
# Where the radius ends
self.x_boundary = (x - radius, x + radius)
self.y_boundary = (y - radius, y + radius)
self.color = color
self.radius = radius
def recalc_boundary(self):
# Recalculate the boundaries of the circle,
# this is needed whenever the circle is moved
self.x_boundary = (
self.pos[0] - self.radius, self.pos[0] + self.radius
)
self.y_boundary = (
self.pos[1] - self.radius, self.pos[1] + self.radius
)
# Single instantiation of our circle
# didn't add aim_circle because it is irrelevant
# in my answer
main_circle = Circle(75, 175, (255, 0, 0), 10)
# Small lambda function that'll take care of
# checking whether or not a point x is
# within two boundaries.
# This replaces your
# `if mouse[0] >= main_circle.x and mouse[0]
# <= main_circle.x + main_circle.radius:`
# lines
within = lambda x, low, high: low <= x <= high
# Boolean that attests to whether or not the
# user is clicking on our circle
selected = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# Test for MOUSEBUTTONDOWN events
elif event.type == pygame.MOUSEBUTTONDOWN:
# Left mouse button
if event.button == 1:
pos = pygame.mouse.get_pos()
# Check if the mouse is within
# our circle's limits, to see if the
# user is trying to click on it
if (
within(pos[0], *main_circle.x_boundary)
and within(pos[1], *main_circle.y_boundary)
):
selected = True
elif event.type == pygame.MOUSEBUTTONUP:
# User released mouse buttons
selected = False
if selected:
# Move to mouse position when selected,
# the circle 'follows' the mouse
main_circle.pos = pygame.mouse.get_pos()
main_circle.recalc_boundary()
window.fill((0, 0, 0))
# Moved this draw call to outside
# your class definition
pygame.draw.circle(
window, main_circle.color,
main_circle.pos,
main_circle.radius
)
pygame.display.update()
Note: it's a bad idea to instantiate a new Circle object each game loop iteration, this'll consume lots of CPU for nothing. I believe you've done that because you placed your circle draw calls inside it, but you should really just move it out into the loop.
I'm trying to move a rectangle inside of pygame, and making it scalable.
The scalable rectangle code is something like this then I tried to add an event like this:
from pygame imports *
init()
rect1 = (rect1x, rect1y, 300,300)
rect1x = 0
rect1y = 0
while running:
x,y = mouse.get_pos()
if rect1Pressed == True:
rect1x = x
rect1y = y
for evnt in event.get():
if evnt.type == QUIT:
running = False
if evnt.type == MOUSEBUTTONDOWN:
if evnt.button == 1:
if rect1.collidepoint(mouse.get_pos()):
rect1Pressed == True
How would i incorporate the scalable rectangle and being able to make it move with the mouse? So that the window will follow the mouse motion. So it kinda is like a on your laptop where your able to scale the window and also move it around.
You could check which mouse button is pressed in the elif event.type == pg.MOUSEMOTION: block, e.g. if event.buttons[0]:, and then either move or scale the rect depending on the button. To move the rect, just add the event.rel to the rect.x and rect.y attributes.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect1 = pg.Rect(100, 100, 161, 100)
rect2 = pg.Rect(300, 200, 161, 100)
selected_rect = None
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
for rect in (rect1, rect2):
if rect.collidepoint(event.pos):
selected_rect = rect # Select the colliding rect.
elif event.type == pg.MOUSEBUTTONUP:
selected_rect = None # De-select the rect.
elif event.type == pg.MOUSEMOTION:
if selected_rect is not None: # If a rect is selected.
if event.buttons[0]: # Left mouse button is down.
# Move the rect.
selected_rect.x += event.rel[0]
selected_rect.y += event.rel[1]
else: # Right or middle mouse button.
# Scale the rect.
selected_rect.w += event.rel[0]
selected_rect.h += event.rel[1]
selected_rect.w = max(selected_rect.w, 10)
selected_rect.h = max(selected_rect.h, 10)
screen.fill((30, 30, 30))
pg.draw.rect(screen, (0, 100, 250), rect1)
pg.draw.rect(screen, (0, 200, 120), rect2)
pg.display.flip()
clock.tick(30)
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)