代码运行正常,正如我预期的那样,但 5 秒后图形显示永远卡住。它没有显示任何错误,什么也没有,只是停止响应。

这是一个模拟一大群物体运动的程序。他们必须像布朗运动一样漫无目的地随机移动。为了做到这一点,我使用 Pygame 将任何对象绘制为随机位置的矩形,为了移动它们,我删除所有内容并再次绘制它们,它们的位置随机改变 1。
我正在使用 pygame 来显示图形。
您能否还为这个问题提出更好的解决方案?

import pygame, random, sys, time, numpy
from pygame.locals import *

black = (0,0,0)
white = (255,255,255)

clock = pygame.time.Clock()

class people():

    def __init__(self):

        screen = pygame.display.get_surface()

        self.x = random.randint(0, 800)
        self.y = random.randint(0, 600)

    def move(self):
        self.x += random.randint(-1, 1)
        self.y += random.randint(-1, 1)
        if self.x < 0:
            self.x = 0
        if self.x > 800:
            self.x = 800
        if self.y < 0:
            self.y = 0
        if self.y > 600:
            self.y = 600

    def place(x, y):
        screen = pygame.display.get_surface()
        pygame.draw.rect(screen, black, [x, y, 10, 10])

def main():
    # Initialise screen
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    pygame.display.set_caption('Test')

    peoples = []

    chosepopul = 1

    while chosepopul == 1:
        try:
            population = abs(int(input("How many people would you like to have")))
            chosepopul = 0
        except:
            print("Number, please")

    for i in range(population):
        peoples.append(people())

    while True:

        screen.fill(white)

        for obj in peoples:

            people.place(obj.x, obj.y)

            people.move(obj)

        pygame.display.update()
        clock.tick(60)

if __name__ == '__main__':
    main()

pygame.quit()
quit()

一切都按我的预期工作,但不可避免地会卡住。

更新: 如果我将输入脚本更改为常量数字,则一切正常。所以这个问题在某种程度上与用户界面交互有关。

最佳答案

程序停止是因为 input() 阻塞了程序流。不再发送和处理 PyGame 更新或事件。基本上一切都会停止,等待用户输入。

解决这个问题的最好方法是编写代码,让用户在屏幕上而不是在控制台中进行一些 PyGame 输入。也许制作一个滑块或微调控件来选择数字,或者加号/减号按钮,等等。

或者,程序仍然可以在线程中使用控制台输入,该线程使用 post() 函数将结果发送到主 PyGame 事件循环线程。

我必须承认,这个答案仅具有学术意义,因为使用控制台与 PyGame 窗口一起输入非常难看!

无论如何,这里有一些代码。主 python 窗口每 0.5 秒简单地改变颜色,而用户可以使用标准的 python input() 函数在控制台中输入文本。代码使用它自己的事件枚举类型来发布消息,但这些也可以只是普通数字。

根据 OP,这是有效的,因为 input() 函数是在执行子线程内调用的。这使主线程可以自由地继续处理 PyGame 事件队列,并将更新绘制到窗口。只有一个事件队列/循环很重要(出于超出本答案范围的原因),因此子线程将事件“发布”回主线程,而不是作用于窗口/事件本身。

import threading
import pygame
import enum

# Window size
WINDOW_WIDTH  = 200
WINDOW_HEIGHT = 200

DARK    = (  50, 50, 50 )
WHITE   = ( 255,255,255 )
RED     = ( 255, 55, 55 )
GREEN   = (   5,255, 55 )
BLUE    = (   5, 55,255 )


colour_cycle = [ DARK, WHITE, RED, GREEN, BLUE ]


class UserEvents( enum.IntEnum ):
    CLIENT_NUMBER = pygame.USEREVENT + 1
    CLIENT_QUIT   = pygame.USEREVENT + 2
    # ...



class ConsoleInputThread( threading.Thread ):
    """ A thread that handles user input on the console.
        Waits for user input, then posts messages
        to the main PyGame thread for processing """
    def __init__( self, prompt ):
        threading.Thread.__init__(self)
        self.daemon         = True # exit with parent
        self.done           = False
        self.prompt         = prompt

    def stop( self ):
        self.done = True

    def run( self ):
        """ Loops until the user hangs-up """
        while ( not self.done ):
            # Get some input from the user
            user_input = input( self.prompt ).strip()
            new_event = None
            if ( user_input == 'quit' ):
                new_event = pygame.event.Event( UserEvents.CLIENT_QUIT, { } )
            else:
                try:
                    user_input = int( user_input )
                    new_event = pygame.event.Event( UserEvents.CLIENT_NUMBER, { "value":user_input } )
                except:
                    print( "Syntax Error" )
            # If we received valid input post it to the main thread
            if ( new_event ):
                pygame.event.post( new_event )




###
### MAIN
###

# Create the window
pygame.init()
pygame.display.set_caption("Socket Messages")
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
WINDOW  = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )


# Start the console-input thread
input_thread = ConsoleInputThread( "How many people would you like to have: " )
input_thread.start()

# Main paint / update / event loop
done = False
clock = pygame.time.Clock()
colour_index = 0
while ( not done ):

    for event in pygame.event.get():
        if ( event.type == pygame.QUIT ):
            done = True

        elif ( event.type == UserEvents.CLIENT_QUIT ):
            print("\nCLIENT ASKED TO QUIT " )
            done = True

        elif ( event.type == UserEvents.CLIENT_NUMBER ):
            print( "\nVALUE WAS INPUT: %d " % ( event.value, ) )


    WINDOW.fill( colour_cycle[colour_index] )
    # rotate the colours, just so the screen changes
    colour_index += 1
    if ( colour_index >= len( colour_cycle ) ):
        colour_index = 0

    pygame.display.flip()

    clock.tick_busy_loop(2)  # NOTE: 2 frames per second, no flashy-flashy

input_thread.stop()
pygame.quit()

关于python - 为什么图形窗口在大约 5 秒后卡住?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57718723/

10-13 08:12
查看更多