программа pygame "Paint" - рисование пустого прямоугольника на холсте - PullRequest
1 голос
/ 25 сентября 2019

Так что я делаю MS-Paint-подобную программу с использованием pygame (к которой я совершенно новичок), которая до сих пор шла хорошо, за исключением этой досадной проблемы, которая у меня есть.Я хочу, чтобы у пользователя была возможность рисовать прямоугольник, перетаскивая мышь вдоль холста, подобно тому, как вы это делаете в MS-Paint, и я хочу, чтобы он выглядел так, как будто прямоугольник "движется", пока мышьтащат.Мне удалось заставить его работать идеально, но неэффективно, пока мне не посоветовали использовать другие методы Pygame, чтобы сделать его более эффективным.Я так и сделал, и единственная проблема, которую я не могу решить, это то, что предыдущие изображения прямоугольника остаются на экране.Вот так: В верхнем левом углу я начал рисовать Вот соответствующая часть моего кода:

        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 голосов
/ 25 сентября 2019

Проблема в том, что save_last - это недра экрана, из-за

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

соответственно

save_last = screen.subsurface(temp_square)

subsurface() создает поверхность, которая ссылается на другую поверхность.Новая поверхность делит свои пиксели с другим родителем.Новая поверхность не имеет собственных данных.

Если вы сделаете

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

, тогда кажется, что screen выглядит временно, когда читается save_lastпотому что на него ссылаются.Наконец, запись в screen не удалась.

Но вы можете решить эту проблему, непосредственно скопировав область от screen до screen с помощью .blit().Не создавайте подповерхность, просто отметьте прямоугольную область (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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...