Qt designer+PyQt5实现多文本文档编辑器基本功能和拓展功能(School Project)

暑假在家时自学了一段时间的python,开学后学校要求写一个多文本文档编辑器。听说Qt designer和PyQt5结合起来写代码会非常方便,做出来的界面比tkinter和wxPython好看许多,于是决定试一试。我在文件加载部分参照了《Python Qt GUI快速编程》的代码,为了保存文件加粗、颜色等.txt不能保存的格式,于是在文件保存过程中又增加.html类型。

运行效果如下:

在这里插入图片描述

程序里的图标文件可以在icon8官网下载,免费实用又好看。我这里使用的是office风格。下载地址:https://icons8.cn/icon/new-icons/all

下面是源代码(各文件在同一目录下):

1. Qt designer生成panel.ui后生成的 panel.py文件。由于Qt里工具栏不支持添加FontComboBox控件,因此需要手动添加

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'E:\多文档编辑器\panel.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1132, 729)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.mdiArea = QtWidgets.QMdiArea(self.centralwidget)
        self.mdiArea.setObjectName("mdiArea")
        self.verticalLayout.addWidget(self.mdiArea)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1132, 30))
        self.menubar.setObjectName("menubar")
        self.menu = QtWidgets.QMenu(self.menubar)
        self.menu.setObjectName("menu")
        self.menu_2 = QtWidgets.QMenu(self.menubar)
        self.menu_2.setObjectName("menu_2")
        self.menu_3 = QtWidgets.QMenu(self.menubar)
        self.menu_3.setObjectName("menu_3")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.toolBar = QtWidgets.QToolBar(MainWindow)
        self.toolBar.setObjectName("toolBar")
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
        self.actionNew = QtWidgets.QAction(MainWindow)
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("icons8-新文件-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionNew.setIcon(icon)
        self.actionNew.setAutoRepeat(False)
        self.actionNew.setObjectName("actionNew")
        self.actionOpen = QtWidgets.QAction(MainWindow)
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("icons8-打开文件夹-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionOpen.setIcon(icon1)
        self.actionOpen.setObjectName("actionOpen")
        self.actionSave = QtWidgets.QAction(MainWindow)
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("icons8-保存-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        icon2.addPixmap(QtGui.QPixmap("icons8-保存-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.On)
        self.actionSave.setIcon(icon2)
        self.actionSave.setObjectName("actionSave")
        self.actionClose = QtWidgets.QAction(MainWindow)
        icon3 = QtGui.QIcon()
        icon3.addPixmap(QtGui.QPixmap("icons8-删除-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionClose.setIcon(icon3)
        self.actionClose.setObjectName("actionClose")
        self.actionPile = QtWidgets.QAction(MainWindow)
        icon4 = QtGui.QIcon()
        icon4.addPixmap(QtGui.QPixmap("icons8-一堆钱-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionPile.setIcon(icon4)
        self.actionPile.setObjectName("actionPile")
        self.actionHorizontal = QtWidgets.QAction(MainWindow)
        icon5 = QtGui.QIcon()
        icon5.addPixmap(QtGui.QPixmap("icons8-水平标志-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionHorizontal.setIcon(icon5)
        self.actionHorizontal.setObjectName("actionHorizontal")
        self.actionVertical = QtWidgets.QAction(MainWindow)
        icon6 = QtGui.QIcon()
        icon6.addPixmap(QtGui.QPixmap("icons8-竖旗-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionVertical.setIcon(icon6)
        self.actionVertical.setObjectName("actionVertical")
        self.actionCut = QtWidgets.QAction(MainWindow)
        icon7 = QtGui.QIcon()
        icon7.addPixmap(QtGui.QPixmap("icons8-剪刀-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionCut.setIcon(icon7)
        self.actionCut.setObjectName("actionCut")
        self.actionCopy = QtWidgets.QAction(MainWindow)
        icon8 = QtGui.QIcon()
        icon8.addPixmap(QtGui.QPixmap("icons8-复制-30.png"), QtGui.QIcon.Normal, QtGui.QIcon.On)
        icon8.addPixmap(QtGui.QPixmap("icons8-复制-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionCopy.setIcon(icon8)
        self.actionCopy.setObjectName("actionCopy")
        self.actionPaste = QtWidgets.QAction(MainWindow)
        icon9 = QtGui.QIcon()
        icon9.addPixmap(QtGui.QPixmap("icons8-粘贴-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionPaste.setIcon(icon9)
        self.actionPaste.setObjectName("actionPaste")
        self.actionSearch = QtWidgets.QAction(MainWindow)
        icon10 = QtGui.QIcon()
        icon10.addPixmap(QtGui.QPixmap("icons8-搜索-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionSearch.setIcon(icon10)
        self.actionSearch.setObjectName("actionSearch")
        self.actionBold = QtWidgets.QAction(MainWindow)
        icon11 = QtGui.QIcon()
        icon11.addPixmap(QtGui.QPixmap("icons8-粗体-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionBold.setIcon(icon11)
        self.actionBold.setObjectName("actionBold")
        self.actionItalic = QtWidgets.QAction(MainWindow)
        icon12 = QtGui.QIcon()
        icon12.addPixmap(QtGui.QPixmap("icons8-斜体-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionItalic.setIcon(icon12)
        self.actionItalic.setObjectName("actionItalic")
        self.actionDelete = QtWidgets.QAction(MainWindow)
        icon13 = QtGui.QIcon()
        icon13.addPixmap(QtGui.QPixmap("icons8-撤销-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionDelete.setIcon(icon13)
        self.actionDelete.setObjectName("actionDelete")
        self.actionRecover = QtWidgets.QAction(MainWindow)
        icon14 = QtGui.QIcon()
        icon14.addPixmap(QtGui.QPixmap("icons8-恢复-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionRecover.setIcon(icon14)
        self.actionRecover.setObjectName("actionRecover")
        self.actionLeft = QtWidgets.QAction(MainWindow)
        icon15 = QtGui.QIcon()
        icon15.addPixmap(QtGui.QPixmap("icons8-左对齐-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionLeft.setIcon(icon15)
        self.actionLeft.setObjectName("actionLeft")
        self.actionRight = QtWidgets.QAction(MainWindow)
        icon16 = QtGui.QIcon()
        icon16.addPixmap(QtGui.QPixmap("icons8-右对齐-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionRight.setIcon(icon16)
        self.actionRight.setObjectName("actionRight")
        self.actionCenter = QtWidgets.QAction(MainWindow)
        icon17 = QtGui.QIcon()
        icon17.addPixmap(QtGui.QPixmap("icons8-居中对齐-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionCenter.setIcon(icon17)
        self.actionCenter.setObjectName("actionCenter")
        self.actionUnderline = QtWidgets.QAction(MainWindow)
        icon18 = QtGui.QIcon()
        icon18.addPixmap(QtGui.QPixmap("icons8-下划线-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionUnderline.setIcon(icon18)
        self.actionUnderline.setObjectName("actionUnderline")
        self.actionFont = QtWidgets.QAction(MainWindow)
        icon19 = QtGui.QIcon()
        icon19.addPixmap(QtGui.QPixmap("icons8-类型-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionFont.setIcon(icon19)
        self.actionFont.setObjectName("actionFont")
        self.actionColor = QtWidgets.QAction(MainWindow)
        icon20 = QtGui.QIcon()
        icon20.addPixmap(QtGui.QPixmap("icons8-文字颜色-30.png"), QtGui.QIcon.Selected, QtGui.QIcon.Off)
        self.actionColor.setIcon(icon20)
        self.actionColor.setObjectName("actionColor")
        self.fontComboBox = QtWidgets.QFontComboBox()
        self.menu.addAction(self.actionNew)
        self.menu.addAction(self.actionOpen)
        self.menu.addAction(self.actionSave)
        self.menu.addSeparator()
        self.menu.addAction(self.actionClose)
        self.menu_2.addAction(self.actionPile)
        self.menu_2.addAction(self.actionHorizontal)
        self.menu_2.addAction(self.actionVertical)
        self.menu_3.addAction(self.actionCut)
        self.menu_3.addAction(self.actionCopy)
        self.menu_3.addAction(self.actionPaste)
        self.menu_3.addSeparator()
        self.menu_3.addAction(self.actionSearch)
        self.menubar.addAction(self.menu.menuAction())
        self.menubar.addAction(self.menu_3.menuAction())
        self.menubar.addAction(self.menu_2.menuAction())
        self.toolBar.addAction(self.actionNew)
        self.toolBar.addAction(self.actionOpen)
        self.toolBar.addAction(self.actionSave)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionCut)
        self.toolBar.addAction(self.actionCopy)
        self.toolBar.addAction(self.actionPaste)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionDelete)
        self.toolBar.addAction(self.actionRecover)
        self.toolBar.addSeparator()
        self.toolBar.addWidget(self.fontComboBox)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionBold)
        self.toolBar.addAction(self.actionItalic)
        self.toolBar.addAction(self.actionUnderline)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionFont)
        self.toolBar.addAction(self.actionColor)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionLeft)
        self.toolBar.addAction(self.actionCenter)
        self.toolBar.addAction(self.actionRight)
        self.toolBar.addSeparator()
        self.toolBar.addAction(self.actionSearch)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.menu.setTitle(_translate("MainWindow", "文件"))
        self.menu_2.setTitle(_translate("MainWindow", "视图"))
        self.menu_3.setTitle(_translate("MainWindow", "编辑"))
        self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
        self.actionNew.setText(_translate("MainWindow", "新建(&N)"))
        self.actionNew.setToolTip(_translate("MainWindow", "新建(N)"))
        self.actionNew.setShortcut(_translate("MainWindow", "Ctrl+N"))
        self.actionOpen.setText(_translate("MainWindow", "打开(&O)"))
        self.actionOpen.setShortcut(_translate("MainWindow", "Ctrl+O"))
        self.actionSave.setText(_translate("MainWindow", "保存(&S)"))
        self.actionSave.setShortcut(_translate("MainWindow", "Ctrl+S"))
        self.actionClose.setText(_translate("MainWindow", "退出(&Q)"))
        self.actionClose.setShortcut(_translate("MainWindow", "Ctrl+Q"))
        self.actionPile.setText(_translate("MainWindow", "平铺"))
        self.actionHorizontal.setText(_translate("MainWindow", "水平布局"))
        self.actionVertical.setText(_translate("MainWindow", "垂直布局"))
        self.actionCut.setText(_translate("MainWindow", "剪切(&X)"))
        self.actionCut.setShortcut(_translate("MainWindow", "Ctrl+X"))
        self.actionCopy.setText(_translate("MainWindow", "复制(&C)"))
        self.actionCopy.setShortcut(_translate("MainWindow", "Ctrl+C"))
        self.actionPaste.setText(_translate("MainWindow", "粘贴(&V)"))
        self.actionPaste.setShortcut(_translate("MainWindow", "Ctrl+V"))
        self.actionSearch.setText(_translate("MainWindow", "查找(&Q)"))
        self.actionSearch.setShortcut(_translate("MainWindow", "Alt+Q"))
        self.actionBold.setText(_translate("MainWindow", "Bold"))
        self.actionItalic.setText(_translate("MainWindow", "Italic"))
        self.actionDelete.setText(_translate("MainWindow", "Delete"))
        self.actionRecover.setText(_translate("MainWindow", "Recover"))
        self.actionLeft.setText(_translate("MainWindow", "Left"))
        self.actionRight.setText(_translate("MainWindow", "Right"))
        self.actionCenter.setText(_translate("MainWindow", "Center"))
        self.actionUnderline.setText(_translate("MainWindow", "Underline"))
        self.actionFont.setText(_translate("MainWindow", "字体"))
        self.actionColor.setText(_translate("MainWindow", "颜色"))

2.textedit.py实现对单个文本窗口的封装。

# -*- coding: utf-8 -*-
from PyQt5.QtCore import QFile, QFileInfo, QIODevice, QTextStream, Qt
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QTextEdit
#from zopyx.convert2 import Converter

class TextEdit(QTextEdit):
    NextId = 1
    def __init__(self, filename="", parent=None):
        super(TextEdit, self).__init__(parent)
        self.setAttribute(Qt.WA_DeleteOnClose, True)
        self.filename = filename
        if self.filename == "":
            self.filename = "Untitled-{0}".format(TextEdit.NextId)
            TextEdit.NextId += 1
        self.document().setModified(False)
        self.windowName = QFileInfo(self.filename).fileName()
        self.setWindowTitle(self.windowName)
    
    def closeEvent(self, event):
        if self.document().isModified():
            dlg = QMessageBox.question(self, "Notepad", "是否保存对'{0}'的修改?".format(self.windowName),QMessageBox.Yes|QMessageBox.No|QMessageBox.Cancel)
            if dlg == QMessageBox.Yes:
                self.save()
            elif dlg == QMessageBox.No:
                self.close()
            else:
                event.ignore()


    def isModified(self):
        return self.document().isModified()


    def save(self):
        if self.filename.startswith("Untitled"):
            self.filename = QFileDialog.getSaveFileName(self, "保存文件", self.filename,"Text files (*.txt);;HTML files (*.html)")[0]
        self.windowName = QFileInfo(self.filename).fileName()
        with open(self.filename, 'w') as file_path:
            if 'rtf' in self.windowName:
                file_path.write(self.toHtml())
            if 'txt' in self.windowName:
                file_path.write(self.toPlainText())
        self.setWindowTitle(QFileInfo(self.filename).fileName())
        self.document().setModified(False)

    def load(self):
        fh = None
        try:
            fh = QFile(self.filename)
            if not fh.open(QIODevice.ReadOnly):
                raise IOError(str(fh.errorString()))
            stream = QTextStream(fh)
#            stream.setCodec("UTF-8")
            self.setPlainText(stream.readAll())
            self.document().setModified(False)
        except EnvironmentError as e:
            QMessageBox.warning(self,"加载错误"
                    "不能加载 {0}".format(self.filename))
        finally:
            if fh is not None:
                fh.close()
        self.setWindowTitle(QFileInfo(self.filename).fileName())

3.editor.py实现基本功能

import sys
import os
import panel
import textedit
from PyQt5.QtCore import Qt
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QWidget, QApplication, QColorDialog, QFontDialog, QTextEdit, QFileDialog, QMessageBox
from PyQt5.QtCore import QFile, QFileInfo
from PyQt5.QtGui import QPalette,QTextCursor

class Editor(QtWidgets.QMainWindow, panel.Ui_MainWindow):
    def __init__(self, parent=None):
        super(Editor, self).__init__(parent)
        self.setupUi(self)
        self.setWindowTitle("Notepad")
        self.actionOpen.triggered.connect(self.fileOpen)
        self.actionNew.triggered.connect(self.fileNew)
        self.actionSave.triggered.connect(self.fileSave)
        self.actionClose.triggered.connect(self.closeEvent)
        self.actionPile.triggered.connect(self.filePile)
        self.actionHorizontal.triggered.connect(self.fileHorizontal)
        self.actionVertical.triggered.connect(self.fileVertical)
        self.actionDelete.triggered.connect(self.fileUndo)
        self.actionRecover.triggered.connect(self.fileRedo)
        self.actionCopy.triggered.connect(self.fileCopy)
        self.actionCut.triggered.connect(self.fileCut)
        self.actionPaste.triggered.connect(self.filePaste)
        self.actionBold.triggered.connect(self.fileBold)
        self.actionItalic.triggered.connect(self.fileItalic)
        self.actionUnderline.triggered.connect(self.fileUnderline)
        self.fontComboBox.currentFontChanged.connect(self.fileChangeFont)
        self.actionSearch.triggered.connect(self.fileSearch)
        self.actionLeft.triggered.connect(self.fileLeft)
        self.actionRight.triggered.connect(self.fileRight)
        self.actionFont.triggered.connect(self.fileFontBox)
        self.actionColor.triggered.connect(self.fileColorBox)
        
    def fileFontBox(self):
        font, okPressed = QFontDialog.getFont()
        if okPressed:
            self.mdiArea.activeSubWindow().widget().setCurrentFont(font)
    def fileColorBox(self):
        col = QColorDialog.getColor()
        if col.isValid():
            self.mdiArea.activeSubWindow().widget().setTextColor(col)
    def fileLeft(self):
        self.mdiArea.activeSubWindow().widget().setAlignment(Qt.AlignLeft)
        
    def fileRight(self):
        self.mdiArea.activeSubWindow().widget().setAlignment(Qt.AlignRight)
        
    def fileCenter(self):
        self.mdiArea.activeSubWindow().widget().setAlignment(Qt.AlignCenter)

    def fileHorizontal(self):
        wList = self.mdiArea.subWindowList()
        size = len(wList)
        if size > 0:
            position = QtCore.QPoint(0, 0)
            for w in wList:
                rect = QtCore.QRect(0, 0,  self.mdiArea.width() / size,
                         self.mdiArea.height())
                w.setGeometry(rect)
                w.move(position)
                position.setX(position.x() + w.width())

    def fileVertical(self):
        wList =  self.mdiArea.subWindowList()
        size = len(wList)
        if size > 0:
            position = QtCore.QPoint(0, 0)
            for w in wList:
                rect = QtCore.QRect(0, 0, self.mdiArea.width(),
                         self.mdiArea.height() / size)
                w.setGeometry(rect)
                w.move(position)
                position.setY(position.y() + w.height())

    def fileChangeFont(self, font):
        self.mdiArea.activeSubWindow().widget().setCurrentFont(font)

    def fileSearch(self):
        pattern, okPressed = QtWidgets.QInputDialog.getText(self,
                "查找", "查找字符串:", QtWidgets.QLineEdit.Normal, "")
        if okPressed and pattern != '':
            sub = self.mdiArea.activeSubWindow().widget()
            sub.moveCursor(QTextCursor.StartOfLine, QTextCursor.MoveAnchor)
            if sub.find(pattern):
                palette = sub.palette()
                palette.setColor(QPalette.Highlight, palette.color(QPalette.Active,QPalette.Highlight))
                sub.setPalette(palette)

    def fileBold(self):
        sub = self.mdiArea.activeSubWindow().widget()
        tmpFormat = sub.currentCharFormat()
        if tmpFormat.fontWeight() == QtGui.QFont.Bold:
            tmpFormat.setFontWeight(QtGui.QFont.Normal)
        else:
            tmpFormat.setFontWeight(QtGui.QFont.Bold)
        sub.mergeCurrentCharFormat(tmpFormat)

    def fileItalic(self):
        tmpTextBox = self.mdiArea.activeSubWindow().widget()
        tmpTextBox.setFontItalic(not tmpTextBox.fontItalic())

    def fileUnderline(self):
        tmpTextBox = self.mdiArea.activeSubWindow().widget()
        tmpTextBox.setFontUnderline(not tmpTextBox.fontUnderline())

    def fileCopy(self):
        self.mdiArea.activeSubWindow().widget().copy()
        
    def fileCut(self):
        self.mdiArea.activeSubWindow().widget().cut()
        
    def filePaste(self):
        self.mdiArea.activeSubWindow().widget().paste()

    def fileRedo(self):
        self.mdiArea.activeSubWindow().widget().redo()

    def fileUndo(self):
        self.mdiArea.activeSubWindow().widget().undo()

    def filePile(self):
        if len(self.mdiArea.subWindowList()) > 1:
            self.mdiArea.cascadeSubWindows()

    def fileSave(self):
        tmpTextEdit = self.mdiArea.activeSubWindow()
        tmpTextEdit=tmpTextEdit.widget()
        if tmpTextEdit is None or not isinstance(tmpTextEdit, QTextEdit):
            return True
        tmpTextEdit.save()

    def fileOpen(self):
        filename,filetype = QFileDialog.getOpenFileName(self,"打开文件","C:","Text files (*.txt);;HTML files (*html)")
        if filename:
            for window in self.mdiArea.subWindowList():
                textEdit=window.widget()
                if textEdit.filename == filename:
                    self.mdiArea.setActiveSubWindow(window)
                    break
            else:
                self.loadFile(filename)
               
    def fileNew(self):
        tmpTextEdit = textedit.TextEdit()
        self.mdiArea.addSubWindow(tmpTextEdit)
        tmpTextEdit.show()
            
    def loadFile(self, filename):
        tmpTextEdit = textedit.TextEdit(filename)
        tmpTextEdit.load()
        self.mdiArea.addSubWindow(tmpTextEdit)
        tmpTextEdit.show()

    def closeEvent(self, event):
        unSaveFile = 0
        for window in self.mdiArea.subWindowList():
            textEdit = window.widget()
            if textEdit.isModified():
                unSaveFile += 1
        if unSaveFile != 0:
            dlg = QMessageBox.warning(self, "Notepad", "{0}个文档尚未保存,是否关闭?".format(unSaveFile), QMessageBox.Yes|QMessageBox.No)
            if dlg == QMessageBox.Yes:
                 QtCore.QCoreApplication.quit()
            elif dlg == QMessageBox.No:
                event.ignore()

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    ex = Editor()
    ex.show()
    app.exec_()

每种语言都有自己擅长的领域,感觉C#实现会更容易一些。

猜你喜欢

转载自blog.csdn.net/weixin_40837922/article/details/82918052