How to move a no frame pygame windows when user click on it?

时光毁灭记忆、已成空白 提交于 2020-06-12 07:28:49

问题


i would create a pygame window that haven't frame but that move move when the user click on it and move the mouse. So I try this script but when I click on the windows, '0' printed but not '1'

But 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 # calcul the dictance 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()

回答1:


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()



回答2:


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()



回答3:


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)


来源:https://stackoverflow.com/questions/57674156/how-to-move-a-no-frame-pygame-windows-when-user-click-on-it

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!