作业要求
下载后直接用python运行软件打开就行了(Tensorflow不支持)
附件链接://download.youkuaiyun.com/download/weixin_44382897/12036092
可供参考实现的学习文件
老师给出的例子是可以实现图片的转换,然后让我们按照例子来实现画板程序的制作。老师例子的主要代码如下:
附件链接:
链接:https://pan.baidu.com/s/19CRNcntfriRGlP62_0cZIQ
提取码:ikqp
import os
import platform
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class myMainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.image = QImage()
self.dirty = False
self.filename = None
self.mirroredvertically = False
self.mirroredhorizontally = False
#图像
self.imageLabel = QLabel()
self.imageLabel.setAlignment(Qt.AlignCenter)
self.imageLabel.setContextMenuPolicy(Qt.ActionsContextMenu)
self.setCentralWidget(self.imageLabel)
#右侧停靠窗口
logDockWidget = QDockWidget("Log", self)
logDockWidget.setAllowedAreas(Qt.LeftDockWidgetArea|Qt.RightDockWidgetArea)
self.listWidget = QListWidget()
logDockWidget.setWidget(self.listWidget)
self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)
#状态栏
self.sizeLabel = QLabel()
self.sizeLabel.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
status = self.statusBar()
status.setSizeGripEnabled(False)
status.addPermanentWidget(self.sizeLabel)
status.showMessage("Ready", 5000)
#各种动作
self.fileOpenAction = QAction(QIcon("images/fileopen.png"), "&Open", self)
self.fileOpenAction.setShortcut(QKeySequence.Open)
self.fileOpenAction.setToolTip("Open an image.")
self.fileOpenAction.setStatusTip("Open an image.")
self.fileOpenAction.triggered.connect(self.fileOpen)
self.fileSaveAction = QAction(QIcon("images/filesave.png"), "&Save", self)
self.fileSaveAction.setShortcut(QKeySequence.Save)
self.fileSaveAction.setToolTip("Save an image.")
self.fileSaveAction.setStatusTip("Save an image.")
self.fileSaveAction.triggered.connect(self.fileSaveAs)
self.editUnMirrorAction = QAction(QIcon("images/editunmirror.png"), "&Unmirror", self)
self.editUnMirrorAction.setShortcut("Ctrl+U")
self.editUnMirrorAction.setToolTip("Unmirror the image")
self.editUnMirrorAction.setStatusTip("Unmirror the image")
self.editUnMirrorAction.setCheckable(True)
self.editUnMirrorAction.setChecked(True)
self.editUnMirrorAction.toggled.connect(self.editUnMirror)
editMirrorHorizontalAction = QAction(QIcon("images/editmirrorhoriz.png"), "Mirror &Horizontally", self)
editMirrorHorizontalAction.setShortcut("Ctrl+H")
editMirrorHorizontalAction.setToolTip("Horizontally mirror the image")
editMirrorHorizontalAction.setStatusTip("Horizontally mirror the image")
editMirrorHorizontalAction.setCheckable(True)
editMirrorHorizontalAction.toggled.connect(self.editMirrorHorizontal)
editMirrorVerticalAction = QAction(QIcon("images/editmirrorvert.png"), "Mirror &Vertically", self)
editMirrorVerticalAction.setShortcut("Ctrl+V")
editMirrorVerticalAction.setToolTip("Vertically mirror the image")
editMirrorVerticalAction.setStatusTip("Vertically mirror the image")
editMirrorVerticalAction.setCheckable(True)
editMirrorVerticalAction.toggled.connect(self.editMirrorVertical)
mirrorGroup = QActionGroup(self)
mirrorGroup.addAction(self.editUnMirrorAction)
mirrorGroup.addAction(editMirrorHorizontalAction)
mirrorGroup.addAction(editMirrorVerticalAction)
#菜单栏
self.fileMenu = self.menuBar().addMenu("&File")
self.fileMenu.addAction(self.fileOpenAction)
self.fileMenu.addAction(self.fileSaveAction)
editMenu = self.menuBar().addMenu("&Edit")
editMenu.addAction(self.editUnMirrorAction)
editMenu.addAction(editMirrorHorizontalAction)
editMenu.addAction(editMirrorVerticalAction)
#工具栏
fileToolbar = self.addToolBar("File")
fileToolbar.addAction(self.fileOpenAction)
fileToolbar.addAction(self.fileSaveAction)
editToolbar = self.addToolBar("Edit")
editToolbar.addAction(self.editUnMirrorAction)
editToolbar.addAction(editMirrorHorizontalAction)
editToolbar.addAction(editMirrorVerticalAction)
self.recentFiles = []
self.setWindowTitle("Image Changer")
def okToContinue(self): #警告当前图像未保存
if self.dirty:
reply = QMessageBox.question(self,
"Image Changer - Unsaved Changes",
"Save unsaved changes?",
QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
if reply == QMessageBox.Cancel:
return False
elif reply == QMessageBox.Yes:
return self.fileSaveAs()
return True
def fileOpen(self):
if not self.okToContinue():
return
dir = (os.path.dirname(self.filename)
if self.filename is not None else ".")
formats = (["*.{}".format(format.data().decode("ascii").lower())
for format in QImageReader.supportedImageFormats()])
fname = QFileDialog.getOpenFileName(self,
"Image Changer - Choose Image", dir,
"Image files ({})".format(" ".join(formats)))
if fname:
print(fname[0])
self.loadFile(fname[0])
self.updateFileMenu()
def loadFile(self, fname=None):
if fname is None:
action = self.sender()
if isinstance(action, QAction):
fname = action.data()
if not self.okToContinue():
return
else:
return
if fname:
self.filename = None
image = QImage(fname)
if image.isNull():
message = "Failed to read {}".format(fname)
else:
self.addRecentFile(fname)
self.image = QImage()
self.editUnMirrorAction.setChecked(True)
self.image = image
self.filename = fname
self.showImage()
self.dirty = False
self.sizeLabel.setText("{} x {}".format(
image.width(), image.height()))
message = "Loaded {}".format(os.path.basename(fname))
self.updateStatus(message)
def updateStatus(self, message):
self.statusBar().showMessage(message, 5000)
self.listWidget.addItem(message)
if self.filename:
self.setWindowTitle("Image Changer - {}[*]".format(
os.path.basename(self.filename)))
elif not self.image.isNull():
self.setWindowTitle("Image Changer - Unnamed[*]")
else:
self.setWindowTitle("Image Changer[*]")
self.setWindowModified(self.dirty)
def updateFileMenu(self):
self.fileMenu.clear()
self.fileMenu.addAction(self.fileOpenAction)
self.fileMenu.addAction(self.fileSaveAction)
current = self.filename
recentFiles = []
print(self.recentFiles)
for fname in self.recentFiles:
if fname != current and QFile.exists(fname):
recentFiles.append(fname)
if recentFiles:
self.fileMenu.addSeparator()
for i, fname in enumerate(recentFiles):
action = QAction(QIcon("images/icon.png"),
"&{} {}".format(i + 1, QFileInfo(
fname).fileName()), self)
action.setData(fname)
action.triggered.connect(lambda: self.loadFile(fname))
self.fileMenu.addAction(action)
def addRecentFile(self, fname):
if fname is None:
return
if fname not in self.recentFiles:
if len(self.recentFiles) < 10:
self.recentFiles = [fname] + self.recentFiles
else:
self.recentFiles = [fname] + self.recentFiles[:8]
print(len(self.recentFiles))
def fileSaveAs(self):
if self.image.isNull():
return True
fname = self.filename if self.filename is not None else "."
formats = (["*.{}".format(format.data().decode("ascii").lower())
for format in QImageWriter.supportedImageFormats()])
fname = QFileDialog.getSaveFileName(self,
"Image Changer - Save Image", fname,
"Image files ({})".format(" ".join(formats)))
fname = fname[0]
if fname:
print(fname)
if "." not in fname:
fname += ".png"
self.addRecentFile(fname)
self.filename = fname
if self.image.save(self.filename, None):
self.updateStatus("Saved as {}".format(self.filename))
self.dirty = False
return True
else:
self.updateStatus("Failed to save {}".format(
self.filename))
return False
return False
def editUnMirror(self, on):
if self.image.isNull():
return
if self.mirroredhorizontally:
self.editMirrorHorizontal(False)
if self.mirroredvertically:
self.editMirrorVertical(False)
def editMirrorHorizontal(self, on):
if self.image.isNull():
return
self.image = self.image.mirrored(True, False)
self.showImage()
self.mirroredhorizontally = not self.mirroredhorizontally
self.dirty = True
self.updateStatus(("Mirrored Horizontally"
if on else "Unmirrored Horizontally"))
def editMirrorVertical(self, on):
if self.image.isNull():
return
self.image = self.image.mirrored(False, True)
self.showImage()
self.mirroredvertically = not self.mirroredvertically
self.dirty = True
self.updateStatus(("Mirrored Vertically"
if on else "Unmirrored Vertically"))
def showImage(self, percent=None):
if self.image.isNull():
return
self.imageLabel.setPixmap(QPixmap.fromImage(self.image))
app = QApplication(sys.argv)
form = myMainWindow()
form.setMinimumSize(1000, 1000)
form.show()
app.exec_()
代码的运行效果:
根据老师提出的问题,我的解决方案参考了网上其他博客的代码:
在这里插入代码片
# 参考本节例程,实现一个鼠标绘图程序:
# 可以更改笔刷的颜色和粗细,具体方式自己设计,合理即可
# 可以读取和保存图片
import platform
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWidgets import QApplication
import sys
from PyQt5.QtWidgets import QWidget
from PyQt5.Qt import QPixmap, QPainter, QPoint, QPaintEvent, QMouseEvent, QPen,\
QColor, QSize
from PyQt5.QtCore import Qt
from PyQt5.Qt import QWidget, QColor, QPixmap, QIcon, QSize, QCheckBox
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout, QPushButton, QSplitter,\
QComboBox, QLabel, QSpinBox, QFileDialog
def main():
app = QApplication(sys.argv)
mainWidget = MainWidget() #新建一个主界面
mainWidget.show() #显示主界面
exit(app.exec_()) #进入消息循环
class PaintBoard(QWidget):
def __init__(self, Parent=None):
'''
Constructor
'''
super().__init__(Parent)
self.__InitData() # 先初始化数据,再初始化界面
self.__InitView()
self.setWindowTitle("画笔")
def __InitData(self):
self.__size = QSize(480, 460)
# 新建QPixmap作为画板,尺寸为__size
self.__board = QPixmap(self.__size)
self.__board.fill(Qt.white) # 用白色填充画板
self.__IsEmpty = True # 默认为空画板
self.EraserMode = False # 默认为禁用橡皮擦模式
self.__lastPos = QPoint(0, 0) # 上一次鼠标位置
self.__currentPos = QPoint(0, 0) # 当前的鼠标位置
self.__painter = QPainter() # 新建绘图工具
self.__thickness = 10 # 默认画笔粗细为10px
self.__penColor = QColor("black") # 设置默认画笔颜色为黑色
self.__colorList = QColor.colorNames() # 获取颜色列表
def __InitView(self):
# 设置界面的尺寸为__size
self.setFixedSize(self.__size)
def Clear(self):
# 清空画板
self.__board.fill(Qt.white)
self.update()
self.__IsEmpty = True
def ChangePenColor(self, color="black"):
# 改变画笔颜色
self.__penColor = QColor(color)
def ChangePenThickness(self, thickness=10):
# 改变画笔粗细
self.__thickness = thickness
def IsEmpty(self):
# 返回画板是否为空
return self.__IsEmpty
def GetContentAsQImage(self):
# 获取画板内容(返回QImage)
image = self.__board.toImage()
return image
def paintEvent(self, paintEvent):
# 绘图事件
# 绘图时必须使用QPainter的实例,此处为__painter
# 绘图在begin()函数与end()函数间进行
# begin(param)的参数要指定绘图设备,即把图画在哪里
# drawPixmap用于绘制QPixmap类型的对象
self.__painter.begin(self)
# 0,0为绘图的左上角起点的坐标,__board即要绘制的图
self.__painter.drawPixmap(0, 0, self.__board)
self.__painter.end()
def mousePressEvent(self, mouseEvent):
# 鼠标按下时,获取鼠标的当前位置保存为上一次位置
self.__currentPos = mouseEvent.pos()
self.__lastPos = self.__currentPos
def mouseMoveEvent(self, mouseEvent):
# 鼠标移动时,更新当前位置,并在上一个位置和当前位置间画线
self.__currentPos = mouseEvent.pos()
self.__painter.begin(self.__board)
if self.EraserMode == False:
# 非橡皮擦模式
self.__painter.setPen(QPen(self.__penColor, self.__thickness)) # 设置画笔颜色,粗细
else:
# 橡皮擦模式下画笔为纯白色,粗细为10
self.__painter.setPen(QPen(Qt.white, 10))
# 画线
self.__painter.drawLine(self.__lastPos, self.__currentPos)
self.__painter.end()
self.__lastPos = self.__currentPos
self.update() # 更新显示
def mouseReleaseEvent(self, mouseEvent):
self.__IsEmpty = False # 画板不再为空
class MainWidget(QWidget):
def __init__(self, Parent=None):
'''
Constructor
'''
super().__init__(Parent)
self.__InitData() # 先初始化数据,再初始化界面
self.__InitView()
def __InitData(self):
'''
初始化成员变量
'''
self.__paintBoard = PaintBoard(self)
# 获取颜色列表(字符串类型)
self.__colorList = QColor.colorNames()
def __InitView(self):
'''
初始化界面
'''
self.setFixedSize(640, 480)
self.setWindowTitle("Paint brush")
# 新建一个水平布局作为本窗体的主布局
main_layout = QHBoxLayout(self)
# 设置主布局内边距以及控件间距为10px
main_layout.setSpacing(10)
# 在主界面左侧放置画板
main_layout.addWidget(self.__paintBoard)
# 新建垂直子布局用于放置按键
sub_layout = QVBoxLayout()
# 设置此子布局和内部控件的间距为10px
sub_layout.setContentsMargins(10, 10, 10, 10)
self.__btn_Clear = QPushButton("清空画板")
self.__btn_Clear.setParent(self) # 设置父对象为本界面
# 将按键按下信号与画板清空函数相关联
self.__btn_Clear.clicked.connect(self.__paintBoard.Clear)
sub_layout.addWidget(self.__btn_Clear)
self.__btn_Quit = QPushButton("退出")
self.__btn_Quit.setParent(self) # 设置父对象为本界面
self.__btn_Quit.clicked.connect(self.Quit)
sub_layout.addWidget(self.__btn_Quit)
self.__btn_Save = QPushButton("保存作品")
self.__btn_Save.setParent(self)
self.__btn_Save.clicked.connect(self.on_btn_Save_Clicked)
sub_layout.addWidget(self.__btn_Save)
self.__cbtn_Eraser = QCheckBox(" 使用橡皮擦")
self.__cbtn_Eraser.setParent(self)
self.__cbtn_Eraser.clicked.connect(self.on_cbtn_Eraser_clicked)
sub_layout.addWidget(self.__cbtn_Eraser)
splitter = QSplitter(self) # 占位符
sub_layout.addWidget(splitter)
self.__label_penThickness = QLabel(self)
self.__label_penThickness.setText("画笔粗细")
self.__label_penThickness.setFixedHeight(20)
sub_layout.addWidget(self.__label_penThickness)
self.__spinBox_penThickness = QSpinBox(self)
self.__spinBox_penThickness.setMaximum(20)
self.__spinBox_penThickness.setMinimum(2)
self.__spinBox_penThickness.setValue(10) # 默认粗细为10
self.__spinBox_penThickness.setSingleStep(2) # 最小变化值为2
self.__spinBox_penThickness.valueChanged.connect(
self.on_PenThicknessChange) # 关联spinBox值变化信号和函数on_PenThicknessChange
sub_layout.addWidget(self.__spinBox_penThickness)
self.__label_penColor = QLabel(self)
self.__label_penColor.setText("画笔颜色")
self.__label_penColor.setFixedHeight(20)
sub_layout.addWidget(self.__label_penColor)
self.__comboBox_penColor = QComboBox(self)
self.__fillColorList(self.__comboBox_penColor) # 用各种颜色填充下拉列表
self.__comboBox_penColor.currentIndexChanged.connect(
self.on_PenColorChange) # 关联下拉列表的当前索引变更信号与函数on_PenColorChange
sub_layout.addWidget(self.__comboBox_penColor)
main_layout.addLayout(sub_layout) # 将子布局加入主布局
def __fillColorList(self, comboBox):
index_black = 0
index = 0
for color in self.__colorList:
if color == "black":
index_black = index
index += 1
pix = QPixmap(70, 20)
pix.fill(QColor(color))
comboBox.addItem(QIcon(pix), None)
comboBox.setIconSize(QSize(70, 20))
comboBox.setSizeAdjustPolicy(QComboBox.AdjustToContents)
comboBox.setCurrentIndex(index_black)
def on_PenColorChange(self):
color_index = self.__comboBox_penColor.currentIndex()
color_str = self.__colorList[color_index]
self.__paintBoard.ChangePenColor(color_str)
def on_PenThicknessChange(self):
penThickness = self.__spinBox_penThickness.value()
self.__paintBoard.ChangePenThickness(penThickness)
def on_btn_Save_Clicked(self):
savePath = QFileDialog.getSaveFileName(self, 'Save Your Paint', '.\\', '*.png')
print(savePath)
if savePath[0] == "":
print("Save cancel")
return
image = self.__paintBoard.GetContentAsQImage()
image.save(savePath[0])
def on_cbtn_Eraser_clicked(self):
if self.__cbtn_Eraser.isChecked():
self.__paintBoard.EraserMode = True # 进入橡皮擦模式
else:
self.__paintBoard.EraserMode = False # 退出橡皮擦模式
def Quit(self):
self.close()
if __name__ == '__main__':
main()
代码实现效果: