文章目录
- 开发环境要求
- 运行方法
- PyCharm
- VScode
- 代码
- main.py
- tools.py
- 效果
开发环境要求
本系统的软件开发及运行环境具体如下。
- 操作系统:Windows 7、Windows 10。
- Python版本:Python 3.7.1。
- 开发工具:PyCharm 2018。
- Python内置模块:os、sys、time、math。
- 第三方模块:pygame。
注意:在使用第三方模块时,首先需要使用pip install命令安装该模块,例如,安装pygame模块,可以在Python命令窗口中执行以下命令:
pip install pygame
运行方法
PyCharm
打开PyCharm开发环境,然后打开源码文件夹,找到drawBoard文件夹,按下<Ctrl+C>进行复制,切换到PyCharm开发环境,在左侧列表中按下<Ctrl+V>进行粘贴,展开drawBoard文件夹,双击main.py打开该文件,然后在右侧窗口中单击右键,选择“Run’main”即可运行程序,如图1所示。
程序运行效果如图2所示(说明:单击左侧的铅笔或者橡皮,然后单击加减号可以增加或者缩小宽度,选择一个颜色,即可在右侧绘制图形,或者擦除绘制的图形)。
图2 项目主界面
VScode
代码
main.py
# -*- coding: utf-8 -*-
import os
import sys
import time# 导入Pygame
try:import pygame
except ModuleNotFoundError:print('正在安装pygame,请稍等...')os.system('pip install pygame') # 安装pygame模块
import tools # 导入tools模块# 检测Python版本号
__MAJOR, __MINOR, __MICRO = sys.version_info[0], sys.version_info[1], sys.version_info[2]
if __MAJOR < 3:print('Python版本号过低,当前版本为 %d.%d.%d, 请重装Python解释器' % (__MAJOR, __MINOR, __MICRO))time.sleep(2)exit()if __name__ == '__main__':# 创建Paint类的对象paint = tools.Paint()try:paint.run() # 启动主窗口except Exception as e:print(e)
tools.py
# -*- coding: utf-8 -*-
import math
import pygame
from pygame.locals import QUIT, KEYDOWN, K_ESCAPE, MOUSEBUTTONDOWN, MOUSEMOTION, MOUSEBUTTONUP # 导入事件class Brush:"""画笔类"""def __init__(self, screen):self.screen = screen # 屏幕对象self.color = (0, 0, 0) # 颜色self.size = 1 # 大小self.drawing = False # 是否绘画self.last_pos = None # 鼠标滑过最后的位置self.space = 1self.brush = pygame.image.load("img/pen.png").convert_alpha() # 画笔图片self.brush_now = self.brush.subsurface((0, 0), (1, 1)) # 初始化画笔对象# 开始绘画def start_draw(self, pos):self.drawing = Trueself.last_pos = pos # 记录鼠标最后位置# 结束绘画def end_draw(self):self.drawing = False# 获取当前使用画笔def get_current_brush(self):return self.brush_now # 获取当前使用的画笔对象def set_size(self, size): # 设置画笔大小if size < 0.5: # 判断画笔尺寸小于0.5size = 0.5 # 设置画笔最小尺寸为0.5elif size > 32: # 判断画笔尺寸大于32size = 32 # 设置画笔最大尺寸为32self.size = size # 设置画笔尺寸# 生成画笔对象self.brush_now = self.brush.subsurface((0, 0), (size * 2, size * 2))# 获取画笔大小def get_size(self):return self.size# 设置画笔颜色def set_color(self, color):self.color = color # 记录选择的颜色for i in range(self.brush.get_width()): # 获取画笔的宽度for j in range(self.brush.get_height()): #获取画笔的高度# 以指定颜色显示画笔self.brush.set_at((i, j), color + (self.brush.get_at((i, j)).a,))# 获取画笔颜色def get_color(self):return self.color# 绘制动作def draw(self, pos):if self.drawing: # 判断是否开始绘画for p in self._get_points(pos):# 在两点之间的每个点上都画上实心点pygame.draw.circle(self.screen, self.color, p, int(self.size))self.last_pos = pos # 记录画笔最后位置# 获取两点之间所有的点位,该函数通过对鼠标坐标前一次记录点与当前记录点之间进行线性插值# 从而获得一系列点的坐标,从而使得绘制出来的画笔痕迹更加平滑自然def _get_points(self, pos):points = [(self.last_pos[0], self.last_pos[1])]len_x = pos[0] - self.last_pos[0]len_y = pos[1] - self.last_pos[1]length = math.sqrt(len_x ** 2 + len_y ** 2)step_x = len_x / lengthstep_y = len_y / lengthfor i in range(int(length)):points.append((points[-1][0] + step_x, points[-1][1] + step_y))# 对 points 中的点坐标进行四舍五入取整points = map(lambda x: (int(0.5 + x[0]), int(0.5 + x[1])), points)return list(set(points)) # 去除坐标相同的点class Menu:"""菜单类"""def __init__(self, screen):self.screen = screen # 初始化窗口self.brush = Noneself.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), (0x00, 0x00, 0x00),(0x80, 0x80, 0x80), (0x00, 0xc0, 0x80),]self.eraser_color = (0xff, 0xff, 0xff) # 初始颜色# 计算每个色块在画板中的坐标值,便于绘制self.colors_rect = []for (i, rgb) in enumerate(self.colors): # 方块颜色表rect = pygame.Rect(10 + i % 2 * 32, 254 + i / 2 * 32, 32, 32)self.colors_rect.append(rect)self.pens = [ # 画笔图片pygame.image.load("img/pen.png").convert_alpha(),]self.erasers = [ # 橡皮图片pygame.image.load("img/eraser.png").convert_alpha(),]self.erasers_rect = []for (i, img) in enumerate(self.erasers): # 橡皮列表rect = pygame.Rect(10, 10 + (i + 1) * 64, 64, 64)self.erasers_rect.append(rect)self.pens_rect = []for (i, img) in enumerate(self.pens): # 画笔列表rect = pygame.Rect(10, 10 + i * 64, 64, 64)self.pens_rect.append(rect)self.sizes = [ # 加减号图片pygame.image.load("img/plus.png").convert_alpha(),pygame.image.load("img/minus.png").convert_alpha()]# 计算坐标,便于绘制self.sizes_rect = []for (i, img) in enumerate(self.sizes):rect = pygame.Rect(10 + i * 32, 138, 32, 32)self.sizes_rect.append(rect)def set_brush(self, brush): # 设置画笔对象self.brush = brushdef draw(self): # 绘制菜单栏for (i, img) in enumerate(self.pens): # 绘制画笔样式按钮self.screen.blit(img, self.pens_rect[i].topleft)for (i, img) in enumerate(self.erasers): # 绘制橡皮按钮self.screen.blit(img, self.erasers_rect[i].topleft)for (i, img) in enumerate(self.sizes): # 绘制 + - 按钮self.screen.blit(img, self.sizes_rect[i].topleft)# 绘制用于实时展示画笔的小窗口self.screen.fill((255, 255, 255), (10, 180, 64, 64))pygame.draw.rect(self.screen, (0, 0, 0), (10, 180, 64, 64), 1)size = self.brush.get_size()x = 10 + 32y = 180 + 32# 在窗口中展示画笔pygame.draw.circle(self.screen, self.brush.get_color(), (x, y), int(size))for (i, rgb) in enumerate(self.colors): # 绘制色块pygame.draw.rect(self.screen, rgb, self.colors_rect[i])def click_button(self, pos):# 点击加减号事件for (i, rect) in enumerate(self.sizes_rect):if rect.collidepoint(pos):if i: # i == 1, size downself.brush.set_size(self.brush.get_size() - 0.5)else:self.brush.set_size(self.brush.get_size() + 0.5)return True# 点击颜色按钮事件for (i, rect) in enumerate(self.colors_rect):if rect.collidepoint(pos):self.brush.set_color(self.colors[i])return True# 点击橡皮按钮事件for (i, rect) in enumerate(self.erasers_rect):if rect.collidepoint(pos):self.brush.set_color(self.eraser_color)return Truereturn Falseclass Paint:"""窗口绘制类"""def __init__(self):self.screen = pygame.display.set_mode((800, 600)) # 显示窗口pygame.display.set_caption("超级画板") # 设置窗口标题self.clock = pygame.time.Clock() # 控制速率self.brush = Brush(self.screen) # 创建画刷对象self.menu = Menu(self.screen) # 创建窗口菜单self.menu.set_brush(self.brush) # 设置默认画刷def clear_screen(self):self.screen.fill((255, 255, 255)) # 填充空白def run(self):self.clear_screen() # 清除屏幕while True:# 设置fps,表示每秒执行30次(注意:30不是毫秒数)self.clock.tick(30)for event in pygame.event.get(): # 遍历所有事件if event.type == QUIT: # 退出事件returnelif event.type == KEYDOWN: # 按键事件# 按ESC键清空画板if event.key == K_ESCAPE: # ESC按键事件self.clear_screen()elif event.type == MOUSEBUTTONDOWN: # ;鼠标左键按下事件if ((event.pos)[0] <= 74 and self.menu.click_button(event.pos)): # 未点击画板按钮passelse:self.brush.start_draw(event.pos) # 开始绘画elif event.type == MOUSEMOTION: # 鼠标移动事件self.brush.draw(event.pos) # 绘画动作elif event.type == MOUSEBUTTONUP: # 鼠标左键松开事件self.brush.end_draw() # 停止绘画self.menu.draw()pygame.display.update() # 更新画板
效果
PS:全部文档放下载处