2009-02-28 8 views
11

Как я вижу, есть два способа обработки событий мыши для рисования изображения.Как создать клонирование MS Paint с Python и pygame

Первый заключается в том, чтобы обнаружить, когда мышь перемещается и нарисовать линию, где находится мышь, показана here. Однако проблема заключается в том, что при большом размере кисти между каждой «линией», которая не является прямой, появляется много пробелов, так как она использует размер штриха линии для создания толстых линий.

Другой способ - нарисовать круги, когда мышь перемещается, как показано на рисунке here. Проблема заключается в том, что между каждым кружком появляются промежутки, если мышь движется быстрее, чем компьютер обнаруживает ввод мыши.

Вот скриншот с моими вопросами с обоими:

http://imgur.com/32DXN.jpg

Каков наилучший способ реализации кисти, как MS краски, с прилично большой размер кисти без каких-либо пробелов в росчерком линии или без пробелов между каждым кругом?

+0

Я не понимаю вашу проблему с линиями. Вы говорите об отсутствии конечных пунктов, или ...? –

+0

Просто объедините два. Толстые линии + круги. –

+0

Вот скриншот моих проблем с обоими: http://imgur.com/32DXN Использование толстых линий и кругов похоже на то, что это может решить проблему, но это не очень элегантно, поэтому я подумаю это еще и использовать это как последнее средство. – Johnston

ответ

13

Почему бы не сделать так?

Нарисуйте круг на каждой конечной точке и линию между ними.

EDIT rofl, просто не мог остановиться.

На самом деле, вы не хотите использовать pygame.draw.line, потому что он обманывает. Он заполняет строку или столбец шириной 1 пиксель (в зависимости от угла атаки) пикселей. Если вы делаете грубый перпендикулярный угол, 0 градусов или 90 градусов, это не проблема, но в 45-е годы вы заметите своего рода фасоль.

Единственное решение - нарисовать круг на расстоянии каждого пикселя. Здесь ...

import pygame, random 

screen = pygame.display.set_mode((800,600)) 

draw_on = False 
last_pos = (0, 0) 
color = (255, 128, 0) 
radius = 10 

def roundline(srf, color, start, end, radius=1): 
    dx = end[0]-start[0] 
    dy = end[1]-start[1] 
    distance = max(abs(dx), abs(dy)) 
    for i in range(distance): 
     x = int(start[0]+float(i)/distance*dx) 
     y = int(start[1]+float(i)/distance*dy) 
     pygame.draw.circle(srf, color, (x, y), radius) 

try: 
    while True: 
     e = pygame.event.wait() 
     if e.type == pygame.QUIT: 
      raise StopIteration 
     if e.type == pygame.MOUSEBUTTONDOWN: 
      color = (random.randrange(256), random.randrange(256), random.randrange(256)) 
      pygame.draw.circle(screen, color, e.pos, radius) 
      draw_on = True 
     if e.type == pygame.MOUSEBUTTONUP: 
      draw_on = False 
     if e.type == pygame.MOUSEMOTION: 
      if draw_on: 
       pygame.draw.circle(screen, color, e.pos, radius) 
       roundline(screen, color, e.pos, last_pos, radius) 
      last_pos = e.pos 
     pygame.display.flip() 

except StopIteration: 
    pass 

pygame.quit() 
1

Для первой проблемы у вас должен быть фон, даже если это только цвет. У меня была та же проблема с репликой, что я сделал. Вот пример реплики краски программы я сделал, щелкните левой кнопкой мыши, чтобы рисовать, нажмите правой кнопкой мыши, чтобы удалить, нажмите на цветное изображение, чтобы выбрать цвет, и вверх кнопку, чтобы очистить экран:

import os 
os.environ['SDL_VIDEO_CENTERED'] = '1' 
from pygamehelper import * 
from pygame import * 
from pygame.locals import * 
from vec2d import * 
from math import e, pi, cos, sin, sqrt 
from random import uniform 

class Starter(PygameHelper): 
    def __init__(self): 
     self.w, self.h = 800, 600 
     PygameHelper.__init__(self, size=(self.w, self.h), fill=((255,255,255))) 

     self.img= pygame.image.load("colors.png") 
     self.screen.blit(self.img, (0,0)) 

     self.drawcolor= (0,0,0) 
     self.x= 0 

    def update(self): 
     pass 

    def keyUp(self, key): 
     if key==K_UP: 
      self.screen.fill((255,255,255)) 
      self.screen.blit(self.img, (0,0)) 




    def mouseUp(self, button, pos): 
     pass 

    def mouseMotion(self, buttons, pos, rel): 
     if pos[1]>=172: 
      if buttons[0]==1: 
       #pygame.draw.circle(self.screen, (0,0,0), pos, 5) 
       pygame.draw.line(self.screen, self.drawcolor, pos, (pos[0]-rel[0], pos[1]-rel[1]),5)     
      if buttons[2]==1: 
       pygame.draw.circle(self.screen, (255,255,255), pos, 30) 
      if buttons[1]==1: 
       #RAINBOW MODE 
       color= self.screen.get_at((self.x, 0)) 
       pygame.draw.line(self.screen, color, pos, (pos[0]-rel[0], pos[1]-rel[1]), 5) 

       self.x+= 1 
       if self.x>172: self.x=0 

     else: 
      if pos[0]<172: 
       if buttons[0]==1: 
        self.drawcolor= self.screen.get_at(pos) 
        pygame.draw.circle(self.screen, self.drawcolor, (250, 100), 30) 

    def draw(self): 
     pass 
     #self.screen.fill((255,255,255)) 
     #pygame.draw.circle(self.screen, (0,0,0), (50,100), 20) 

s = Starter() 
s.mainLoop(40) 
2

Не блиттинг на каждом шаг цикла может улучшить скорость рисования (используя этот код, адаптированный из предыдущего, позволяет устранить проблему с задержкой на моей машине)

import pygame, random 

screen = pygame.display.set_mode((800,600)) 

draw_on = False 
last_pos = (0, 0) 
color = (255, 128, 0) 
radius = 10 

def roundline(srf, color, start, end, radius=1): 
    dx = end[0]-start[0] 
    dy = end[1]-start[1] 
    distance = max(abs(dx), abs(dy)) 
    for i in range(distance): 
     x = int(start[0]+float(i)/distance*dx) 
     y = int(start[1]+float(i)/distance*dy) 
     pygame.display.update(pygame.draw.circle(srf, color, (x, y), radius)) 

try: 
    while True: 
     e = pygame.event.wait() 
     if e.type == pygame.QUIT: 
      raise StopIteration 
     if e.type == pygame.MOUSEBUTTONDOWN: 
      color = (random.randrange(256), random.randrange(256), random.randrange(256)) 
      pygame.draw.circle(screen, color, e.pos, radius) 
      draw_on = True 
     if e.type == pygame.MOUSEBUTTONUP: 
      draw_on = False 
     if e.type == pygame.MOUSEMOTION: 
      if draw_on: 
       pygame.display.update(pygame.draw.circle(screen, color, e.pos, radius)) 
       roundline(screen, color, e.pos, last_pos, radius) 
      last_pos = e.pos 
     #pygame.display.flip() 

except StopIteration: 
    pass 

pygame.quit()