PyQt5(一):加载图片画框框并保存

PyQt5(一):加载图片画框框并保存

环境

  • Win10
  • PyCharm2019 社区版
  • PyQt5
  • Qt Designer

设计界面

     使用Qt Designer进行快速设计,选择 MainWindow,在左侧添加 QLabel 和两个 PushButton。其中,QLabel 用于显示图片,两个按键分别用于获取图片和保存图片。

    设计如下:

在这里插入图片描述

    然后对生成的 .ui文件转换为 .py 代码文件。但注意这里代码需要进行一个改动,见下面代码注释。

from PyQt5 import QtCore, QtGui, QtWidgets
from drawline import MyLabel

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(600, 480)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setGeometry(QtCore.QRect(140, 370, 131, 41))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.pushButton.setFont(font)
        self.pushButton.setObjectName("pushButton")
		
		# 生成代码为:
		# self.label = QtWidgets.QLabel(self.centralwidget)
		# 这里改为MyLabel,因为QLabel的鼠标点击事件没有具体实现,我们需要重写这个类的鼠标点击方法
        self.label = MyLabel(self.centralwidget)
        self.label.setGeometry(QtCore.QRect(110, 40, 401, 281))
        self.label.setText("")
        self.label.setObjectName("label")

        self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_2.setGeometry(QtCore.QRect(360, 370, 131, 41))
        font = QtGui.QFont()
        font.setFamily("Arial")
        font.setPointSize(14)
        self.pushButton_2.setFont(font)
        self.pushButton_2.setObjectName("pushButton_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 600, 22))
        self.menubar.setObjectName("menubar")
        self.menuOpen = QtWidgets.QMenu(self.menubar)
        self.menuOpen.setObjectName("menuOpen")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.actionNew = QtWidgets.QAction(MainWindow)
        self.actionNew.setObjectName("actionNew")
        self.menuOpen.addAction(self.actionNew)
        self.menubar.addAction(self.menuOpen.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton.setText(_translate("MainWindow", "Get Image"))
        self.pushButton_2.setText(_translate("MainWindow", "Save Image"))
        self.menuOpen.setTitle(_translate("MainWindow", "Open"))
        self.actionNew.setText(_translate("MainWindow", "New"))

重写QLabel

  • 写一个 MyLabel 类继承 QLabel
  • 重写鼠标事件方法:paintEvent, mousePressEvent, mouseMoveEvent, mouseReleaseEvent,并记得先调用父类的该方法,看下面注释(否则可能功能失效)
  • 画矩形方法:当左键点击,保存左上角矩形点;鼠标拖动,不断复制 上一张图, 再在复制后的图绘制矩形,刷新界面;当左键释放,更新 上一张图 为当前图。
# -*- coding: utf-8 -*-

from PyQt5.QtWidgets import QLabel
from PyQt5.QtGui import QPainter, QPixmap, QPen
from PyQt5.QtCore import Qt, QPoint

class MyLabel(QLabel):
    def __init__(self, parent):
        super().__init__(parent)
        self.drawable = False
	
	# 是否允许作图
    def drawingPermission(self, a):
        if isinstance(a, bool):
            self.drawable = a
	# 初始化画布
    def initDrawing(self, img):
        self.pix = img	# 当前图
        self.tmpPix = self.pix.copy()	# 上一张图
        self.lastPoint = QPoint()
        self.endPoint = QPoint()

    def paintEvent(self, event):
    	# 先执行父类方法,必须加上
        super().paintEvent(event)
        if self.drawable:
            pp = QPainter(self)
            pp.begin(self)
            pp.drawPixmap(0, 0, self.pix)
            pp.end()

    def mousePressEvent(self, event):
    	# 先执行父类方法,可不加
        super().mousePressEvent(event)
        if self.drawable:
            # 鼠标左键按下
            if event.button() == Qt.LeftButton:
                self.lastPoint = event.pos()

    def mouseMoveEvent(self, event):
    	# 先执行父类方法,可不加
        super().mouseMoveEvent(event)
        if self.drawable:
            # 鼠标左键按下的同时移动鼠标
            if event.buttons() and Qt.LeftButton:
                self.endPoint = event.pos()
				
				# 当前图复制上一张图
                self.pix = self.tmpPix.copy()

                pp = QPainter(self.pix)
                pp.setPen(QPen(Qt.green, 5))
                pp.drawRect(self.lastPoint.x(), self.lastPoint.y(),
                                 self.endPoint.x() - self.lastPoint.x(),
                                 self.endPoint.y() - self.lastPoint.y())
				# 更新label
                self.update()

    def mouseReleaseEvent(self, event):
    	# 先执行父类方法,可不加
        super().mouseReleaseEvent(event)
        if self.drawable:
            # 鼠标左键释放
            if event.button() == Qt.LeftButton:
            	# 上一张图指向当前图
                self.tmpPix = self.pix

note: QPainter(device),中 device 是作图的上下文,也就是在哪作图(device上)。上面代码有QPainter(self) 和 QPainter(self.pix),这两个作图对象是不同的。

主函数

  • 初始化label背景
  • 按钮连接槽函数:打开选择文件框和保存文件框
import sys
from PIL import ImageQt, Image
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QLabel
from FileTest import Ui_MainWindow

class MyMainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        # 初始化label背景
        img = Image.open(r'./upload.jpg')
        img = self.transImg(img)
        self.label.setPixmap(img)
        # 设置当前不可作图
        self.flagPaint = False
	
        # connect the slot when you push the button
        self.pushButton.clicked.connect(self.getImage)
        self.pushButton_2.clicked.connect(self.saveImage)

    def getImage(self):
    	# 该方法会启动文件对话框,当你选择某文件后,返回文件绝对路径和文件类型
        fdir, ftype = QFileDialog.getOpenFileName(self,
                  "Select Image",
                  "./",
                  "Image Files (*.png *.jpg)")
		# 把选择的图片展示在label上
        img = Image.open(fdir)
        img = self.transImg(img)
        self.label.setPixmap(img)
		
		# 初始化画布,允许作图
        self.label.initDrawing(img)
        self.label.drawingPermission(True)
        self.flagPaint = True

    def saveImage(self):
        if self.flagPaint:
            img = self.label.pix.toImage()
            # 该方法同上
            fdir, ftype = QFileDialog.getSaveFileName(self, "Save Image",
		   "./", "Image Files (*.jpg)")
            img.save(fdir)

    def transImg(self, img):
        '''
        use to trans PIL img to Qt img
        :param img: PIL object
        :return: Qt object
        '''
        img = img.resize((self.label.width(), self.label.height()))
        return ImageQt.toqpixmap(img)

if __name__ == "__main__":
	# 此句解决Qt Designer和Pycharm显示不同的问题
    QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
    
    app = QApplication(sys.argv)
    myWin = MyMainWindow()
    myWin.show()
    sys.exit(app.exec_())

效果

在这里插入图片描述

在这里插入图片描述

参考

  1. https://blog.csdn.net/zzzzjh/article/details/82985209
  2. https://blog.csdn.net/jeekmary/article/details/79590570?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduend~default-3-79590570.nonecase&utm_term=pyqt%20%E8%AF%BB%E5%8F%96%E6%96%87%E4%BB%B6
  3. 《PyQt5快速开发与实践》王硕,孙洋洋 著
  • 4
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值