赞
踩
之前用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,os
- from PyQt5 import sip
- from PyQt5.QtCore import Qt,QVariant,QFile,QIODevice,QItemSelectionModel
- from PyQt5.QtSql import QSqlDatabase,QSqlTableModel,QSqlQuery,QSqlRecord
- from PyQt5.QtWidgets import QPushButton,QLabel,QCheckBox,QHBoxLayout,QVBoxLayout,QWidget,QMenu,QMainWindow,QMessageBox,QHeaderView,QAction, qApp, QApplication, QDesktopWidget , QGridLayout,QTableView,QAbstractItemView
- from PyQt5.QtGui import QIcon,QContextMenuEvent
-
- import win32api
- import win32con
-
- class 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,样式一样会改变好方便,可以做定制,赞。
转载于:https://blog.51cto.com/ikezcn/2166426
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。