pygame实现的GUI画板

写在前面

这是将近一年前学校开设的Python高级语言程序课上的一次作业,最近太久没打代码所以又翻出来重新温习了一遍,希望对自己以后做项目开发软件设计方面有所帮助

创建画笔类

橡皮擦视作颜色为白的笔即可

我们给画笔一个drawing开关记录现在是否在画画(也就是当我们在画布上按下鼠标左键时drawing变为True)同时记录笔刷的上一位置也即las_pos

当我们捕捉到鼠标移动时,我们开始绘制曲线,我们希望笔刷画出的轨迹相对圆润平滑,所以我们在las_pos以及当前pos的连线上等间距选取圆心,并以当前画笔大小(size)为半径作实心圆

最后当我们捕捉到鼠标左键松开时,drawing开关关闭即可

class Brush():
    def __init__(self,screen):
        self.color=(0,0,0)
        self.screen=screen
        self.drawing=False
        self.size=1
        self.laspos=None
        self.lascol=(0,0,0)
        self.p_or_e=True

    def start(self,pos):
        self.drawing=True
        self.laspos=pos
    def close(self):
        self.drawing=False

    def set_size(self,size):
        if size>50:
            size=50
        elif size<1:
            size=1
        self.size=size
    def get_size(self):
        return self.size

    def getline(self,pos):
        lenx=pos[0]-self.laspos[0]
        leny=pos[1]-self.laspos[1]
        length=math.sqrt(lenx**2+leny**2)
        cosx=lenx/length
        sinx=leny/length
        points=[]
        for i in range(int(length)):
            points.append((self.laspos[0]+i*cosx,self.laspos[1]+i*sinx))
        points.append((self.laspos[0]+length*cosx,self.laspos[1]+length*sinx))
        return points

    def Draw(self,pos):
        if self.drawing==True:
            for p in self.getline(pos):
                pygame.draw.circle(self.screen,self.color,p,self.size)
        self.laspos=pos

创建菜单栏

菜单栏上设计了吸色盘,笔刷变大变小按钮,选取橡皮或笔刷的按钮

pygame给了我们Rect也就是矩形这个非常方便的对象

rect =pygame.Rect(left,top,width,height)

同时也给了 collidepoint 函数可以很便捷地判断某一位置是否在当前矩形范围内

吸色盘只需设计多个矩形(这里用了8*2)并在其中填充相应颜色就好,当鼠标左键按下时根据相应坐标就能知道选取了什么颜色

其余部分也都一样,各自设置一下对应的矩形位置就能判断点击了哪里

class Menu():
    def __init__(self,screen,brush):
        self.screen=screen
        self.brush=brush
        self.colors=[
            (0xff, 0x00, 0xff), (0x80, 0x00, 0x80),
            (0x00, 0x00, 0xff), (0x00, 0x00, 0x80),
            (0x00, 0xff, 0xff), (0x00, 0x80, 0x80),
            (0x00, 0xff, 0x00), (0x00, 0x80, 0x00),
            (0xff, 0xff, 0x00), (0x80, 0x80, 0x00),
            (0xff, 0x00, 0x00), (0x80, 0x00, 0x00),
            (0xc0, 0xc0, 0xc0), (0xff, 0xff, 0xff),
            (0x00, 0x00, 0x00), (0x80, 0x80, 0x80),
        ]
        self.color_rec=[]
        for (i,col) in enumerate(self.colors):
            if i%2==0:
                rect=pygame.Rect(10,10+i//2+32*(i//2),32,32)
            else:
                rect=pygame.Rect(43,10+i//2+32*(i//2),32,32)
            self.color_rec.append(rect)
        self.pen=pygame.image.load('./img/pen.png').convert_alpha()
        self.plus=pygame.image.load('./img/plus.png').convert_alpha()
        self.minus=pygame.image.load('./img/minus.png').convert_alpha()
        self.eraser=pygame.image.load('./img/eraser.png').convert_alpha()
        self.pen_rec=Rect(10,275,28,28)
        self.plus_rec=Rect(10,320,28,28)
        self.minus_rec=Rect(40,320,28,28)
        self.eraser_rec=Rect(40,275,28,28)

    def draw(self):
        self.screen.blit(self.pen,self.pen_rec.topleft)
        self.screen.blit(self.eraser,self.eraser_rec.topleft)
        self.screen.blit(self.plus,self.plus_rec.topleft)
        self.screen.blit(self.minus,self.minus_rec.topleft)
        for (i,col) in enumerate(self.color_rec):
            pygame.draw.rect(self.screen,self.colors[i],col)

    def click_button(self,pos):
        for (i,col) in enumerate(self.color_rec):
            if col.collidepoint(pos):
                self.brush.p_or_e=True
                self.brush.color=self.colors[i]
                self.brush.lascol=self.colors[i]
                return True
        if self.pen_rec.collidepoint(pos):
            if self.brush.p_or_e==False:
                self.brush.p_or_e=True
                self.brush.color=self.brush.lascol
            return True
        if self.eraser_rec.collidepoint(pos):
            if self.brush.p_or_e==True:
                self.brush.p_or_e=False
                self.brush.color=(255,255,255)
            return True
        if self.plus_rec.collidepoint(pos):
            self.brush.set_size(self.brush.get_size()+1)
            return True
        if self.minus_rec.collidepoint(pos):
            self.brush.set_size(self.brush.get_size()-1)
            return True
        return False

画板

在这部分定义了快捷键, esc 清空屏幕, ctrl+z 撤销, ctrl+s 保存。

先使用 key.get_pressed 捕获按下的键并保存在key_pressed中:

    key_pressed = pygame.key.get_pressed()

判断组合键只需keypressed[K_LCTRL] _与_keypressed[K_letter]同时判定为true即可

esc_即把画板全涂成白色, _ctrl+s 即将当前图像按照 “Draw+tot”的格式保存即可

对于撤销操作,我们只需开一个栈:

    las_screen=[]

然后依次保存每次动笔前的surface对象,按下 ctrl+z 使用 blit 函数覆盖当前界面并弹栈

    self.screen.blit(las_screen[len(las_screen)-1],(0,0))
    las_screen.pop()

画板部分代码:

class Painter():
    def __init__(self):
        pygame.display.set_caption('Painter')
        self.clock=pygame.time.Clock()
        self.screen=pygame.display.set_mode(fbl,0,32)
        self.brush=Brush(self.screen)
        self.menu=Menu(self.screen,self.brush)

    def run(self):
        tot=1
        self.screen.fill((255,255,255))
        while True:
            self.clock.tick(60)
            for event in pygame.event.get():
                if event.type==QUIT:
                    exit()
                elif event.type==MOUSEBUTTONDOWN:
                    if self.menu.click_button(event.pos):
                        pass
                    elif event.pos[0]>=0 and event.pos[1]fbl[0] and event.pos[1]>=0 and event.pos[1]fbl[1]:
                        las_screen.append(self.screen.copy())

                        self.brush.start(event.pos)
                elif event.type==MOUSEMOTION:
                    self.brush.Draw(event.pos)
                elif event.type==MOUSEBUTTONUP:
                    self.brush.close()
                elif event.type==KEYDOWN:
                    key_pressed = pygame.key.get_pressed()
                    if key_pressed[K_LCTRL] and key_pressed[K_s]:
                        pygame.image.save(self.screen,'Draw'+str(tot)+'.png')
                        tot+=1
                    elif key_pressed[K_LCTRL] and key_pressed[K_z]:
                        if len(las_screen)==0:
                            pass
                        else:
                            self.screen.blit(las_screen[len(las_screen)-1],(0,0))

                            las_screen.pop()
                    elif event.key==K_ESCAPE:
                        las_screen.append(self.screen.copy())
                        self.screen.fill((255,255,255))
            self.menu.draw()
            pygame.display.update()

最终效果

pygame实现的GUI画板

Original: https://blog.csdn.net/qq_39562371/article/details/125154031
Author: Checkmate_Ril
Title: pygame实现的GUI画板

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/780394/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球