如何修复 pygame 闪烁

How to fix pygame flicker

所以我决定尝试在 pygame 中制作一个应用程序,因为它比 tkinter 更复杂(它也帮助我已经使用了其中的一些)并且我遇到了一个问题,其中只有一部分我的文字在闪烁。 (不是屏幕上的所有文字只是其中的一部分)

一些环境信息:我在 windows 10 运行 python 3.7 on atom。我已经尝试找出问题所在,但无法找到问题的根源,我已经通过 运行 文件正常检查它是否是 atom,但这没有帮助。

import pygame
from winsound import Beep
from roundrects import aa_round_rect
from time import sleep, time
pygame.init()
pygame.font.init()
window_h = 725
window_w = 1300
bg_grey = (230, 230, 230)
button_grey = (190, 190, 190)
del_button_grey = (165, 165, 165)
white = (255, 255, 255)
black = (0, 0, 0)
normalfont = pygame.font.SysFont("Aileron", 30)
mediumfont = pygame.font.SysFont("Aileron", 60)
largefont = pygame.font.SysFont("Aileron", 70)
window = pygame.display.set_mode((window_w, window_h))
morse_keystrokes = []
class Button: # this class will be used to draw and interact with a Button.
    def __init__(self, x, y, w, h, color, border=0, round=False, text=None, Font=mediumfont, Font_Color=black):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.color = color
        self.border = border
        self.round = round
        self.text = text
        self.Font = Font
        self.Font_Color = Font_Color
        self.draw()
    def draw(self):
        if self.round == False:
            if self.border != 0:
                pygame.draw.rect(window, self.color, (self.x, self.y, self.w, self.h))
                pygame.draw.rect(window, black, (self.x, self.y, self.w, self.h), self.border)
                pygame.display.update()
            else:
                pygame.draw.rect(window, self.color, (self.x, self.y, self.w, self.h))
                pygame.display.update()
        elif self.round == True:
            if self.border != 0:
                aa_round_rect(window, (self.x, self.y, self.w, self.h), black, 30, self.border, self.color)
                pygame.display.update()
            else:
                aa_round_rect(window, (self.x, self.y, self.w, self.h), self.color, 30)
                pygame.display.update()
        if self.text != None:
            self.draw_text()

    def clicked(self):
        mouse = pygame.mouse.get_pos()
        if self.x + self.w > mouse[0] > self.x and self.y + self.h > mouse[1] > self.y:
            return True
        else:
            return False

    def draw_text(self):
        Label(self.text, self.x, self.y, self.w, self.h, self.Font, self.Font_Color)


class Typing_Box:
    def __init__(self, x, y, w, h, color, dbc, border=0, font=normalfont, typing_font=mediumfont, font_color=black):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.color = color
        self.dbc = dbc #delete button color
        self.border = border
        self.font = font
        self.typing_font = typing_font
        self.font_color = font_color
        self.draw()

    def draw(self):
        if self.border != 0:
            pygame.draw.rect(window, self.color, (self.x, self.y, self.w, self.h))
            pygame.draw.rect(window, black, (self.x, self.y, self.w, self.h), self.border)
            pygame.draw.rect(window, self.dbc, ((window_w-self.x)-(self.w/15), self.y, self.w/15, self.h))
            pygame.draw.rect(window, black, ((window_w-self.x)-(self.w/15), self.y, self.w/15, self.h), self.border)
        else:
            pygame.draw.rect(window, self.color, (self.x, self.y, self.w, self.h))
            pygame.draw.rect(window, self.dbc, ((window_w-self.x)-(self.w/15), self.y, self.w/15, self.h))
        Label("DEL", self.x, self.y, self.w, self.h, self.font, self.font_color, (((window_w-self.x)-(self.w/15)+((self.w/15)/2)), (self.y+(self.h/2))))
        Label("".join(morse_keystrokes), self.x, self.y, self.w, self.h, self.font, self.font_color, ((self.x+((self.w/2)-(self.w/15)+35)), (self.y+(self.h/2)-10)))

    def update(self):
        if self.border != 0:
            pygame.draw.rect(window, self.color, (self.x, self.y, self.w, self.h))
            pygame.draw.rect(window, black, (self.x, self.y, self.w, self.h), self.border)
            pygame.draw.rect(window, self.dbc, ((window_w-self.x)-(self.w/15), self.y, self.w/15, self.h))
            pygame.draw.rect(window, black, ((window_w-self.x)-(self.w/15), self.y, self.w/15, self.h), self.border)
        else:
            pygame.draw.rect(window, self.color, (self.x, self.y, self.w, self.h))
            pygame.draw.rect(window, self.dbc, ((window_w-self.x)-(self.w/15), self.y, self.w/15, self.h))
        Label("DEL", self.x, self.y, self.w, self.h, self.font, self.font_color, (((window_w-self.x)-(self.w/15)+((self.w/15)/2)), (self.y+(self.h/2))))
        Label("".join(morse_keystrokes), self.x, self.y, self.w, self.h, self.typing_font, self.font_color, ((self.x+((self.w/2)-(self.w/15)+35)), (self.y+(self.h/2)-10)))

    def clicked(self):
        mouse = pygame.mouse.get_pos()
        if ((window_w-self.x)-(self.w/15)) + self.w > mouse[0] > ((window_w-self.x)-(self.w/15)) and self.y + self.h > mouse[1] > self.y:
            return True
        else:
            return False


class Label:
    def __init__(self, msg, x, y, w, h, font, font_color=black, alternate_center=None):
        self.msg = msg
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.font = font
        self.font_color = font_color
        self.alternate_center = alternate_center
        self.draw()

    def render(self):
        textsurface = self.font.render(self.msg, True, self.font_color)
        return textsurface, textsurface.get_rect()

    def draw(self):
        textsurf, textrect = self.render()
        if self.alternate_center == None:
            textrect.center = ((self.x+(self.w/2)-3), (self.y+(self.h/2)))
        else:
            textrect.center = self.alternate_center
        window.blit(textsurf, textrect)
        pygame.display.update()


def Play_Beep(Type, box):
    if Type == 1:
        morse_keystrokes.append(".")
        box.update()
        Beep(800, 300)
    elif Type == 2:
        morse_keystrokes.append("_")
        box.update()
        Beep(800, 600)

def first_screen():
    window.fill(bg_grey)
    dit = Button(20, 40, 450, 250, button_grey, 2, True, "Dit")
    da = Button(20, 370, 450, 250, button_grey, 2, True, "Da")
    first_box = Typing_Box(150, 667, 1000, 55, button_grey, del_button_grey, 2)
    back = Button(-2, 677, 80, 50, button_grey, 2, False, "Back", normalfont)
    run = True
    while run:
        first_box.update()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if dit.clicked():
                    Play_Beep(1, first_box)
                elif da.clicked():
                    Play_Beep(2, first_box)
                elif first_box.clicked():
                    start = time()
                    global morse_keystrokes
                    morse_keystrokes = morse_keystrokes[:-1]

first_screen()

如有任何帮助,我们将不胜感激, TIA

这些文章会有所帮助。

Flickering dice image when i press my dice button.

Python Tkinter refresh canvas

以下是对tkinter问题的回答,但与pygame问题的回答类似。我会引用这个,因为它似乎更简洁。

The only way for the canvas to refresh is for the event loop to service "redraw" events. In your loop you're never giving the event loop a chance to update, so you don't see any changes.

The quick fix is to call self.canvas.update_idletasks, but that's just a hack and not a proper solution.

The proper way to do animation is to use the event loop to do the iterations. You do this by placing work to be done on a queue -- in this case, the idle event queue. You can place things on this queue with the after command.

What you should do is write a function that does one iteration of your animation. Essentially, take everything in your while loop and move it to a function. Then, arrange for that function to be continually be called as long as there is work to do. You can either place the call to after in that function, or have a separate function controlling the animation.

感谢您的帮助,但结果我正在更新屏幕一帧。