先说废话,再上代码
这个绘画板主要运用了Python自带的标准GUI库Tkinter,包含了画笔颜色选择,背景布颜色选择,橡皮擦,清屏,保存图片等功能。
from tkinter import *
from tkinter.ttk import Scale
from tkinter import colorchooser, filedialog, messagebox
import PIL.ImageGrab as ImageGrab
from tkinter.colorchooser import askcolor
# from ttkbootstrap import ttk
from tkmacosx import Button
# Defining Class and constructor of the Program
class Draw():
def __init__(self, root):
# Defining title and Size of the Tkinter Window GUI
self.root = root
self.root.title("画图工具Python")
self.root.geometry("1000x1000")
self.root.configure(background="white")
# self.root.resizable(0,0)
# variables for pointer and Eraser
self.pointer = "black"
self.erase = "white"
# Widgets for Tkinter Window
# Configure the alignment , font size and color of the text
text = Text(root, height=5, width=100)
text.tag_configure("tag_name", justify='center', font=('arial', 25), background='#292826', foreground='orange')
# Insert a Text
text.insert("1.0", "python中画画")
# Add the tag for following given text
text.tag_add("tag_name", "1.0", "end")
text.pack()
# Pick a color for drawing from color pannel
self.pick_color = LabelFrame(self.root, text='Colors', font=('arial', 15), bd=5, relief=RIDGE, bg="white")
self.pick_color.place(x=0, y=40, width=135, height=525)
colors = ['blue', 'red', 'green', 'orange', 'violet', 'black', 'yellow', 'purple', 'pink', 'gold', 'brown',
'indigo']
i = j = 0
for color in colors:
Button(self.pick_color, bg=color, width=61,
command=lambda col=color: self.select_color(col)).grid(row=i, column=j)
i += 1
if i == 6:
i = 0
j = 1
# 擦除按钮
self.eraser_btn = Button(self.root, text="Eraser", command=self.eraser, width=120)
self.eraser_btn.place(x=7, y=230) # 改
# 清屏
self.clear_screen = Button(self.root, text="Clear Screen",width=120,
command=lambda: self.background.delete('all'))
self.clear_screen.place(x=7, y=260)
# 保存
self.save_btn = Button(self.root, text="ScreenShot",command=self.save_drawing,width=120)
self.save_btn.place(x=7, y=290)
# 改变画布背景
self.bg_btn = Button(self.root, text="Background", command=self.canvas_color,width=120)
self.bg_btn.place(x=7, y=320)
# 改变画笔大小
self.pointer_frame = LabelFrame(self.root, text='size', bd=5, bg='white', font=('arial', 15, 'bold'),
relief=RIDGE)
self.pointer_frame.place(x=33, y=380, height=200, width=70)
self.pointer_size = Scale(self.pointer_frame, orient=VERTICAL, from_=1, to=48, length=168)
self.pointer_size.set(1)
self.pointer_size.grid(row=0, column=1, padx=15)
# 定一个画布
self.background = Canvas(self.root, bg='white', bd=5, relief=GROOVE, height=890, width=800)
self.background.place(x=140, y=45)
# 默认光标形状为箭头
self.cursor_shape = "arrow"
# 监听画布被点击
self.background.bind("<B1-Motion>", self.paint)
# Functions are defined here
# 画笔函数
def paint(self, event):
x1, y1 = (event.x - 2), (event.y - 2)
x2, y2 = (event.x + 2), (event.y + 2)
self.background.create_oval(x1, y1, x2, y2, fill=self.pointer, outline=self.pointer,
width=self.pointer_size.get())
# Function for choosing the color of pointer
def select_color(self, col):
self.pointer = col
self.cursor_shape: str = "pencil" # 更改光标形状为铅笔
self.root.configure(cursor=self.cursor_shape)
# Function for defining the eraser
def eraser(self):
self.pointer = self.erase
self.cursor_shape: str = "dotbox" # 更改光标形状为点框
self.root.configure(cursor=self.cursor_shape)
# Function for choosing the background color of the Canvas
def canvas_color(self):
color = colorchooser.askcolor()
self.background.configure(background=color[1])
self.erase = color[1]
self.cursor_shape: str = "arrow" # 更改光标形状为箭头
self.root.configure(cursor=self.cursor_shape)
# Function for saving the image file in Local Computer
def save_drawing(self):
try:
# self.background update()
file_ss = filedialog.asksaveasfilename(defaultextension='jpg')
# print(file_ss)
x = self.root.winfo_rootx() + self.background.winfo_x()
# print(x, self.background.winfo_x())
y = self.root.winfo_rooty() + self.background.winfo_y()
# print(y)
x1 = x + self.background.winfo_width()
# print(x1)
y1 = y + self.background.winfo_height()
# print(y1)
ImageGrab.grab().crop((x, y, x1, y1)).save(file_ss)
messagebox.showinfo('Screenshot Successfully Saved as' + str(file_ss))
except:
print("Error in saving the screenshot")
if __name__ == "__main__":
root = Tk()
p = Draw(root)
root.mainloop()
显示结果:![](https://i-blog.csdnimg.cn/blog_migrate/177ae5f2e5bd7ec2cd8bb72c52cfacc7.png)
软件特色:
1.框架采用的是LabelFrame
LabelFrame 组件是 Frame 组件的变体。默认情况下,LabelFrame 会在其子组件的周围绘制一个边框以及一个标题。
2.设置了一个总标题,橘色的字体更加显眼
# Configure the alignment , font size and color of the text
text = Text(root, height=5, width=100)
text.tag_configure("tag_name", justify='center', font=('arial', 25), background='#292826', foreground='orange')
3.简化代码,可以让后面的组件从1.0->最后都逐一pack
# Add the tag for following given text
text.tag_add("tag_name", "1.0", "end")
text.pack()
4.在色块选择时,列举出部分颜色,并逐一放置在组件中
colors = ['blue', 'red', 'green', 'orange', 'violet', 'black', 'yellow', 'purple', 'pink', 'gold', 'brown',
'indigo']
i = j = 0
for color in colors:
Button(self.pick_color, bg=color, width=61,
command=lambda col=color: self.select_color(col)).grid(row=i, column=j)
i += 1
if i == 6:
i = 0
j = 1
5.画笔粗细调节采用的是滑动条来改变
# 改变画笔大小
self.pointer_frame = LabelFrame(self.root, text='size', bd=5, bg='white', font=('arial', 15, 'bold'),
relief=RIDGE)
self.pointer_frame.place(x=33, y=380, height=200, width=70)
self.pointer_size = Scale(self.pointer_frame, orient=VERTICAL, from_=1, to=48, length=168)
self.pointer_size.set(1)
self.pointer_size.grid(row=0, column=1, padx=15)
学习历程:
本人是Python零基础,开始拿到这个课题时,纯茫然,特别是要求设计一个绘画软件时,人都是懵的,但还是硬着头皮学,最开始先学习Python基础语法,我是根据书本来学习的(书本是上学期二手淘的),因为之前学习C语言就是看视频学习,老是分心,感觉学习周期会比较长,这次就尝试看书来学习,很快就对Python产生了兴趣,觉得比C语言代码简洁,然后就开始逐步学习,了解了PYthon自带的GUI库--Tkinter库,
遇到问题全靠CSDN,但是CSDN也不是万能的,很多时候都是自己茫然的搜索资料
但是仍感觉自己学的不精,脱离了书本等辅助资料,可能就啥也不会了
寄
临近4.9号,才看到要求是用PyQt5设计,只有临时抱佛脚,大概了解一些常用的模块和类,并靠CSDN编写一个。但是写出来就有大问题,运行的时候,橡皮擦的鼠标光标倒是改变了,但是橡皮擦的颜色却与画笔颜色一样,尝试过修改橡皮擦颜色,失败了。
这个版本的画板,还有个缺点,画笔粗细只设置了小中大三个选项,没有像tkinter版设置一个滑动条,本想利用QInputDialog来直接输入画笔粗细,但是引用QInputDialog后出现报错
Process finished with exit code -1073741819 (0xC0000005)
不知道该怎么解决
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, QFileDialog, QColorDialog, QMenu
from PyQt5.QtGui import QIcon, QImage, QPainter, QPen, QPixmap, QCursor, QColor
from PyQt5.QtCore import Qt, QPoint
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("画图软件")
self.setGeometry(100, 100, 800, 600)
self.image = QImage(self.size(), QImage.Format_RGB32)
self.image.fill(Qt.white)
self.drawing = False
self.brush_size = 2
self.brush_color = Qt.white
self.last_point = QPoint()
self.color = self.palette().color(self.backgroundRole())
self.initUI()
def initUI(self):
# 创建菜单栏
menubar = self.menuBar()
# 创建文件菜单
file_menu = menubar.addMenu("文件")
# 创建打开文件动作
open_action = QAction(QIcon("icons/open.png"), "打开", self)
open_action.triggered.connect(self.open_image)
file_menu.addAction(open_action)
# 创建保存文件动作
save_action = QAction(QIcon("icons/save.png"), "保存", self)
save_action.triggered.connect(self.save_image)
file_menu.addAction(save_action)
# 创建退出动作
exit_action = QAction(QIcon("icons/exit.png"), "退出", self)
exit_action.triggered.connect(self.close)
file_menu.addAction(exit_action)
# 创建画笔菜单
brush_menu = menubar.addMenu("画笔")
# 创建颜色选择动作
color_action = QAction(QIcon("icons/color.png"), "颜色", self)
color_action.triggered.connect(self.choose_color)
brush_menu.addAction(color_action)
# 创建粗细选择动作
size_menu = QMenu("粗细", self)
brush_menu.addMenu(size_menu)
# 创建粗细选择动作组
size_group = QAction(QIcon("icons/size.png"), "粗细", self, checkable=True)
size_group.triggered.connect(self.choose_size)
size_menu.addAction(size_group)
# 创建粗细选择动作
small_size = QAction(QIcon("icons/small.png"), "小", self, checkable=True)
small_size.triggered.connect(lambda: self.set_size(2))
size_menu.addAction(small_size)
medium_size = QAction(QIcon("icons/medium.png"), "中", self, checkable=True)
medium_size.triggered.connect(lambda: self.set_size(4))
size_menu.addAction(medium_size)
large_size = QAction(QIcon("icons/large.png"), "大", self, checkable=True)
large_size.triggered.connect(lambda: self.set_size(6))
size_menu.addAction(large_size)
# 创建橡皮擦菜单
eraser_menu = menubar.addMenu("橡皮擦")
# 创建橡皮擦动作
eraser_action = QAction(QIcon("icons/eraser.png"), "橡皮擦", self, checkable=True,)
eraser_action.triggered.connect(self.use_eraser)
eraser_menu.addAction(eraser_action)
# 创建清空画布动作
clear_action = QAction(QIcon("icons/clear.png"), "清空", self)
clear_action.triggered.connect(self.clear_image)
eraser_menu.addAction(clear_action)
self.show()
def paintEvent(self, event):
painter = QPainter(self)
painter.drawImage(self.rect(), self.image, self.image.rect())
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.color = self.palette().color(self.backgroundRole())
self.update()
self.drawing = True
self.last_point = event.pos()
def mouseMoveEvent(self, event):
if event.buttons() and Qt.LeftButton and self.drawing:
painter = QPainter(self.image)
painter.setPen(QPen(self.brush_color, self.brush_size, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
painter.drawLine(self.last_point, event.pos())
self.last_point = event.pos()
self.update()
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
self.drawing = False
def open_image(self):
file_name, _ = QFileDialog.getOpenFileName(self, "打开图片", "",
"Images (*.png *.xpm *.jpg *.bmp);;All Files (*)")
if file_name:
self.image = QImage(file_name)
self.update()
def save_image(self):
file_name, _ = QFileDialog.getSaveFileName(self, "保存图片", "",
"Images (*.png *.xpm *.jpg *.bmp);;All Files (*)")
if file_name:
self.image.save(file_name)
def choose_color(self):
color = QColorDialog.getColor()
if color.isValid():
self.brush_color = color
def choose_size(self):
pass
def set_size(self, size):
self.brush_size = size
def use_eraser(self):
self.setCursor(QCursor(Qt.PointingHandCursor))
def clear_image(self):
self.image.fill(Qt.white)
self.update()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
sys.exit(app.exec_())
显示结果:![](https://i-blog.csdnimg.cn/blog_migrate/6bad4b2b904ce13cad9ac579386b3cff.png)
PyQt5,Tkinter都是Python中常用的GUI工具包,它们各自有优缺点,具体如下:(百度搜索结果)
PyQt5的优点:
提供了丰富的GUI控件和功能,支持多种操作系统;
具有良好的文档和社区支持,易于学习和使用;
支持Qt Designer,可以通过可视化界面设计工具快速创建GUI界面;
支持多线程和网络编程,适合开发复杂的应用程序。
PyQt5的缺点:
由于其功能丰富,学习曲线较陡峭,需要花费一定的时间和精力;
PyQt5的许可证是GPL或商业许可证,商业使用需要购买许可证;
PyQt5的安装包较大,需要下载和安装许多依赖库。
Tkinter的优点:
是Python标准库中的一部分,无需额外安装;
学习曲线较平缓,易于入门;
支持多种GUI控件和布局管理器,可以创建简单的GUI界面;
适合快速开发小型应用程序。
Tkinter的缺点:
功能相对较少,不支持一些高级功能;
界面设计较为简单,不支持可视化界面设计工具;
不支持多线程和网络编程,不适合开发复杂的应用程序。
接下来再慢慢学习PyQt5吧...