pyqt5 自定义控件_PyQt5学习笔记(十六)Pyinstaller打包与SQLite数据库
終于到了最后一章了QAQ,第一次寫(xiě)4萬(wàn)字以上的筆記分享,最近也在忙科創(chuàng)和CV的比賽,所以筆記會(huì)顯得比較粗糙。其實(shí)吧分享這個(gè)筆記很大一部分是為了讓自己記得更牢,網(wǎng)上翻閱自己的筆記也方便,如果有講解注釋不清楚的地方歡迎評(píng)論留言(秋梨膏)。當(dāng)然本蒟蒻也會(huì)時(shí)不時(shí)地在以后的時(shí)間更新完善這些已經(jīng)完成的筆記。
以下內(nèi)容涉及到SQLite數(shù)據(jù)庫(kù)和requests爬蟲(chóng)庫(kù)的使用,有時(shí)間我也會(huì)做相關(guān)方面的筆記噠(`?ω?′)。以下只是初步使用。
使用Pyinstaller打包PyQt5應(yīng)用
Pyinstaller部分同學(xué)想必用過(guò),這是一個(gè)在命令行下使用的、將腳本代碼轉(zhuǎn)成可執(zhí)行文件的python第三方庫(kù)。如果想要使得我們做出來(lái)的GUI脫離于python解釋器而讓操作系統(tǒng)直接執(zhí)行的話,我們可以使用Pyinstaller庫(kù)來(lái)封裝我們的GUI的腳本程序。這樣不同python、沒(méi)有python依賴庫(kù)的用戶也可以方便運(yùn)行程序。
這里直接講windows下可行的方法,安裝完pyinstaller后,打開(kāi)命令行,一路cd到需要打包的python文件的目錄下。或者也可以在需要打包的python文件的目錄下按住“Shift”+鼠標(biāo)右鍵,打開(kāi)“PowerShell“:
點(diǎn)開(kāi)后,就會(huì)有和windows的命令行幾乎一樣的頁(yè)面。
下面我們對(duì)draft.py文件打包生成可執(zhí)行文件,那么只要輸入以下指令:
pyinstaller -Fw "draft.py"打開(kāi)目錄,你會(huì)發(fā)現(xiàn)多了兩個(gè)文件夾build和dist,打開(kāi)dist文件夾,里面就是可以直接運(yùn)行的可執(zhí)行文件了:
如果要修改圖標(biāo),比如要給文件“SevenDigitDrawV2.py“附上”curve.ico“的圖標(biāo),則輸入命令:
pyinstaller -i curve.ico -Fw "draft.py"需要說(shuō)明的是,打包完的可執(zhí)行文件會(huì)很大(筆者的這個(gè)小小的畫(huà)板e(cuò)xe就有37MB),這是因?yàn)樗鼘⑺衟ython的依賴庫(kù)都包括進(jìn)去了,即你裝的第三方庫(kù)越多,打包出來(lái)的文件越大。
操作SQLite數(shù)據(jù)庫(kù)
許多桌面應(yīng)用都有訪問(wèn)本地?cái)?shù)據(jù)庫(kù)或者遠(yuǎn)程數(shù)據(jù)庫(kù)的需求,下面就講講其中的一種SQLite。SQLite是一種輕量級(jí)的跨平臺(tái)數(shù)據(jù)庫(kù),因此很常用。
PyQt5中提供了操控SQLite數(shù)據(jù)庫(kù)的API。
- QSqlDatabase.addDatabase():創(chuàng)建一個(gè)通用數(shù)據(jù)庫(kù),參數(shù)填入“QSQLITE”表示創(chuàng)建SQLite數(shù)據(jù)庫(kù)
我們現(xiàn)在python文件的目錄下創(chuàng)建一個(gè)文件夾"db"。
import sys from PyQt5.QtSql import * ? def createDB():# 創(chuàng)建一個(gè)通用數(shù)據(jù)庫(kù)對(duì)象,參數(shù)"QSQLITE"代表通用數(shù)據(jù)庫(kù)為SQLite數(shù)據(jù)庫(kù)類(lèi)型db = QSqlDatabase.addDatabase("QSQLITE")# 指定SQLite數(shù)據(jù)庫(kù)的文件名db.setDatabaseName("./db/database.db")if not db.open():print("無(wú)法建立與數(shù)據(jù)庫(kù)的連接")return False# 創(chuàng)建查詢功能query = QSqlQuery()# 執(zhí)行創(chuàng)建表格的指令query.exec('create table people(id int primary key,name varchar(10),address varchar(50))')# 執(zhí)行往表格中插入數(shù)據(jù)的指令query.exec('insert into people values(1, "Kirigaya", "GitHub")')db.close()return True ? if __name__ == '__main__':createDB()通過(guò)DB Browser for SQLite打開(kāi)"./db/database.db",點(diǎn)擊"Browser Data"瀏覽數(shù)據(jù):
我們創(chuàng)建的表格和數(shù)據(jù)條已經(jīng)在里面了建議使用DB Browser for SQLite來(lái)打開(kāi)數(shù)據(jù)庫(kù)進(jìn)行操作,網(wǎng)上可以下載到。
通過(guò)可視化的方式對(duì)SQLite數(shù)據(jù)庫(kù)進(jìn)行增、刪、改、查操作
此處我們使用之前講過(guò)的QTableView控件來(lái)展示二維數(shù)據(jù)。之前你可能會(huì)覺(jué)得QTableView控件不常用,因?yàn)榕cQTableWidget相比,QTableView需要?jiǎng)?chuàng)建一個(gè)model,設(shè)置模型代表的表格的尺寸、屬性,再在模型上添加數(shù)據(jù),再將model與view關(guān)聯(lián),最后將view作為控件添加到窗口上才能顯示出我們model代表的表格的樣式與數(shù)據(jù),看起來(lái)比較繁瑣,沒(méi)有QTableWidget那樣直觀和方便。
但是當(dāng)我們想將數(shù)據(jù)庫(kù)中的數(shù)據(jù)在GUI上可視化時(shí),QTableView就變得很常用了,因?yàn)?/p>import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtSql import * from PyQt5.QtWidgets import * ? def initializeModel(model):# 設(shè)置表格名稱model.setTable("people")# 設(shè)置編輯策略model.setEditStrategy(QSqlTableModel.OnFieldChange)# 調(diào)用select方法model.select()# 設(shè)置表格頭model.setHeaderData(0, Qt.Horizontal, "ID")model.setHeaderData(1, Qt.Horizontal, "姓名")model.setHeaderData(2, Qt.Horizontal, "地址") ? def createView(title, model):view = QTableView()view.setModel(model)view.setWindowTitle(title)return view ? def findrow(i):delrow = i.row()print("選中第{}行".format(delrow)) ? def addrow():# 在model.rowCount()行后插入1行,并返回插入的行所在行數(shù)ret = model.insertRows(model.rowCount(), 1)print("添加第{}行".format(ret)) ? if __name__ == '__main__':app = QApplication(sys.argv)db = QSqlDatabase.addDatabase("QSQLITE")# 設(shè)置數(shù)據(jù)庫(kù)名字(路徑)db.setDatabaseName("./db/database.db") ?# 創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)的表格模型,QSqlTableModel()會(huì)自動(dòng)關(guān)聯(lián)到db上model = QSqlTableModel()delrow = -1# 初始化這個(gè)表格模型(函數(shù)在上面)initializeModel(model) ?# 根據(jù)model創(chuàng)建QTableView對(duì)象view = createView("展示數(shù)據(jù)", model)view.clicked.connect(findrow) ?window = QDialog()layout = QVBoxLayout()layout.addWidget(view)addBtn = QPushButton("添加一行")addBtn.clicked.connect(addrow) ?delBtn = QPushButton("刪除一行")# 下面view.currentIndex().row()表示view中被選中的單元格對(duì)象所在行數(shù)delBtn.clicked.connect(lambda : model.removeRow(view.currentIndex().row())) ?layout.addWidget(addBtn)layout.addWidget(delBtn)window.setLayout(layout) ?window.setWindowTitle("Database Demo")window.resize(550, 400)window.show() ?sys.exit(app.exec_())
運(yùn)行效果:
因?yàn)閿?shù)據(jù)庫(kù)路徑設(shè)置的是我們之前創(chuàng)建的數(shù)據(jù)庫(kù),所以一打開(kāi)就已經(jīng)有數(shù)據(jù)了分頁(yè)顯示數(shù)據(jù)
如果數(shù)據(jù)量很大,那么看起來(lái)會(huì)很不方便,一頁(yè)上只能顯示幾條數(shù)據(jù)。事實(shí)上,不僅是在GUI中,許多網(wǎng)頁(yè)也會(huì)有這種效果:
通過(guò)兩個(gè)按鈕控件“前一頁(yè)”和“后一頁(yè)”和一個(gè)QLineEdit控件可供任意頁(yè)面的跳轉(zhuǎn),用戶就可以在有限的UI中瀏覽整個(gè)數(shù)據(jù)庫(kù)中對(duì)的數(shù)據(jù)(emm,事實(shí)上,這不就是一般數(shù)據(jù)庫(kù)的基本功能嗎?)
下面,我們完成這個(gè)實(shí)例。
我們先將整個(gè)窗口的布局和控件設(shè)置一下:
import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtSql import * from PyQt5.QtWidgets import * ? class DataGrid(QWidget):def __init__(self):super().__init__()self.setWindowTitle("分頁(yè)查詢例子")self.resize(820, 420)self.initUI() ?def initUI(self):# 創(chuàng)建窗口(自定義方法)self.createWindow() ? ?# 添加窗口上的控件和布局def createWindow(self):# 添加相關(guān)的布局與控件hbox1 = QHBoxLayout()# 向前翻頁(yè)的按鈕self.prevButton = QPushButton("前一頁(yè)")# 向后翻頁(yè)的按鈕self.nextButton = QPushButton("后一頁(yè)")# 直接跳轉(zhuǎn)到指定頁(yè)數(shù)的按鈕和輸入想要跳轉(zhuǎn)至的頁(yè)數(shù)的輸入框self.switchPageButton = QPushButton("Go")self.switchPageLineEdit = QLineEdit()self.switchPageLineEdit.setFixedWidth(40) ?switchPage = QLabel("轉(zhuǎn)到第")page = QLabel("頁(yè)") ?# 添加我們的控件hbox1.addWidget(self.prevButton)hbox1.addWidget(self.nextButton)hbox1.addWidget(switchPage)hbox1.addWidget(self.switchPageLineEdit)hbox1.addWidget(page)hbox1.addWidget(self.switchPageButton)# 通過(guò)添加間隔控件使得上面的控件全部被擠到左邊去hbox1.addWidget(QSplitter()) ?# 下面這個(gè)布局置于最底端,當(dāng)做當(dāng)前頁(yè)面的狀態(tài)hbox2 = QHBoxLayout()# 創(chuàng)建顯示總也是的labelself.totalPageLabel = QLabel()self.totalPageLabel.setFixedWidth(70)# 創(chuàng)建顯示當(dāng)前頁(yè)數(shù)的labelself.currentPageLabel = QLabel()self.currentPageLabel.setFixedWidth(100)# 創(chuàng)建顯示總記錄數(shù)的labelself.totalRecordLabel = QLabel()self.totalRecordLabel.setFixedWidth(70) ?hbox2.addWidget(self.totalPageLabel)hbox2.addWidget(self.currentPageLabel)# 通過(guò)添加間隔控件使得上面的控件(totalPageLabel和currentPageLabel)在左邊,下面的控件(totalRecordLabel)在右邊hbox2.addWidget(QSplitter())hbox2.addWidget(self.totalRecordLabel) ?# 設(shè)置表格屬性self.tabelView = QTableView()# 表格寬度自適應(yīng)調(diào)整self.tabelView.resizeRowsToContents()self.tabelView.resizeColumnsToContents() ?# 創(chuàng)建主布局,并將hbox1,表格和hbox2裝入mainLayout = QVBoxLayout(self)mainLayout.addLayout(hbox1)mainLayout.addWidget(self.tabelView)mainLayout.addLayout(hbox2)self.setLayout(mainLayout)if __name__ == '__main__':app = QApplication(sys.argv)main = DataGrid()main.show()sys.exit(app.exec_())運(yùn)行效果:
然后我們手動(dòng)創(chuàng)建26條數(shù)據(jù),并且設(shè)置查詢模型和QTableView控件,并將查詢模型和QTableView控件關(guān)聯(lián)起來(lái),就可以在中間空白區(qū)域顯示數(shù)據(jù)了。
完成了布局和控件之后,我們還需要為控件添加槽函數(shù),一通操作后,總體的代碼如下(有點(diǎn)雜,不好寫(xiě),所以我就將注釋全部打在上面了(`?ω?′))
import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtSql import * from PyQt5.QtWidgets import * ? class DataGrid(QWidget):def __init__(self):super().__init__()self.setWindowTitle("分頁(yè)查詢例子")self.resize(820, 420)# 手動(dòng)創(chuàng)建表格與數(shù)據(jù)(自定義方法)self.createTableAndInit() ?# 當(dāng)前頁(yè)self.currentPage = 0# 總頁(yè)數(shù)self.totalPage = 0# 總記錄數(shù)self.totalRecordCount = 0# 每頁(yè)顯示的記錄數(shù)self.PageRecordCount = 6 ?self.initUI() ?def initUI(self):# 創(chuàng)建窗口(自定義方法)self.createWindow()# 設(shè)置表格(自定義方法)self.setTableView() ? ?# 創(chuàng)建一個(gè)SQLite數(shù)據(jù)庫(kù)對(duì)象,并打開(kāi)指定路徑上的數(shù)據(jù)庫(kù)文件def createTableAndInit(self):self.db = QSqlDatabase.addDatabase("QSQLITE")self.db.setDatabaseName("./db/database.db")if not self.db.open():return False ?# 申明數(shù)據(jù)庫(kù)的查詢對(duì)象query = QSqlQuery()# 創(chuàng)建表query.exec("create table student(id int primary key, name vchar, sex vchar, age int, major vchar)")# 手動(dòng)添加記錄(嫌累也可以在數(shù)據(jù)庫(kù)查詢中添加)query.exec("insert into student values(1, 'AA', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(2, 'AB', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(3, 'AC', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(4, 'AD', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(5, 'AE', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(6, 'AF', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(7, 'AG', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(8, 'AH', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(9, 'AI', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(10, 'AJ', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(11, 'AK', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(12, 'AL', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(13, 'AM', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(14, 'AN', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(15, 'AO', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(16, 'AP', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(17, 'AQ', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(18, 'AR', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(19, 'AS', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(20, 'AT', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(21, 'AU', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(22, 'AV', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(23, 'AW', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(24, 'AX', '女', 20, '計(jì)算機(jī)')")query.exec("insert into student values(25, 'AY', '男', 20, '計(jì)算機(jī)')")query.exec("insert into student values(26, 'Az', '女', 20, '計(jì)算機(jī)')") ?return True ?# 添加窗口上的控件和布局def createWindow(self):# 添加相關(guān)的布局與控件hbox1 = QHBoxLayout()# 向前翻頁(yè)的按鈕self.prevButton = QPushButton("前一頁(yè)")# 向后翻頁(yè)的按鈕self.nextButton = QPushButton("后一頁(yè)")# 直接跳轉(zhuǎn)到指定頁(yè)數(shù)的按鈕和輸入想要跳轉(zhuǎn)至的頁(yè)數(shù)的輸入框self.switchPageButton = QPushButton("Go")self.switchPageLineEdit = QLineEdit()self.switchPageLineEdit.setFixedWidth(40) ?switchPage = QLabel("轉(zhuǎn)到第")page = QLabel("頁(yè)") ?# 綁定信號(hào)和槽self.prevButton.clicked.connect(self.onPrevButton)self.nextButton.clicked.connect(self.onNextButton)self.switchPageButton.clicked.connect(self.onSwitchPageButtonClick) ?# 添加我們的控件hbox1.addWidget(self.prevButton)hbox1.addWidget(self.nextButton)hbox1.addWidget(switchPage)hbox1.addWidget(self.switchPageLineEdit)hbox1.addWidget(page)hbox1.addWidget(self.switchPageButton)# 通過(guò)添加間隔控件使得上面的控件全部被擠到左邊去hbox1.addWidget(QSplitter()) ?# 下面這個(gè)布局置于最底端,當(dāng)做當(dāng)前頁(yè)面的狀態(tài)hbox2 = QHBoxLayout()# 創(chuàng)建顯示總也是的labelself.totalPageLabel = QLabel()self.totalPageLabel.setFixedWidth(70)# 創(chuàng)建顯示當(dāng)前頁(yè)數(shù)的labelself.currentPageLabel = QLabel()self.currentPageLabel.setFixedWidth(100)# 創(chuàng)建顯示總記錄數(shù)的labelself.totalRecordLabel = QLabel()self.totalRecordLabel.setFixedWidth(70) ?hbox2.addWidget(self.totalPageLabel)hbox2.addWidget(self.currentPageLabel)# 通過(guò)添加間隔控件使得上面的控件(totalPageLabel和currentPageLabel)在左邊,下面的控件(totalRecordLabel)在右邊hbox2.addWidget(QSplitter())hbox2.addWidget(self.totalRecordLabel) ?# 設(shè)置表格屬性self.tabelView = QTableView()# 表格寬度自適應(yīng)調(diào)整self.tabelView.resizeRowsToContents()self.tabelView.resizeColumnsToContents() ?# 創(chuàng)建主布局,并將hbox1,表格和hbox2裝入mainLayout = QVBoxLayout(self)mainLayout.addLayout(hbox1)mainLayout.addWidget(self.tabelView)mainLayout.addLayout(hbox2)self.setLayout(mainLayout) ?def setTableView(self):# 聲明查詢模型self.queryModel = QSqlQueryModel(self)# 設(shè)置當(dāng)前頁(yè)self.currentPage = 1# 獲取總記錄數(shù)self.totalRecordCount = self.getTotalRecordCount()# 獲取總頁(yè)數(shù)self.totalPage = self.getPageCount()# 刷新?tīng)顟B(tài)(也就是更新hbox2中各控件顯示的值)self.updateStatus()# 設(shè)置總頁(yè)數(shù)文本self.setTotalPageLabel()# 設(shè)置總記錄數(shù)self.setTotalRecordLabel() ?# 記錄查詢(0代表從第1條開(kāi)始查),從第一條往后查詢6條self.recordQuery(0)# 將數(shù)據(jù)庫(kù)中的model和tabelView關(guān)聯(lián)# 這樣數(shù)據(jù)庫(kù)中的數(shù)據(jù)就可以直接顯示在tableView代表的表格上了self.tabelView.setModel(self.queryModel) ?# 得到記錄數(shù)def getTotalRecordCount(self):# 設(shè)置查詢模型,獲得一個(gè)查詢所有數(shù)據(jù)的查詢模型self.queryModel.setQuery("select * from student")# 通過(guò)模型的rowCount()方法得到數(shù)據(jù)條數(shù)rowCount = self.queryModel.rowCount()return rowCount ?# 得到頁(yè)數(shù)def getPageCount(self):# 實(shí)際得到的頁(yè)數(shù)應(yīng)該是:總的記錄數(shù) / 每頁(yè)能夠容納下的記錄條數(shù),再向上取整# 下面就是通過(guò)判斷來(lái)達(dá)到向上取整 ?if self.totalRecordCount % self.PageRecordCount == 0:return int(self.totalRecordCount / self.PageRecordCount)else:return int(self.totalRecordCount / self.PageRecordCount + 1) ? ?# 記錄查詢函數(shù)(顯示limitIndex到limitIndex+5的6條數(shù)據(jù))def recordQuery(self, limitIndex):# 查詢語(yǔ)句,從limitIndex開(kāi)始往后查詢6條szQuery = ("select * from student limit %d,%d" % (limitIndex, self.PageRecordCount))# 對(duì)查詢模型使用set方法來(lái)設(shè)置模型self.queryModel.setQuery(szQuery) ?# 刷新?tīng)顟B(tài)def updateStatus(self):szCurrentText = ("當(dāng)前第%d頁(yè)" % self.currentPage)# 這是更新顯示當(dāng)前頁(yè)數(shù)的labelself.currentPageLabel.setText(szCurrentText) ?# 設(shè)置按鈕是否可用# 如果當(dāng)前在第一頁(yè),那么“向前一頁(yè)”的按鈕不可用if self.currentPage == 1:self.prevButton.setEnabled(False)self.nextButton.setEnabled(True)# 如果當(dāng)前在最后一頁(yè),那么“向后一頁(yè)”的按鈕不可用elif self.currentPage == self.totalPage:self.prevButton.setEnabled(True)self.nextButton.setEnabled(False)# 如果當(dāng)前在既不在第一頁(yè),也不在最后一頁(yè),那么兩個(gè)按鈕都可用else:self.prevButton.setEnabled(True)self.nextButton.setEnabled(True) ?# 設(shè)置顯示總頁(yè)數(shù)def setTotalPageLabel(self):szTotalPageText = ("共%d頁(yè)" % self.totalPage)self.totalPageLabel.setText(szTotalPageText) ?# 設(shè)置顯示總記錄數(shù)def setTotalRecordLabel(self):szTotalRecordText = ("共%d條" % self.totalRecordCount)self.totalRecordLabel.setText(szTotalRecordText) ?# 跳轉(zhuǎn)到前一頁(yè)的按鈕按下的槽函數(shù)def onPrevButton(self):# 計(jì)算上一頁(yè)第一條數(shù)據(jù)的索引# 注意我們的當(dāng)前頁(yè)數(shù)是從1開(kāi)始的,而數(shù)據(jù)索引是從0開(kāi)始的limitIndex = (self.currentPage - 2) * self.PageRecordCount# 設(shè)置查詢模型(顯示上一頁(yè)的6條數(shù)據(jù))self.recordQuery(limitIndex)# 記錄當(dāng)前頁(yè)數(shù)的變量也需要變self.currentPage -= 1# 刷新?tīng)顟B(tài)self.updateStatus() ?# 跳轉(zhuǎn)到后一頁(yè)的按鈕按下的槽函數(shù)def onNextButton(self):# 如法炮制limitIndex = self.currentPage * self.PageRecordCountself.recordQuery(limitIndex)self.currentPage += 1self.updateStatus() ?# 轉(zhuǎn)到指定頁(yè)面的按鈕按下的槽函數(shù)def onSwitchPageButtonClick(self):# 得到輸入的字符串szText = self.switchPageLineEdit.text() ?# 得到頁(yè)數(shù)pageIndex = int(szText)# 判斷是否有指定頁(yè)數(shù)if pageIndex > self.totalPage or pageIndex < 1:QMessageBox.information(self, "提示", "沒(méi)有指定的頁(yè)面,請(qǐng)重新輸入")return ?# 得到查詢起始行號(hào)limitIndex = (pageIndex - 1) * self.PageRecordCount ?# 設(shè)置查詢模型self.recordQuery(limitIndex)# 設(shè)置當(dāng)前頁(yè)self.currentPage = pageIndex# 刷新?tīng)顟B(tài)self.update() ? ? if __name__ == '__main__':app = QApplication(sys.argv)main = DataGrid()main.show()sys.exit(app.exec_())運(yùn)行效果:
實(shí)戰(zhàn)項(xiàng)目:天氣信息查詢
最后我們完成一個(gè)查詢北京、天津、上海三地的天氣查詢的小GUI。
基本思路是先通過(guò)PyQt5搭建基本的布局和控件,然后為了獲取三地的天氣信息,我們需要使用Python中的Requests庫(kù),這是一個(gè)超級(jí)輕量的python爬蟲(chóng)庫(kù),可以靜態(tài)爬取指定url的數(shù)據(jù)流(這不是重點(diǎn)啦),反正將爬取的數(shù)據(jù)setText()在我們的控件上就行了。至于怎么使用requests庫(kù)爬取,讀者可以搜索MOOC上北京理工大學(xué)的requests課程。
最后我們搭建主循環(huán),在其中設(shè)置窗口的QSS樣式。
from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtGui import * import requests import sys ? ? class QueryWeather(QWidget):# 構(gòu)造函數(shù)后面三個(gè)參數(shù)決定默認(rèn)的圖像生成的寬度,高度和清晰度(每英寸像素點(diǎn)數(shù))def __init__(self, parent=None):super(QueryWeather, self).__init__(parent)self.setWindowTitle("查詢城市天氣")# 設(shè)置固定的窗口大小self.setFixedSize(800, 600)# 設(shè)置透明度self.setWindowOpacity(0.98)# 城市編碼self.cityName2Code = {"北京":"101010100", "天津":"101030100", "上海":"101020100"} ?self.initUI() ?# 搭建窗口,你也可以根據(jù)自己的喜好搭建,這里只是參考def initUI(self):mainVbox = QVBoxLayout()vbox = QVBoxLayout()hbox1 = QHBoxLayout()hbox2 = QHBoxLayout()self.cityLabel = QLabel("城市")self.cityLabel.setAlignment(Qt.AlignCenter)self.cityLabel.setFixedSize(100, 50)self.cityComboBox = QComboBox()self.cityComboBox.setFixedSize(200, 35)self.cityComboBox.addItems(["北京","天津","上海"])self.weatherInfoText = QTextBrowser()self.weatherInfoText.setFixedSize(750, 300)self.weatherInfoText.setAlignment(Qt.AlignCenter)hbox1.addWidget(self.cityLabel)hbox1.addWidget(self.cityComboBox)hbox1.addWidget(QSplitter())hbox2.addWidget(self.weatherInfoText)vbox.addLayout(hbox1)vbox.addLayout(hbox2) ?buttonHBox = QHBoxLayout()self.queryButton = QPushButton("查詢")self.queryButton.setFixedSize(150, 40)self.queryButton.setProperty("name", "queryButton")self.clearButton = QPushButton("清空")self.clearButton.setFixedSize(150, 40)self.clearButton.setProperty("name", "clearButton")buttonHBox.addStretch(1)buttonHBox.addWidget(self.queryButton)buttonHBox.addStretch(1)buttonHBox.addWidget(self.clearButton)buttonHBox.addStretch(1) ?mainVbox.addLayout(vbox)mainVbox.addStretch(1)mainVbox.addLayout(buttonHBox) ?self.setLayout(mainVbox)self.queryButton.clicked.connect(self.queryWeather)self.clearButton.clicked.connect(self.clearWeather) ? ?def queryWeather(self):cityName = self.cityComboBox.currentText()# 獲取城市對(duì)應(yīng)我們要爬取的頁(yè)面中的編碼cityCode = self.cityName2Code[cityName] ?# 爬取頁(yè)面內(nèi)容,返回response對(duì)象(json數(shù)據(jù))rep = requests.get("http://www.weather.com.cn/data/sk/" + cityCode + ".html")# 設(shè)置response對(duì)象的編碼rep.encoding = "utf-8"print(rep.json()) ?# 獲取json數(shù)據(jù)中的鍵值對(duì),就是我們需要的信息msg1 = "城市: {}".format(rep.json()["weatherinfo"]["city"] + "n")msg2 = "風(fēng)向: {}".format(rep.json()["weatherinfo"]["WD"] + "n")msg3 = "溫度: {}".format(rep.json()["weatherinfo"]["temp"] + "n")msg4 = "風(fēng)力: {}".format(rep.json()["weatherinfo"]["WS"] + "n")msg5 = "濕度: {}".format(rep.json()["weatherinfo"]["SD"] + "n")result = msg1 + msg2 + msg3 + msg4 + msg5self.weatherInfoText.setText(result) ?def clearWeather(self):# 因?yàn)閟etText方法本來(lái)就是覆蓋寫(xiě),那我們將全文信息設(shè)置成一個(gè)空格就可以達(dá)到清空頁(yè)面信息的效果self.weatherInfoText.setText(" ") ? if __name__ == '__main__':app = QApplication(sys.argv)main = QueryWeather()# QSS樣式表字符串style = '''QLabel{font-size:30px;}QComboBox{font-size:30px;}QPushButton[name="queryButton"]{background-color:#938FD9;color:#2f4f4f;font-size:25px;}QPushButton[name="clearButton"]{background-color:#C0C0C0;font-size:25px;}QTextBrowser{font-size:40px;color:#00CED1;}'''main.setStyleSheet(style)main.show()sys.exit(app.exec_())運(yùn)行效果:
總結(jié)
以上是生活随笔為你收集整理的pyqt5 自定义控件_PyQt5学习笔记(十六)Pyinstaller打包与SQLite数据库的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: rabbitmq 持久化_RabbitM
- 下一篇: JdbcTemplate(操作数据库-添