用户单击时如何移动无边框pygame窗口?

时间:2019-08-27 11:55:43

标签: python pygame python-3.7

我会创建一个没有框架的pygame窗口,但是当用户单击它并移动鼠标时该窗口会移动。 所以我尝试了这个脚本,但是当我单击窗口时,打印的是“ 0”,而不是“ 1”

但是我的脚本有问题

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

3 个答案:

答案 0 :(得分:3)

编写一个函数,该函数根据先前的鼠标位置(start_xstart_y)和鼠标位置(new_xnew_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_x), pygame.NOFRAME)

在此功能中非常重要的一行:

window_size_x += 1 if window_size_x % 2 == 0 else -1

此行将窗口的宽度从+1和-1交替更改。在Windows系统上,如果窗口的大小没有变化,则似乎有一个错误会忽略新的position参数。
此“ hack”是一种解决方法,每当更改位置时,它都会略微更改窗口的大小。

更改MOUSEMOTIONMOUSEBUTTONUP上的位置:

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)

完整的示例程序:

# coding : utf-8
import pygame
from pygame.locals import *
from os import environ
pygame.init()

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

答案 1 :(得分:2)

此代码仅使用一个for event循环和MOUSEBUTTONDOWN来设置moving = TrueMOUSEBUTTONUP来设置moving = FalseMOUSEMOTION来改变窗口的位置当movingTrue时。

移动后,我使用pygame.event.clear(pygame.MOUSEBUTTONUP)删除了此类事件,因为新窗口使此事件变得均匀并且正在停止窗口。

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

答案 2 :(得分:0)

这里是@ Rabbid76对Pygame 2的回答的一个版本。请注意,此示例可能会中断,因为用于设置窗口位置的模块_sdl2.video是实验性的。
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

在主文件中:

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)