2016-08-11 86 views
1

在我的程序中,我有一个Popup对象,在创建后,会向屏幕绘制一条消息,暂停并删除它。这在绝大多数情况下都能正常工作,包括将消息依次链接在一起。但是,如果任何时候游戏窗口出于任何原因(它被最小化或者您点击另一个窗口)出现焦点,那么在一个或两个链接弹出窗口后,屏幕将冻结并且不显示任何后续的窗口,从而变得响应再次最后一个弹出窗口消失后。这似乎发生在弹出窗口消失之前,因为冻结持续时间的窗口仍然可见。Pygame 3.3没有正确更新屏幕导致冻结

我不知道这是Python还是Pygame的问题,但我希望这是我所做的,所以可以修复它。有谁知道发生了什么?用法

class Popup(): 

def __init__(self,surface,font,colour,thickness,text,textcolour,duration,align="center",x=None,y=None): #Position can be specified, but will default to centre of screen. 
    self.surface = surface 
    self.font = font 
    self.colour = colour 
    self.x = x 
    self.y = y 
    self.thickness = thickness 
    self.text = text 
    self.textcolour = textcolour 
    self.duration = duration 
    self.align = align 

    self.appear() 
    sleep(self.duration) #I want to thread this if I can. For now, it pauses the entire program, so don't use long durations! 
    self.disappear() 

def appear(self): 
    screenBorder = pygame.Rect(0,0,self.surface.get_width()-10,50) #Limits text width to slightly smaller than screen. 
    message = multiLineText(None,self.font,self.text,self.textcolour,screenBorder,self.align) 

    POPUPSURF = pygame.Surface((message.get_width()+(self.thickness*2),message.get_height()+(self.thickness*2))).convert_alpha() #New surface size of message plus border. 
    POPUPSURF.fill(self.colour) 
    POPUPSURF.blit(message,(self.thickness,self.thickness)) #Add the text. 

    if self.thickness > 0: 
     alphas = [] 
     increment = int(255/self.thickness) 
     for i in range(self.thickness): 
      alphas.append(increment*(i+1)) 

     for alpha in alphas: 
      num = alphas.index(alpha) 
      thisL = POPUPSURF.get_width() - (2*num) 
      thisH = POPUPSURF.get_height() - (2*num) 

      R,G,B = self.colour 
      pygame.draw.rect(POPUPSURF,(R,G,B,alpha),(num,num,thisL,thisH),1) #Draw border. 

    if self.x == None: 
     self.x = (self.surface.get_width()/2) - (POPUPSURF.get_width()/2) 
    if self.y == None: 
     self.y = (self.surface.get_height()/2) - (POPUPSURF.get_height()/2) 

    self.BACKUPSURF = pygame.Surface((POPUPSURF.get_width(),POPUPSURF.get_height())) 
    self.BACKUPSURF.blit(self.surface,(0,0),(self.x,self.y,POPUPSURF.get_width(),POPUPSURF.get_height())) #Takes a copy of what it looks like without popup. This can be restored in disappear(). 

    self.surface.blit(POPUPSURF,(self.x,self.y)) 
    pygame.display.update() 

def disappear(self): 
    self.surface.blit(self.BACKUPSURF,(self.x,self.y)) 
    pygame.display.update() 
    sleep(0.1) 

例子:

expGainPopup = Popup(DISPLAYSURF,font,DARKRED,10,"You have gained %d EXP!" %gain,WHITE,DURATION) #Inform of gain. 

if player["Level"] < 15: #If not max level (would cause out-of-bounds error on array) 
    progressPopup = Popup(DISPLAYSURF,font,DARKRED,10,"You now have %d EXP out of %d to level up." %(player["EXP"], levels[player["Level"]]),WHITE,DURATION) #Inform of progress. 

如果有人想测试代码,他们还需要MultiLineText功能:

def multiLineText(background,font,text,colour,boundary=None,align="left",returnNum=False): #NB the boundary ONLY cares about width/length. It will not limit the height of returned surface objects. 
if type(boundary) == pygame.Rect: #If a valid boundary is passed 
    testSection = "" 
    testResult = "" 
    for word in findall(r'\S+|\n',text): #Borrowed this from my text compressor program. Splits all words and newlines, as \S+ finds a non-whitespace character and all similar characters following it. \n will match all newlines, treating them as words. | is just the 'or' operator. r makes it a raw string so Python doesn't get confused with all the formatting symbols. 
     testSection += " "+word #Remember to add spaces back in! 
     if word == "\n": 
      testResult += testSection #Skip check and auto-newline if it is a newline 
      testSection = "" 
     elif font.size(testSection)[0] > boundary.width: #If has exceeded one line length 
      testSection = testSection[:-len(word)-1] #Remove the word, -1 also removes the space before the word. 
      testResult += testSection+"\n" #Add string with line break to the result. 
      testSection = " "+word #Restart testSection with word that did not fit, ready for new line. 
    testResult += testSection #Add the last section that never reached the max length to the output so it doesn't get lost. 
    lines = testResult.split("\n") 
    for i in range(len(lines)): 
     lines[i] = lines[i][1:] #Removes the first character, an unwanted space. 
else: #If just working off existing \n in the text 
    lines = text.split("\n") 

lengths = [] 
for line in lines: 
    lengths.append(font.size(line)[0]) 
length = max(lengths) #Length is set to the length of the longest individual line. 

totalHeight = 0 
for line in lines: 
    totalHeight += font.size(line)[1] 
TEXTSURF = pygame.Surface((length,totalHeight)).convert_alpha() 
if background != None: #Fill the background with colour or transparency. 
    TEXTSURF.fill(background) 
else: 
    TEXTSURF.fill((0,0,0,0)) 

for i in range(len(lines)): 
    lines[i] += str(i) #Add a unique identifier onto every line. This way if two or more lines are the same, index(line) will not return the wrong value, resulting in repeated lines not appearing. 

for line in lines: 
    dudChars = len(str(lines.index(line))) #The number of characters in the index of this line within lines, and therefore the character length of the unique identifier we want to remove. 
    renderedLine = font.render(line[:-dudChars],True,colour) #Render the line without identifier. 

    if align == "left": 
     xpos = 0 
    elif align == "center": 
     xpos = (length/2) - (renderedLine.get_width()/2) 
    elif align == "right": 
     xpos = length - renderedLine.get_width() 

    ypos = int((lines.index(line)) * (totalHeight/len(lines))) #Find the appropriate vertical space 

    TEXTSURF.blit(renderedLine,(xpos,ypos)) #Add to the multiline surface. 

if returnNum == False: 
    return TEXTSURF 
else: 
    return TEXTSURF, len(lines) #Return the number of lines used as well, if it was asked for. 
+0

无码 - 即时downvote。我们应该如何知道造成问题的原因? –

+0

请添加与问题相关的代码。作为参考:[如何创建一个最小,完整和可验证的示例](http://stackoverflow.com/help/mcve) –

+0

@JonathonOgden代码已被添加,对不起! –

回答

0

这最终被在pygame.event.pump将解决功能到关键的地方。这允许pygame处理其内部事件,例如与OS交谈。如果没有这个,事件队列会被暂停太久,程序会被标记为无响应,屏幕冻结,并发生不好的事情。

相关固定的代码(只有一条线不同):

def disappear(self): 
    self.surface.blit(self.BACKUPSURF,(self.x,self.y)) 
    pygame.display.update() 
    pygame.event.pump() #So the display updates properly, stops it from freezing and making you miss messages. This allows pygame to do some internal events such as talking to the OS. Otherwise, if the event queue has been paused for too long, the OS will treat it as not responding, and bad things happen. 
    sleep(0.1)