千家信息网

快捷方式管理(pyqt5升级版)附代码纯干货 pytq5 p

发表于:2024-11-23 作者:千家信息网编辑
千家信息网最后更新 2024年11月23日,之前用python写了个小软件https://blog.51cto.com/ikezcn/2142638说实话用tk的话界面确实不好看,所以需要改进,看了pyqt5的介绍想要试一下,对于上次写的软件来
千家信息网最后更新 2024年11月23日快捷方式管理(pyqt5升级版)附代码纯干货 pytq5 p

之前用python写了个小软件https://blog.51cto.com/ikezcn/2142638
说实话用tk的话界面确实不好看,所以需要改进,看了pyqt5的介绍想要试一下,对于上次写的软件来说这里只是更改了界面而已。上面的程序不再更新。

使用的软件:
python3.6
pyqt5 安装:pip insatll pyqt5

界面:

代码(干货来了,之后会不定时更新):

# -*- coding: utf-8 -*-#v2.0 2018-08-30更新#v2.1 2018-08-31更新#现在可以使用pyinsatller打包了,新增了样式表,就算没有数据库也会自己创建并增加数据表,隐藏列名#v2.2 2018-09-05更新#增加了左边一列用来做查询条件,双击就可以搜索.#右键右边的路径可以添加搜索条件.#最后遇到一个问题:多次使用setFilter会造成模型出现问题导致无法写入数据库,这里就直接跳过模型自己插入数据库#v2.3 2018-09-06更新#增加刷新菜单,显示所有路径,修复bug#v2.4 2018-09-11更新#小修小补import sys,osfrom PyQt5 import sipfrom PyQt5.QtCore import Qt,QVariant,QFile,QIODevice,QItemSelectionModelfrom PyQt5.QtSql import QSqlDatabase,QSqlTableModel,QSqlQuery,QSqlRecordfrom PyQt5.QtWidgets import QPushButton,QLabel,QCheckBox,QHBoxLayout,QVBoxLayout,QWidget,QMenu,QMainWindow,QMessageBox,QHeaderView,QAction, qApp, QApplication, QDesktopWidget , QGridLayout,QTableView,QAbstractItemViewfrom PyQt5.QtGui import QIcon,QContextMenuEventimport win32apiimport win32conclass Icon(QMainWindow):    def __init__(self,model,sqlite,query,view,sview,smodel):        super().__init__()        self.model = model        self.sqlite = sqlite        self.query = query        self.view = view        self.sview = sview        self.smodel = smodel        if self.sqlite.open():#如果没有找到数据库文件就自动创建            self.query.exec("select count(*) from sqlite_master where type='table' and name='lj'")            if self.query.next():                if self.query.value(0) == 0:                    self.query.prepare("CREATE TABLE lj(id integer primary key,lj text not NULL,isdel BOOLEAN DEFAULT 0)")                    if not self.query.exec():                        QMessageBox.information(self,"数据表创建失败",self.query.lastError().text())                    self.query.prepare("CREATE TABLE cxtj(cxtj text not NULL)")                    if not self.query.exec():                        QMessageBox.information(self,"数据表创建失败",self.query.lastError().text())        else:            QMessageBox.information(self,"程序将关闭",self.sqlite.lastError().text())            sys.exit(app.exec_())        self.setAcceptDrops(True)        self.statusBar().showMessage('Reday')        delAction = QAction("&删除", self)        delAction.setShortcut("Ctrl+D")        delAction.setStatusTip("删除选定的行")        delAction.triggered.connect(self.delrow)        deltableAction = QAction("&全部删除", self)        deltableAction.setStatusTip("删除所有的行")        deltableAction.triggered.connect(self.deltable)        vacuumAction = QAction("&整理数据库", self)        vacuumAction.setShortcut("Ctrl+D")        vacuumAction.setStatusTip("让数据库变小")        vacuumAction.triggered.connect(self.vacuum)        selectAction = QAction("&刷新", self)        selectAction.setShortcut("Ctrl+R")        selectAction.setStatusTip("显示所有路径")        selectAction.triggered.connect(self.selectAll)        menubar = self.menuBar()        menubar.addAction(delAction)        setMenu = menubar.addMenu('&设置')        setMenu.addAction(vacuumAction)        setMenu.addAction(deltableAction)        menubar.addAction(selectAction)        widget = QWidget()        QMainWindow.setCentralWidget(self,widget)        layout = QHBoxLayout(self) #QHBoxLayout水平排列        layout.addWidget(self.sview)        layout.addWidget(self.view)        layout.setStretchFactor(self.sview,1) #显示的比例 1:3        layout.setStretchFactor(self.view,3)        self.table1()        self.stable()        widget.setLayout(layout)        self.resize(800, 600)        self.center() #居中        self.setWindowTitle("快捷方式")        #self.setWindowIcon(QIcon("icon.png"))        self.show()    def selectAll(self):        self.model.setFilter("1=1")    def delrow(self):        if self.view.selectionModel().hasSelection():            self.query.prepare("delete from lj where lj=?")            self.query.bindValue(0,QVariant(self.view.currentIndex().data()))            if self.query.exec():                self.model.setFilter("1=1")            else:                QMessageBox.information(self,"删除错误",self.model.lastError().text())        if self.sview.selectionModel().hasSelection():            self.query.prepare("delete from cxtj where cxtj=?")            self.query.bindValue(0,QVariant(self.sview.currentIndex().data()))            if self.query.exec():                self.smodel.setFilter("1=1")            else:                QMessageBox.information(self,"删除错误",self.smodel.lastError().text())    def deltable(self):        ret = QMessageBox.question(self,"提示!","是否删除全部路径",QMessageBox.Ok | QMessageBox.Cancel,QMessageBox.Cancel)        if 0x00000400 == ret: #OK            self.query.prepare("delete from lj")            if not self.query.exec():                QMessageBox.information(self,"删除错误",self.model.lastError().text())            self.query.prepare("delete from cxtj")            if not self.query.exec():                QMessageBox.information(self,"删除错误",self.smodel.lastError().text())    def vacuum(self):        self.query.exec("VACUUM")    def center(self): #窗口居中        #QtGui.QDesktopWidget提供了关于用户桌面的信息,包括屏幕尺寸。        qr = self.frameGeometry()        cp = QDesktopWidget().availableGeometry().center()        qr.moveCenter(cp)        self.move(qr.topLeft())    def sql(self):        sqlite = QSqlDatabase.addDatabase("QSQLITE")        sqlite.setDatabaseName("db")        return sqlite    def table1(self):        self.model.setTable("lj")        #self.model.setFilter("isdel = 0") #where 条件        self.model.setSort(1,Qt.AscendingOrder) #按lj列排序        self.model.select()        #self.model.setHeaderData(0, Qt.Horizontal, "ID")        #self.model.setHeaderData(1, Qt.Horizontal,"路径")        self.view.setModel(self.model)        self.view.setEditTriggers(QAbstractItemView.NoEditTriggers) #禁止对表格编辑        self.view.horizontalHeader().setStretchLastSection(True) #是否填满宽度        self.view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)        self.view.hideColumn(0)#隐藏列        self.view.hideColumn(2)#隐藏列        self.view.setSelectionBehavior(QAbstractItemView.SelectRows) #点击整行选中        #self.view.setAlternatingRowColors(True) #隔行自动变色        self.view.verticalHeader().setVisible(False)#隐藏表头        self.view.horizontalHeader().setVisible(False)#隐藏列名        self.view.doubleClicked.connect(lambda:self.slotRowDoubleClicked())        self.view.clicked.connect(lambda:self.singleSelect(view))        #view.setAcceptDrops(True)        self.view.show()    def slotRowDoubleClicked(self):        try:            modedata = self.view.currentIndex().data()            win32api.ShellExecute(0,'open',str(modedata),'','',1)        except (BaseException):            QMessageBox.information(self,"错误!","路径不存在!")    def stable(self):        self.smodel.setTable("cxtj")        #self.model.setFilter("isdel = 0") #where 条件        self.smodel.setSort(0,Qt.AscendingOrder) #按cxtj列排序        self.smodel.setHeaderData(0, Qt.Horizontal,"搜索条件")        self.smodel.select()        self.sview.setModel(self.smodel)        self.sview.setEditTriggers(QAbstractItemView.NoEditTriggers) #禁止对表格编辑        self.sview.horizontalHeader().setStretchLastSection(True) #是否填满宽度        self.sview.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)        self.sview.setSelectionBehavior(QAbstractItemView.SelectRows) #点击整行选中        self.sview.verticalHeader().setVisible(False)#隐藏表头        self.sview.horizontalHeader().setVisible(False)#隐藏列名        self.sview.doubleClicked.connect(lambda:self.slotRowDoubleClickedS())        self.sview.clicked.connect(lambda:self.singleSelect(sview))        self.sview.show()    def slotRowDoubleClickedS(self):        modedata = self.sview.currentIndex().data()        data = str(modedata)        if self.sqlite.open():            self.model.setFilter("lj like '%" + data + "%'") #where 条件        else:            QMessageBox.information(self,"程序将关闭",self.sqlite.lastError().text())            sys.exit(app.exec_())    def contextMenuEvent(self,event): #右键菜单        popAction = QAction(self)        popAction.setText("创建搜索条件")        popAction.triggered.connect(self.popMenu)        popMenubar = QMenu(self)        popMenubar.addAction(popAction)        popMenubar.exec(self.cursor().pos())    def popMenu(self):        i = 0        sdata = []        modedata = self.view.currentIndex().data()        data = str(modedata)        for txt in data.split("\\"):            sdata.append((i,txt))            i = i + 1        self.cbWindow = cbWindow(sdata,self.sqlite,self.query,self.smodel)    # def enableBorder(self, enable):    #     if enable:    #         self.setStyleSheet("MainWidget{border:3px solid #165E23}")    #     else:    #         self.setStyleSheet('')    def dragEnterEvent(self, event):        if event.mimeData().hasUrls():            event.acceptProposedAction()            #self.enableBorder(True)        else:            event.ignore()    def dragMoveEvent(self, event):        if event.mimeData().hasUrls():            event.setDropAction(Qt.LinkAction)            event.accept()        else:            event.ignore()    #def dragLeaveEvent(self, event):        #print('dragLeaveEvent...')        #self.enableBorder(False)    def dropEvent(self, event):        #self.model.setFilter("1=1")        if event.mimeData().hasUrls():            counts = -1                    #record = self.model.record()            # 遍历输出拖动进来的所有文件路径            for url in event.mimeData().urls():                self.query.prepare("select count(*) as c from lj where lj=?") #不加 as c会报错                pathStr = url.toLocalFile().replace('/','\\')                self.query.bindValue(0,QVariant(pathStr))                if self.query.exec():                    while self.query.next():                        counts = self.query.value(0)                if counts > 0:                    QMessageBox.information(self,"已存在!",pathStr)                elif counts == 0:                    #record.setValue(1,QVariant(pathStr)) #lj列                    #record.setValue(2,QVariant(0)) #isdel列                    #self.model.insertRecord(-1,record)                    self.query.prepare("insert into lj(lj) values(?)")                    self.query.bindValue(0,QVariant(pathStr))                    self.query.exec()                elif counts == -1:                    return            event.acceptProposedAction()            self.model.setFilter("1=1")            #print(self.model.lastError().text())        else:            event.ignore()    def singleSelect(self,lstView):        if lstView == self.view:            if self.sview.selectionModel().hasSelection():                self.sview.selectionModel().clearSelection()        if lstView == self.sview:            if self.view.selectionModel().hasSelection():                self.view.selectionModel().clearSelection()        # for lstViewI in lstViews:        #     if lstViewI == lstView:        #        continue        #     # the check is necessary to prevent recursions...        #     if lstViewI.selectionModel().hasSelection():        #       # ...as this causes emission of selectionChanged() signal as well:        #        lstViewI.selectionModel().clearSelection()    def closeEvent(self,event):        if self.sqlite.isOpen():            self.sqlite.close()        self.close()class cbWindow(QWidget):    def __init__(self,sdata,sqlite,query,smodel):        super().__init__()        self.sdata = sdata        self.sqlite = sqlite        self.query = query        self.smodel = smodel        self.cbStr = []        layout = QVBoxLayout()        #items = [(0, 'Python'), (1, 'Golang'), (2, 'JavaScript'), (3, 'Ruby')]        for id_, txt in self.sdata:            checkBox = QCheckBox(txt, self)            checkBox.id_ = id_            checkBox.stateChanged.connect(self.checkLanguage) #1            layout.addWidget(checkBox)        self.lMessage = QLabel(self)        layout.addWidget(self.lMessage)        self.button1 = QPushButton("保存",self)        self.button1.clicked.connect(self.checkbutton1)        layout.addWidget(self.button1)        self.setLayout(layout)        self.setWindowTitle("选择搜索条件")        self.resize(200, 300)        self.show()    def checkLanguage(self, state):        checkBox = self.sender()        if state == Qt.Unchecked:            self.cbStr.remove((checkBox.id_, checkBox.text()))            #print(self.cbStr)            #self.lMessage.setText(u'取消选择了{0}: {1}'.format(checkBox.id_, checkBox.text()))        elif state == Qt.Checked:            self.cbStr.append((checkBox.id_, checkBox.text()))            #print(self.cbStr)            #self.lMessage.setText(u'选择了{0}: {1}'.format(checkBox.id_, checkBox.text()))    def checkbutton1(self):        counts = -1        if self.sqlite.isOpen():            for id_, txt in self.cbStr:                self.query.prepare("select count(*) as c from cxtj where cxtj=?")                self.query.bindValue(0,QVariant(txt))                if self.query.exec():                    while query.next():                        counts = query.value(0)                    if counts == 0:                        self.query.prepare("insert into cxtj(cxtj) values(?)")                        self.query.bindValue(0,QVariant(txt))                        if self.query.exec():                            self.smodel.setFilter("1=1")                        else:                            QMessageBox.information(self,"查询条件写入错误","查询条件写入错误")            self.close()        else:            QMessageBox.information(self,"程序将关闭",self.sqlite.lastError().text())            sys.exit(app.exec_())    def closeEvent(self,event):        self.close()if __name__ == "__main__":    app = QApplication(sys.argv)    qss = QFile("stylesheet.qss") #样式表    qss.open(QIODevice.ReadOnly)  #样式表    app.setStyleSheet(str(qss.readAll(),encoding='utf-8')) #样式表    #样式表 http://doc.qt.io/qt-5/stylesheet-customizing.html    #样式表 http://doc.qt.io/qt-5/stylesheet-reference.html (QTableView stylesheet)    qss.close() #样式表    sqlite = QSqlDatabase.addDatabase("QSQLITE")    sqlite.setDatabaseName("db")    model = QSqlTableModel(None,sqlite)    model.setEditStrategy(QSqlTableModel.OnManualSubmit)    smodel = QSqlTableModel(None,sqlite)    smodel.setEditStrategy(QSqlTableModel.OnManualSubmit)    query = QSqlQuery(sqlite)    view = QTableView()    #view.setSelectionMode(QTableView.SingleSelection)    sview = QTableView()    #view.setSelectionMode(QTableView.SingleSelection)    icon = Icon(model,sqlite,query,view,sview,smodel)    sys.exit(app.exec_())

数据库 db

CREATE TABLE lj(id integer primary key,lj text not NULL,isdel BOOLEAN DEFAULT 0)CREATE TABLE cxtj(cxtj text not NULL)

qss样式表 stylesheet.qss

QTableView {gridline-color: white;selection-background-color: rgb(74,112,139);        /*选中区域的背景色*/font: bold 14px;/*注释*/}QMenuBar{font: 14px;}QStatusBar{font: 14px;}

QT的样式表使用起来确实很方便,按CSS做的很多地方都是一样的,代码里有qt官网的样式表介绍连接

说说PYQT5与TK的使用感觉,TK上手方便,拿起来就能写,PYQT5需要了解它的工作机制所以上手时间会比较长。比较喜欢qss、tableview、tablemodel,qss可以很方便的调整样式而且和js很像,用过js的上手那叫一个快,tableview与tablemodel联动可以少些很多代码,最主要的它的容错度很高,有些可以不用写try也不会造成程序停止运行,这点很重要,哈哈,重要的点就在于'懒'。

程序打包之后可以直接修改stylesheet.qss,样式一样会改变好方便,可以做定制,赞。

0