为什么图形窗口在大约 5 秒后冻结? [英] Why does graphical window freeze after about 5 seconds?

查看:35
本文介绍了为什么图形窗口在大约 5 秒后冻结?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码运行正常,正如我所料,但 5 秒后图形显示永远冻结.它没有显示任何错误,什么也没有,只是停止响应.

Code is running correctly and as I expected but after 5 seconds the display for graphics freezes forever. It shows no error, nothing, just stops responding.

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

This is a program to simulate a movement of a large group of objects. They have to move randomly while aimless like Brownian motion. To make this I used Pygame to draw any object as a rectangle of random location, to move them I remove everything and draw them again with their location randomly changed by 1. I am using pygame to show graphics. Could you please also suggest a better solution for this problem?

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

一切都按我的预期工作,但不可避免地会冻结.

Everything is working as I expected but freezing inevitably.

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

UPDATE: If I change input script to constant number, everything is working correctly. So the problem is somehow linked with user interface interactions.

推荐答案

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

The program stops because the input() blocks the program flow. No further PyGame updates or events are sent & processed. Basically everything comes to a halt, waiting for the user to type.

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

The best way around this is to write code such that the user does some PyGame on-screen input, rather than in the console. Maybe make a slider or spinner-control to select the number, or plus/minus buttons, whatever.

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

Alternatively, the program can still use console input in a thread which uses the post() function to send the result to the main PyGame event-loop thread.

我必须承认,这个答案只是学术兴趣,因为使用控制台和 PyGame 窗口一起输入非常难看!

I must admit, this answer is of academic interest only, since using the console to input along with a PyGame window is pretty ugly!

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

Anyway, here is some code. The main python window simply changes colour every 0.5 seconds, while the user can input text in the console with the standard python input() function. The code uses it's own Event enumerated type for posting messages, but these could also just be plain numbers.

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

This works, as per the OP, because the input() function is called inside a sub-thread of execution. This leaves the main thread free to continually process the PyGame event queue, and paint updates to the window. It's important to only have a single event queue/loop (for reasons beyond the scope of this answer), so the sub-thread "posts" events back to the main thread, rather than acting on the window/events itself.

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

这篇关于为什么图形窗口在大约 5 秒后冻结?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆