pygame的“绘画”程序-在画布上绘制空矩形

时间:2019-09-24 23:20:00

标签: python pygame

因此,我正在使用pygame(我是全新的)制作类似于MS-Paint的程序,到目前为止进展顺利,除了我遇到的这个烦人的问题。 我希望用户能够通过在画布上拖动鼠标来绘制矩形,这与您在MS-Paint中的操作类似,并且我希望它看起来就像矩形在“移动”(只要鼠标一直在移动)被拖。 在设法告知我应该使用其他一些pygame方法使其更高效之前,我设法使其完美且效率低下。所以我做到了,而我无法解决的一个问题是,矩形的先前图像仍保留在屏幕上。像这样: Top-left is where I started to draw 这是我的代码的相关部分:

        if canvas.collidepoint(cursor) and pygame.mouse.get_pressed()[0] and mode == 'Square' and not draw_square:
            start_x, start_y = find_pixel(mouse_x, mouse_y)
            width, height = find_pixel(mouse_x, mouse_y)
            save_last = screen.subsurface(start_x, start_y, width - start_x, height - start_y)
            square = pygame.draw.rect(screen, current_color, (start_x, start_y, width - start_x, height - start_y), 5)
            temp_square = square
            draw_square = True

        if draw_square and canvas.collidepoint(cursor) and pygame.mouse.get_pressed()[0]:
            # Mouse is being held down outside canvas, show square progress
            prev_width, prev_height = width, height
            save_last = screen.subsurface(temp_square)
            width, height = find_pixel(mouse_x, mouse_y)
            if width != prev_width or height != prev_height:
                square = temp_square.inflate(width - start_x, height - start_y)
                square.topleft = start_x, start_y
                pygame.draw.rect(screen, current_color, square, 5)

        if not canvas.collidepoint(cursor) and draw_square:
            # Mouse is being held down outside canvas, show square progress
            width, height = find_pixel(mouse_x, mouse_y)
            if width < 150:  # Cursor is left of the canvas
                width = 150
            if width > 980:  # Cursor is right of the canvas
                width = 980
            if height < 20:  # Cursor is above the canvas
                height = 20
            if height > 580:  # Cursor if below the canvas
                height = 580

            square = temp_square.inflate(width - start_x, height - start_y)
            square.topleft = start_x, start_y
            pygame.draw.rect(screen, current_color, square, 5)

        if draw_square and not pygame.mouse.get_pressed()[0]:
            draw_square = False

        pygame.display.flip()

我尝试将save_last拖到屏幕上,但这给了我这个错误:

Traceback (most recent call last):
  File "C:/Users/yargr/PycharmProjects/Paint/PaintApp.py", line 548, in <module>
    main()
  File "C:/Users/yargr/PycharmProjects/Paint/PaintApp.py", line 435, in main
    screen.blit(save_last, (mouse_x, mouse_y))
pygame.error: Surfaces must not be locked during blit

我尝试使用screen.unlock(),但没有用(我想我还不完全了解它是如何工作的)。无论如何,如果有人有什么想法,我很想听听建议:)

1 个答案:

答案 0 :(得分:0)

问题在于save_last是屏幕的一个子表面,原因是

  
save_last = screen.subsurface(start_x, start_y, width - start_x, height - start_y)

分别

  
save_last = screen.subsurface(temp_square)

subsurface()创建一个引用另一个表面的表面。新的Surface与另一个父级共享其像素。新表面没有自己的数据。

如果愿意

  
screen.blit(save_last, (mouse_x, mouse_y))

然后,当读取screen时,似乎save_last会临时出现,因为已对其进行了引用。最后写入screen失败。

但是您可以通过.blit()screen的区域直接复制到screen来解决此问题。不要创建地下表面,只需注意矩形区域(pygame.Rect)并将该区域从screen Surface复制到screen上的另一个位置。例如:

save_rect = pygame.Rect(start_x, start_y, width - start_x, height - start_y)

# [...]

save_rect = pygame.Rect(temp_square)

# [...]

screen.blit(screen, (mouse_x, mouse_y), area=save_rect)

或者,您也可以创建矩形区域的副本并将blit的副本复制到screen

save_rect = pygame.Rect(start_x, start_y, width - start_x, height - start_y)
save_last = pygame.Surface(save_rect.size)
save_last.blit(screen, (0, 0), save_rect)

# [...]

save_rect = pygame.Rect(temp_square)
save_last = pygame.Surface(save_rect.size)
save_last.blit(screen, (0, 0), save_rect)

# [...]

screen.blit(save_last, (mouse_x, mouse_y))