python【PyQt5】的环境搭建和使用(全网最全)其一
目錄
什么是pyQT
為什么要開發桌面應用
要講些什么
搭建PyQt5開發環境
?參見CSDN:pyQt5環境的搭建_Hi~晴天大圣的博客-CSDN博客_pyqt5環境搭建
1 Python
2 PyQt模塊插件
??? PyQt5中插件的作用:??? QtDesigner——通過Qt語言進行UI設計(支持拖拽式的UI設計)??? PyUIC——主要用來將QtDesigner代碼轉化成Python代碼??? Pyrcc—— 將圖片、數據文件資源打包成py文件
3 PyCharm
添加到環境變量:環境變量目錄
問題:在安裝第三方庫時出現報錯"These Packages Do Not Match The Hashes From The Requirements File."
python在虛擬解釋器環境中使用pip安裝第三方庫出現Requirement already satisfied錯誤
1到14課時后續學習后添加!
課時15 ? 開發第一個基于PyQt5的桌面應用
?課時16 ? 打開QtDesigner設計師工具
ctrl+R預覽
將.ui文件轉換為.py文件
方法一: python -m PyQt5.uic.pyuic demo.ui -o demo.py
方法二:
python文件夾//打開pyuic5程序 -o 文件名稱 直接生成demo.py
推薦 方式三
課時17 ? 在QtDesigner中使用布局
?課時18 ? 調用源文件:RunDemo.py調用demo.py文件
課時19 ? PyQt5中的瀏覽器控件-QtWebEngine
課時20 ? Edit 編輯伙伴 編輯Tab順序
課時21 ? 在Qt Designer中設置信號與插槽
?課時22 ?? 動作編輯器
?課時23 ? 主窗口類型
QMainWindow:可以包含菜單欄,工具欄,狀態欄和標題欄
QDialog:是對話窗口的基類。沒有菜單欄,工具欄,狀態欄
QWidget:不確定窗口的用途,就使用QWidget
課時24 ? 接下來用代碼寫一個程序Demo
課時25 ? 讓程序居中窗口
課時26??? 退出應用程序
?課時27 ? 獲取屏幕坐標系
課時28?? 設置窗口和應用程序圖標
課時29 顯示控件提示信息
課時30 QLabel控件的基本用法
課時31 QLabel與伙伴關系
課時32 QLineEdit控件與回顯模式
課時33 限制QLineEdi t控件的輸入
校驗器
課時34 使用掩碼限制QLineEdit控件的輸入
課時35 QLineEdit綜合案例
課時36 使用QTextEdit控件輸入多行文本
課時37 按鈕控件(QpushButton)
單選按鈕控件QRatioButton
課時39 復選框控件QCheckBox?編輯?編輯
?課時40 下拉列表控件QComboBox
?課時41 滑塊控件QSlider
課時42 計數器控件QSpinBox
課時43 使用 QDialog顯示通用對話框
課時44 顯示不同類型的消息對話框
課時45 輸入對話框QInputDialog
課時46? 字體對話框QFontDialog
?課時47 顏色對話框QColorDialog
課時48 文件對話框QFileDialog
課時49 在窗口上繪制文本
課時50 用像素點繪制正弦曲線
?編輯
課時51 繪制不同類型的直線
課時52 繪制各種圖形
?課時53 用畫刷填充圖形區域
?課時54 讓控件支持拖拽動作
?課時55 使用剪貼板
課時56 日歷控件
課時57 設置不同風格的日期和時間
?課時58 日期和時間控件的高級操作
?課時59 創建和使用菜單
課時60 創建和使用工具欄
課時61 創建和使用狀態欄?
用于顯示狀態信息,一般在窗口的最下方顯示
課時62 使用打印機
課時63 顯示打印對話框
?課時64 顯示二維表數據
?課時65 顯示列數據
課時66? 擴展的列表控件
課時67 擴展的表格控件
課時68 在單元格中放置控件
課時69 在表格中搜索Cell和行定位
課時70 設置單元格字體和顏色
課時71 按表格的某一列排序
課時71 設置單元格的文本對齊方式
課時73 合并單元格
課時74 設置單元格的尺寸
課時75 在單元格中實現圖文混排的效果
課時76 改變單元格中圖片的尺寸
課時77 在表格中顯示上下文菜單
?課時78 樹控件(QTreeWidget)的基本用法
?編輯
課時79 為樹節點添加響應事件
?課時 80 增加,修改和刪除樹控件的節點
課時81 QTreeView控件與系統定制模式
課時82 選項卡控件(QTabWidget)
?課時83 堆棧窗口控件(QStackedWidget)
課時84 停靠控件(QDockWidget)
課時85 容納多文檔的窗口
課時86 滾動條控件(QScrollBar)
課時87 動態顯示當前時間(QTimer)
?課時88 讓窗口定時關閉
課時89 使用線程類(QThread)編寫計數器
課時90 用Web瀏覽器控件(QWebEngineView)顯示網頁
課時91 裝載本地Web頁面
課時91 顯示嵌入Web頁面
?課時93 PyQt5調用JavaScript代碼,并返回值
課時94 JavaScript調用PyhtonAPI計算階乘
課時95 絕對布局
課時96 水平盒布局(QHBoxLayout)
課時97 設置控件的對齊方式
課時98? 垂直盒布局
課時99 設置布局的伸縮量
課時100 讓按鈕永遠在窗口的右下角
課時101 柵格布局:用循環方式實現計算器UI
?課時102 柵格布局:進行表單UI設計
課時103 表單布局
課時104 拖動控件之間的邊界(QSplitter)
課時105 信號與槽基礎
課時106 自定義信號實現對象之間的通信
課時107 可以傳遞多個參數的信號
課時108 為類添加多個信號(重載形式的信號)
課時109 信號與槽的N對N連接與斷開連接
課時110 為窗口添加信號
?課時111 多線程更新UI數據
課時112 信號與槽自動連接
課時113 用Lambda表達式為槽函數傳遞參數
?課時114 用partial對象為槽函數傳遞參數
課時115 override(覆蓋)槽函數
?課時116 多窗口交互(1):不使用信號與槽
課時117 多窗口交互(2):使用信號與槽
?課時118 設置窗口中控件的風格
?課時119 設置窗口樣式
?課時120 用代碼設置窗口的最大化和最小化
課時121 項目實戰:實現繪圖應用
課時122? QSS基礎
?課時123 使用QSS選擇器設置控件樣式
課時124 QSS子控件選擇器
課時125 使用QSS為標簽和按鈕添加背景圖
?課時126 裝載QSS文件
?課時127 三種設置背景色和背景圖片的方式
方式一 QSS?
?方式二 QPalette
方式三 直接繪制
課時127 實現不規則窗口(異形窗口)注意只對windowse系統有效果
?課時128 移動和關閉不規則窗口(異形窗口)
?課時129 實現異形窗口動畫效果?編輯
課時130 裝載gif動畫文件
課時131 縮放圖片
課時132 用動畫效果改變窗口的尺寸
課時133用動畫效果以不同速度移動窗口
?課時134 用PyInstaller打包PyQt5應用
課時135 操作SQLite數據庫
課時136 使用可視化的方式對SQLite數據庫進行增刪改查操作
課時137 分頁顯示數據
?課時138 使用PyQtGraph進行數據可視化
什么是pyQT
pyqt是一個用于創建GUI應用程序的跨平臺工具包,它將python與qt庫融為一體。也就是說,pyqt允許使用python語言調用qt庫中的API。這樣做的最大好處就是在保存了qt高運行效率的同時,大大提高開發效率。因為,使用python語言開發程序要比使用c++語言開發程序快的多。pyqt對qt做了完整的封裝,幾乎可以用pyqt做qt能做的任何事情。
??????? 由于目前最新的pyqt版本是5.11,所以習慣上稱呼為pyqt為pyqt5
為什么要開發桌面應用
???????
桌面應用,也可以成為GUI應用,在windows處于非常火爆的15年時間(1995到2010)里是非常火的,不過最近幾年web應用和移動應用搶了風頭。盡管web和移動應用看似成為現在的主流。但桌面應用目前仍然為很多類型應用的首選。移動應用由于屏幕太小,機器性能遠低于同時代的pc機,所以至少目前來看,在短時間內移動應用是無法取代pc應用的,而在pc瀏覽器上運行的web應用的主要優勢是不需要安裝的,只要有瀏覽器就可以運行。
??????? 但缺點也顯而易見,web應用在瀏覽器部分的邏輯代碼通常都是由于javascript語言編寫的,運行效率比較低,而且web應用是無法完全控制本機的硬件的,如攝像頭,藍牙設備,打印機,串口等,web應用在用戶體驗上也不如同時代的桌面應用,而web設備不擅長的事正好是桌面應用的強項,因此,在未來的幾十年,桌面應用仍然會占有非常重要的地位。
要講些什么
Qt Designer
pyQt5基本窗口控件(QMainWindow,Qwidget,Qlabel,QLineEdit,菜單,工具欄等)
pyQt5高級控件(QTableView,QListView,容器,多線程等)
pyQt5布局管理(QBoxLayout,QGridLayout,QFormLayout,嵌套布局等)
pyQt5信號與槽(事件處理,數據傳遞等)
pyQt5圖形與特效(定制窗口風格,繪圖,QSS與UI美化,不規則窗口,設置樣式等)
pyQt5擴展應用(制作pyQt5安裝程序,數據處理,第三方繪圖庫在pyQt5中的應用,UI自動化測試等)
搭建PyQt5開發環境
?參見CSDN:pyQt5環境的搭建_Hi~晴天大圣的博客-CSDN博客_pyqt5環境搭建
1 Python
2 PyQt模塊插件
??? PyQt5中插件的作用:
??? QtDesigner——通過Qt語言進行UI設計(支持拖拽式的UI設計)
??? PyUIC——主要用來將QtDesigner代碼轉化成Python代碼
??? Pyrcc—— 將圖片、數據文件資源打包成py文件
3 PyCharm
因為這里存在網絡慢的原因 我使用了手機數據分享給電腦的方式下載的PyQt5
?下載過程有些慢 只能耐性等待...
添加到環境變量:環境變量目錄
?C:\Users\xiangbin\AppData\Local\Programs\Python\Python39\Lib\site-packages\PyQt5\Qt5\plugins
問題:在安裝第三方庫時出現報錯"These Packages Do Not Match The Hashes From The Requirements File."
原因:通常是因為網速問題導致的下載錯誤,導致對應的哈希值不匹配。
解決方法:需要在pip時,添加"–upgrade"參數即可。通常這時下載還會報錯timeout,因此多加一個"–default-timeout=100000" 更為保險(timeout的賦值可以視情況變化)。
pip install --upgrade --default-timeout=100000 packagename -i http://pypi.douban.com/simple
當使用conda安裝完pyqt5后,在pycharm中配置額外模塊時發現找不到designer.exe文件
經過查資料發現,是因為我安裝pyqt5時,里面不帶這個pyqt5-tools文件,所以在使用conda下的pip下載pyqt5-tools即可(conda是下載不了pyqt5-tools的)
解決方法,在命令行中輸入pip install PyQt5-tools -i http://pypi.douban.com/simple --trusted-host=pypi.douban.com即可
python在虛擬解釋器環境中使用pip安裝第三方庫出現Requirement already satisfied錯誤
原因是:用項目自己創建的虛擬解釋器環境時,因為沒有配置系統環境變量,所以找不到要安裝的地址,不知道這個包要安裝到那個位置。
解決辦法,在安裝語句中加- -target,指定安裝的位置,用項目虛擬解釋器環境安裝的話,安裝位置為項目中的虛擬環境中,默認為:
pip install --target=項目路徑\項目名稱\venv\Lib\site-packages 要安裝的包名
例如:
pip install --target=C:\Users\xiangbin\AppData\Local\Programs\Python\Python39\Lib\site-packages ?PyQt5-tools
1到14課時后續學習后添加!
課時15 ? 開發第一個基于PyQt5的桌面應用
# @CSDN王家視頻教程圖書館 # @Time 2022/11/22 17:59import sysfrom PyQt5.QtWidgets import QApplication,QWidget''' 鑒于這兩種情況中__name__的值是不同的:當一個模塊被直接執行時,其__name__必然等于__main__;當一個模塊被引用時, 其__name__必然等于文件名(不含.py)。所以利用判斷__name__ == '__main__'的真假就可以將這兩種情況區分出來。 ''' if __name__ == '__main__':#創建QApplication類的實例app=QApplication(sys.argv)#創建一個窗口w = QWidget()#設置窗口的尺寸w.resize(300,150)#移動窗口w.move(300,300)#設置窗口的標題w.setWindowTitle('第一個基于pyqt的桌面程序')#顯示窗口w.show()#進入程序的主循環 并通過exit函數確保主循環安全結束sys.exit(app.exec_())?課時16 ? 打開QtDesigner設計師工具
?或者
ctrl+R預覽
將.ui文件轉換為.py文件
方法一: python -m PyQt5.uic.pyuic demo.ui -o demo.py
生成完成 !demo.py
方法二:
python文件夾//打開pyuic5程序 -o 文件名稱 直接生成demo.py
推薦 方式三
?生成完成 !demo1.py
課時17 ? 在QtDesigner中使用布局
全選控件 右鍵 選擇布局 為水平布局
其他布局設置方式同理 因為第二擴展菜單截圖 截不到 這里請參考
?CTRL + R 預覽
?
?課時18 ? 調用源文件:RunDemo.py調用demo.py文件
課時19 ? PyQt5中的瀏覽器控件-QtWebEngine
?新版本的QtDesigner里是沒有WebView的,想要使用瀏覽器控件就需要自己安裝QtWebEngine。安裝之后也是沒有圖形界面的控件的,所以使用策略就是
用其他控件在圖形界面布局,然后生成python代碼之后在代碼中修改
修改代碼參考如下
from PyQt5 import QtWebEngineWidgets
self.webView = QtWebEngineWidgets.QWebEngineView(self.centralwidget)
self.webView.setGeometry(QtCore.QRect(300, 300, 451, 241))
self.webView.setUrl(QtCore.QUrl("https://markwannafly.blog.csdn.net/"))
self.webView.setObjectName("webView")
或者:如何在Python QT Designer中插入Web瀏覽器
課時20 ? Edit 編輯伙伴 編輯Tab順序
課時21 ? 在Qt Designer中設置信號與插槽
信號(signal)
是Qt的核心機制,也是PyQt的核心機制
信號:是由對象或者控件發射出去的消息
按鈕的單擊事件
當單擊按鈕時,按鈕就會向外部發送單擊消息,這些發送出去的信號需要一些代碼來攔截,這些代碼就是插槽上一個函數或者方法
一個信號可以和多個槽綁定,一個槽可以攔截多個信號
?課時22 ?? 動作編輯器
?課時23 ? 主窗口類型
有3種窗口
QMainWindow
QWidget
QDialog
QMainWindow:可以包含菜單欄,工具欄,狀態欄和標題欄
QDialog:是對話窗口的基類。沒有菜單欄,工具欄,狀態欄
QWidget:不確定窗口的用途,就使用QWidget
課時24 ? 接下來用代碼寫一個程序Demo
?這里分享一個在線icon制作的網站:Icon圖標在線制作工具
# @CSDN王家視頻教程圖書館 # @Time 2022/11/22 23:14 import sys from PyQt5.QtWidgets import QMainWindow,QApplication from PyQt5.QtGui import QIcon class FirstMainWin(QMainWindow):def __init__(self):super(FirstMainWin,self).__init__()#設置主窗口的標題self.setWindowTitle("第一個主窗口應用")#設置窗口的尺寸self.resize(400,300)self.status=self.statusBar()self.status.showMessage("只存在5秒的消息",5000)#只有本程序可以調用 防止其他程序調用本程序 if __name__ == '__main__':app=QApplication(sys.argv)app.setWindowIcon(QIcon('./and.png'))main=FirstMainWin()main.show()# 程序的主循環sys.exit(app.exec_())課時25 ? 讓程序居中窗口
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 11:38 # 龍文學python # @Time 2022/11/22 23:14 import sys from PyQt5.QtWidgets import QDesktopWidget,QMainWindow,QApplication from PyQt5.QtGui import QIcon class CenterForm(QMainWindow):def __init__(self):super(CenterForm,self).__init__()#設置主窗口的標題self.setWindowTitle("讓主窗口居中")#設置窗口的尺寸self.resize(400,300)def center(self):# 獲取屏幕坐標系screen=QDesktopWidget.screenGeometry()#獲取窗口坐標系size=self.geometry()newLeft=(screen.width()-size.width())/2newTop=(screen.height()-size.height())/2self.move(newLeft,newTop)#只有本程序可以調用 防止其他程序調用本程序 if __name__ == '__main__':app=QApplication(sys.argv)app.setWindowIcon(QIcon('./and.png'))main=CenterForm()main.show()# 程序的主循環sys.exit(app.exec_())課時26??? 退出應用程序
?課時27 ? 獲取屏幕坐標系
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 12:11 import sys from PyQt5.QtWidgets import QDesktopWidget,QHBoxLayout,QMainWindow,QApplication,QPushButton,QWidgetdef onClick_Button():print("第一種方式 窗口坐標系 包含標題欄")print("widget.x()=%d" % widget.x())print("widget.y()=%d" % widget.y())print("widget.width()=%d" % widget.width())print("widget.height()=%d" % widget.height())print("第二種方式 窗口坐標系 不包含標題欄 只有工作區")print("widget.geometry().x()=%d" % widget.geometry().x())print("widget.geometry().y()=%d" % widget.geometry().y())print("widget.geometry().width()=%d" % widget.geometry().width())print("widget.geometry().height()=%d" % widget.geometry().height())print("第三種方式 暫時未理解全面")print("widget.frameGeometry().x()=%d" % widget.frameGeometry().x())print("widget.frameGeometry().y()=%d" % widget.frameGeometry().y())print("widget.frameGeometry().width()=%d" % widget.frameGeometry().width())print("widget.frameGeometry().height()=%d" % widget.frameGeometry().height()) app=QApplication(sys.argv)widget=QWidget() btn=QPushButton(widget) btn.setText('按鈕')btn.clicked.connect(onClick_Button)btn.move(55,55)widget.resize(300,240)#設置工作區的尺寸widget.move(250,200)widget.setWindowTitle('屏幕坐標系')widget.show()sys.exit(app.exec_())課時28?? 設置窗口和應用程序圖標
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 12:40 ''' 窗口的setWindowIcon方法用于設置窗口的圖標,只在windows中可用 QAplication中的setQindowIcon的方法用于設置主窗口的圖標和應用程序圖標,但調用了窗口的setWindowIcon方法 QAplication中的setQindowIcon的方法就只能用于設置應用程序圖標了 ''' import sys from PyQt5.QtWidgets import QDesktopWidget,QMainWindow,QApplication from PyQt5.QtGui import QIcon class IconFrom(QMainWindow):def __init__(self):super(IconFrom,self).__init__()self.initUI()def initUI(self):self.setGeometry(300, 300, 250, 250)#設置主窗口的標題self.setWindowTitle("設置窗口圖標")#設置窗口圖標self.setWindowIcon(QIcon('./and.png'))#只有本程序可以調用 防止其他程序調用本程序 if __name__ == '__main__':app=QApplication(sys.argv)#app.setWindowIcon(QIcon('./and.png'))main=IconFrom()main.show()# 程序的主循環sys.exit(app.exec_())課時29 顯示控件提示信息
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 12:51 #顯示控件提示信息 import sys from PyQt5.QtWidgets import QDesktopWidget,QHBoxLayout,QMainWindow,QApplication,QToolTip,QPushButton,QWidget from PyQt5.QtGui import QIcon from PyQt5.QtGui import QFontclass TooltipForm(QMainWindow):def __init__(self):super().__init__()self.initUI()def initUI(self):QToolTip.setFont(QFont("SansSerif",12))self.setToolTip('今天是<b>星期五<b>')self.setGeometry(300,300,200,200)self.setWindowTitle('設置控件提示信息')# 添加Buttonself.button1 = QPushButton("我的按鈕")self.button1.setToolTip('這是一個按鈕ok')layout = QHBoxLayout()layout.addWidget(self.button1)mainFrame = QWidget()mainFrame.setLayout(layout)self.setCentralWidget(mainFrame)#按鈕點擊事件方法(自定義的槽)def onClick_Button(self):sender=self.sender()print(sender.text()+'按鈕被按下')app=QApplication.instance()#退出應用程序app.quit()#只有本程序可以調用 防止其他程序調用本程序 if __name__ == '__main__':app=QApplication(sys.argv)app.setWindowIcon(QIcon('./and.png'))main=TooltipForm()main.show()# 程序的主循環sys.exit(app.exec_())課時30 QLabel控件的基本用法
QLabel控件
setAlignment():設置文本的對齊方式
setIndent():設置文本縮進
text():獲取文本內容
selectedText():返回所選擇的字符
setWordWrap():設置是否允許換行
QLabel常用的信號(事件):
1.當鼠標滑過QLabel控件時出發:linkHovered
2.當鼠標單擊QLabel控件時觸發:linkActivated
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 12:51 import sys from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout # 垂直布局 from PyQt5.QtGui import QPalette # 調色版 from PyQt5.QtGui import QPixmap # 展示圖片 from PyQt5.QtCore import Qt # 有一些常量在這里面,eg:blueclass QLabelDdemo(QWidget):def __init__(self):super(QLabelDdemo, self).__init__()self.initUI()def initUI(self):label1 = QLabel(self)label2 = QLabel(self)label3 = QLabel(self)label4 = QLabel(self)label1.setText('<font color=yellow>這是一個文本標簽</font>')label1.setAutoFillBackground(True) # 自動填充背景palette = QPalette()# 設置背景色palette.setColor(QPalette.Window, Qt.blue)#設置背景色# 對label1設置調色版label1.setPalette(palette)# 跳轉到一個網頁或者觸發一個點擊事件label2.setText("<a href='#'>歡迎使用Python GUI程序</a>")# 文本居中label3.setAlignment(Qt.AlignCenter)# 提示信息label3.setToolTip('這是一個圖片標簽')label3.setPixmap(QPixmap('./and.png'))# 如果設為True,用瀏覽器打開網頁,如果設為False,調用槽函數label4.setOpenExternalLinks(True)label4.setText("<a href='www.baidu.com'>打開百度</a>")# 右對齊label4.setAlignment(Qt.AlignRight)label4.setToolTip('這是一個超級鏈接')vbox = QVBoxLayout()vbox.addWidget(label1)vbox.addWidget(label2)vbox.addWidget(label3)vbox.addWidget(label4)# 綁定信號和槽# 滑過事件label2.linkHovered.connect(self.linkHovered)# 單擊事件label4.linkActivated.connect(self.linkClicked)self.setLayout(vbox)self.setWindowTitle('QLabel控件演示')self.resize(400, 300)returndef linkHovered(self):print('當鼠標滑過label2標簽時,觸發事件')def linkClicked(self):print('當鼠標單擊label4標簽時,觸發事件')if __name__ == '__main__':app = QApplication(sys.argv)main = QLabelDdemo()main.show()sys.exit(app.exec_())課時31 QLabel與伙伴關系
伙伴關系
舉例:柵格布局下給控件設置伙伴關系
addWidget函數:
mainLayout . addWidget(控件對象, rowIndex, columnIndex, row, column)
第一個參數是要添加的控件對象,第二個和第三個是位置索引(行,列),就像矩陣一樣是從(0,0)開始的,第四,五參數是空間大小,第四個是占幾行,第五個是占幾列
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 14:12 from PyQt5.QtWidgets import * import sys''' QLabel與伙伴控件 控件對象 #組件對象 rowIndex,columnIndex #控件位置 row,column #指定控件的尺寸 mainLayout.addWidget(控件對象,rowIndex,columnIndex,row,column) ''' class QLabelBuddy(QDialog):def __init__(self):super(QLabelBuddy, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QLabel與伙伴關系')self.resize(400, 150)# &代表設置熱鍵,其后第一個字母就是熱鍵,不區分大小寫,Alt+熱鍵調用即可nameLabel = QLabel('&Name(N)', self) # designer下的labelnameLineEdit = QLineEdit(self) # designer下的lineEdit,即文本輸入框# 設置伙伴關系nameLabel.setBuddy(nameLineEdit)passwordLabel = QLabel('&Password(P)', self) # designer下的labelpasswordLineEdit = QLineEdit(self) # designer下的lineEdit,即文本輸入框# 設置伙伴關系passwordLabel.setBuddy(passwordLineEdit)btnOK = QPushButton('&OK(O)')btnCancel = QPushButton('&Cancel(C)')# 柵格布局mainlayout = QGridLayout(self)mainlayout.addWidget(nameLabel, 0, 0) # 放在第一行第一列# 放在第一行第二列,占用空間大小為一行兩列(占用大小一行兩列意思就是編輯框寬是標簽控件的兩倍)mainlayout.addWidget(nameLineEdit, 0, 1, 1, 2)mainlayout.addWidget(passwordLabel, 1, 0) # 放在第二行第一列mainlayout.addWidget(passwordLineEdit, 1, 1, 1, 2) # 放在第二行第二列,占用空間大小為一行兩列mainlayout.addWidget(btnOK, 2, 1) # 第三行第二列mainlayout.addWidget(btnCancel, 2, 2) # 第三行第三列returnif __name__ == '__main__':app = QApplication(sys.argv)main = QLabelBuddy()main.show()sys.exit(app.exec_())課時32 QLineEdit控件與回顯模式
?
課時33 限制QLineEdi t控件的輸入
校驗器
如限制只能輸入整數、浮點數或滿足一定條件的字符串
代碼問題:
限制范圍的函數setRange有bug 需要正則表達式解決bug 可能在蘋果系統可以(應該也不行) win系統不行
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 15:04 課時33 限制QLineEdi t控件的輸入import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import QIntValidator, QDoubleValidator, QRegExpValidator # 最后一個是正則表達式校驗器 from PyQt5.QtCore import QRegExp # 正則表達式類class QLineEditValidator(QWidget):def __init__(self):super(QLineEditValidator, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('文龍學校驗器')# 創建表單布局formLayout = QFormLayout()intLineEdit = QLineEdit()doubleLineEdit = QLineEdit()validatorLineEdit = QLineEdit()formLayout.addRow('整數類型', intLineEdit)formLayout.addRow('浮點類型', doubleLineEdit)formLayout.addRow('數字和字母', validatorLineEdit)intLineEdit.setPlaceholderText('整型[1,99]')doubleLineEdit.setPlaceholderText('浮點類型[-360,360]')validatorLineEdit.setPlaceholderText('數字和字母')# 整數校驗器[1,99]intValidator = QIntValidator(self) # 因為此函數需要一個QWidget對象作為參數,所以把自己傳進去了intValidator.setRange(1, 99) # 試了試可以輸入0# 浮點校驗器[-1,360],精度:小數點后2位doubleValidator = QDoubleValidator(self) # 傳self原因同上doubleValidator.setRange(-1, 360) # setRange有bug 需要正則表達式解決bug 可以在蘋果系統可以(沒有試過) win系統不行doubleValidator.setNotation(QDoubleValidator.StandardNotation)# 設置精度,小數點2位doubleValidator.setDecimals(2)# 字符和數字reg = QRegExp('[a-zA-Z0-9]+$') # 正則表達式validtor = QRegExpValidator(self) # 傳self原因同上validtor.setRegExp(reg)# 設置校驗器intLineEdit.setValidator(intValidator)doubleLineEdit.setValidator(doubleValidator)validatorLineEdit.setValidator(validtor)self.setLayout(formLayout)if __name__ == '__main__':app = QApplication(sys.argv)main = QLineEditValidator()main.show()sys.exit(app.exec_())課時34 使用掩碼限制QLineEdit控件的輸入
用掩碼限制QLineEdit控件的輸入
A:ASCII字母字符是必須輸入的(A-Z、a-z) a:ASCII字母字符是允許輸入的,但不是必需的(A-Z、a-z) N:ASCII字母字符是必須輸入的(A-Z、a-z、0-9) n:ASCII字母字符是允許輸入的,但不是必需的(A-Z. a-z、0-9) X:任何字符都是必須輸入的 x:任何字符都是允許輸入的,但不是必需的 9:ASCII數字字符是必須輸入的(0-9) 0:ASCII數字字符是允許輸入的,但不是必需的(0-9) D:ASCII數字字符是必須輸入的(1-9) d:ASCII數字字符是允許輸入的,但不是必需的(1-9) #:ASCII數字字符或加減符號是允許輸入的,但不是必需的 H:十六進制格式字符是必須輸入的(A-F、a-f、0-9) h:十六進制格式字符是允許輸入的,但不是必需的(A-F、a-f、0-9) B:二進制格式字符是必須輸入的(0, 1) b:二進制格式字符是允許輸入的,但不是必需的(0, 1) >:所有的字母字符都大寫<:所有字母字符都小寫!:關閉大小寫轉換\:使用"\"轉義上面列出的字符 # @CSDN王家視頻教程圖書館 # @Time 2022/11/23 15:26 import sys from PyQt5.QtWidgets import *class QLineEditMask(QWidget):def __init__(self):super(QLineEditMask, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('用掩碼限制QLineEdit控件的輸入')formLayout = QFormLayout()ipLineEdit = QLineEdit() # ip地址macLineEdit = QLineEdit() # MAC地址dateLineEdit = QLineEdit() # 日期licenseLineEdit = QLineEdit() # 驗證碼#192.168.21.45# 最后加個分號和_意為沒輸入是默認顯示_ ,前面的都是掩碼,即ASCII數字字符是允許輸入的,但不是必需的(0-9)ipLineEdit.setInputMask('000.000.000.000;_')macLineEdit.setInputMask('HH:HH:HH:HH:HH:HH;_')dateLineEdit.setInputMask('0000-00-00')licenseLineEdit.setInputMask('>AAAAA-AAAAA-AAAAA-AAAAA-AAAAA;#') # 若沒有輸入顯示井號formLayout.addRow('數字掩碼', ipLineEdit)formLayout.addRow('MAC掩碼', macLineEdit)formLayout.addRow('日期掩碼', dateLineEdit)formLayout.addRow('許可證掩碼', licenseLineEdit)self.setLayout(formLayout)if __name__ == '__main__':app = QApplication(sys.argv)main = QLineEditMask()main.show()sys.exit(app.exec_())課時35 QLineEdit綜合案例
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 15:37 from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import Qt import sysclass QLine_comprehensive_case(QWidget):def __init__(self):super(QLine_comprehensive_case, self).__init__()self.initUI()def initUI(self):'''控件定義及屬性設置'''edit1 = QLineEdit()# int校驗器edit1.setValidator(QIntValidator())# 設置最大位數為4位,即不超過9999edit1.setMaxLength(4)# 右對齊edit1.setAlignment(Qt.AlignRight)# 這個字號直接影響輸入框的尺寸edit1.setFont(QFont('Arial', 18))edit2 = QLineEdit()edit2.setValidator(QDoubleValidator(0.99, 99.99, 2)) # 2是精度,即小數點后幾位edit3 = QLineEdit()edit3.setInputMask('99_9999_999999;#')edit4 = QLineEdit()edit4.textChanged.connect(self.textChanged) # 綁定信號和槽edit5 = QLineEdit()edit5.setEchoMode(QLineEdit.Password)edit5.editingFinished.connect(self.enterPress) # 綁定信號和槽edit6 = QLineEdit('Hello Pyqt5!')edit6.setReadOnly(True) # 只讀'''將控件添加到表單'''formlayout = QFormLayout()formlayout.addRow('整數校驗', edit1)formlayout.addRow('浮點數校驗', edit2)formlayout.addRow('input mask', edit3)formlayout.addRow('文本變化', edit4)formlayout.addRow('密碼', edit5)formlayout.addRow('只讀', edit6)'''設置主窗口屬性'''self.setLayout(formlayout)self.setWindowTitle('QLineEdit綜合案例')'''槽函數'''def textChanged(self, text):print('輸入的內容' + text)def enterPress(self):print('已輸入值')if __name__ == '__main__':app = QApplication(sys.argv)main = QLine_comprehensive_case()main.show()sys.exit(app.exec_())課時36 使用QTextEdit控件輸入多行文本
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 16:30 from PyQt5.QtWidgets import * import sysclass QTextEditDemo(QWidget):def __init__(self):super(QTextEditDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QTextEdit控件演示')self.resize(300, 320)# 定義控件self.textEdit = QTextEdit()self.buttonText = QPushButton('顯示文本')self.buttonHTML = QPushButton('顯示HTML')self.buttonToText = QPushButton('獲取文本')self.buttonToHTML = QPushButton('獲取HTML')# 垂直布局layout = QVBoxLayout()layout.addWidget(self.textEdit)layout.addWidget(self.buttonText)layout.addWidget(self.buttonHTML)layout.addWidget(self.buttonToText)layout.addWidget(self.buttonToHTML)# 綁定信號和槽self.buttonText.clicked.connect(self.onClick_buttonText)self.buttonHTML.clicked.connect(self.onClick_buttonHTML)self.buttonToText.clicked.connect(self.onClick_buttonToText)self.buttonToHTML.clicked.connect(self.onClick_buttonToHTML)self.setLayout(layout)# 槽函數def onClick_buttonText(self):# 普通文本self.textEdit.setPlainText('Hello World!')def onClick_buttonHTML(self):# 富文本(HTML)self.textEdit.setHtml('<font color="blue" size="5">Hello World</font>')def onClick_buttonToText(self):print(self.textEdit.toPlainText()) # 控制臺輸出普通文本def onClick_buttonToHTML(self):print(self.textEdit.toHtml()) # 控制臺輸出HTML文本if __name__ == '__main__':app = QApplication(sys.argv)main = QTextEditDemo()main.show()sys.exit(app.exec_())課時37 按鈕控件(QpushButton)
QAbstractButton(所有按鈕控件的父類) QPushButton(普通按鈕) AToolButton(工具條按鈕) QRadioButton(單選框按鈕) QCheckBox(復選框按鈕)?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 16:47import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class QPushButtonDemo(QDialog):def __init__(self):super(QPushButtonDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QPushButton Demo')self.resize(350, 200)layout = QVBoxLayout() # 垂直布局self.btn1 = QPushButton('第一個按鈕')self.btn1.setText('First Button1')# 下面兩句配合使用,功能類似于單選框按鈕QCheckBoxself.btn1.setCheckable(True)self.btn1.toggle() # 按一下就按下去了,再按一下才能抬起# btn1一個信號對應兩個槽函數self.btn1.clicked.connect(self.buttonState) # 先綁定誰系統就先調用誰self.btn1.clicked.connect(lambda: self.whichButton(self.btn1))layout.addWidget(self.btn1)# 在文本前面顯示圖像self.btn2 = QPushButton('圖像按鈕')self.btn2.setIcon(QIcon(QPixmap('./and.png')))self.btn2.clicked.connect(lambda: self.whichButton(self.btn2))layout.addWidget(self.btn2)self.btn3 = QPushButton('不可用的按鈕')self.btn3.setEnabled(False)layout.addWidget(self.btn3)self.btn4 = QPushButton('&MyButton') # 設置了熱鍵M/mself.btn4.setDefault(True) # 如果沒有任何按鈕被選中,那么按回車就是按了這個按鈕self.btn4.clicked.connect(lambda: self.whichButton(self.btn4))layout.addWidget(self.btn4)self.setLayout(layout)'''注意下面的方法是兩個參數,如果用傳統的信號與槽連接方式的話,只會將按鈕對象本身傳入,那樣的話第二個參數就沒有傳入值了所以要用lambda表達式,當前對象直接調用這個函數,傳入的值就對應第二個參數了'''def whichButton(self, btn):# self.sender() #通過此方法可得到是哪個按鈕被按下,或者可用此方法中的傳參方法print('被單擊的按鈕是<' + btn.text() + '>')def buttonState(self):if self.btn1.isChecked():print('按鈕1已經被選中')else:print('按鈕1未被選中')if __name__ == '__main__':app = QApplication(sys.argv)main = QPushButtonDemo()main.show()sys.exit(app.exec_())單選按鈕控件QRatioButton
在一個容器內的單選按鈕是互斥的,即選中了一個單選按鈕,就不能再選中另一個單選按鈕,也就是不能同時處于選中狀態。在不同容器中的單選按鈕是分開的,互不影響。
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 17:12 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import *class QRatioButtonDemo(QWidget):def __init__(self):super(QRatioButtonDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QRatioButton')self.resize(350, 100)# 水平布局layout = QHBoxLayout()self.btn1 = QRadioButton('單選按鈕1')# 設為默認是選中狀態self.btn1.setChecked(True)# toggled是狀態切換的信號self.btn1.toggled.connect(self.buttonState)layout.addWidget(self.btn1)self.btn2 = QRadioButton('單選按鈕2')self.btn2.toggled.connect(self.buttonState)layout.addWidget(self.btn2)self.setLayout(layout)def buttonState(self):ratiobtn = self.sender()if ratiobtn.isChecked() == True:print('<' + ratiobtn.text() + '>被選中')else:print('<' + ratiobtn.text() + '>被取消選中狀態')# 同一容器下單選按鈕是互斥的,所以不必利用ratiobtn.text()來分情況判斷'''if ratiobtn.text()=='單選按鈕1':#是否被選中if ratiobtn.isChecked()==True:print('<'+ratiobtn.text()+'>被選中')else:print('<'+ratiobtn.text()+'>被取消選中狀態')if ratiobtn.text()=='單選按鈕2':if ratiobtn.isChecked()==True:print('<'+ratiobtn.text()+'>被選中')else:print('<'+ratiobtn.text()+'>被取消選中狀態')'''if __name__ == '__main__':app = QApplication(sys.argv)main = QRatioButtonDemo()main.show()sys.exit(app.exec_())課時39 復選框控件QCheckBox
3種狀態:未選中:0半選中:1選中:2tristate屬性表示復選框是三種狀態還是兩種狀態,如果tristate為true,則表示復選框中有選中,半選中,未選中三種狀態,即setTristate(True)即表示允許半選中。
# @CSDN王家視頻教程圖書館
# @Time 2022/11/23 17:39import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtCore import Qt # 其中有許多常量class QCheckBoxDemo(QWidget):def __init__(self):super(QCheckBoxDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QCheckBoxDemo')self.resize(350, 100)layout = QHBoxLayout()self.checkbox1 = QCheckBox('復選框控件1')# 默認選中self.checkbox1.setChecked(True) # 此函數只有兩種狀態self.checkbox1.stateChanged.connect(lambda: self.checkboxState(self.checkbox1))layout.addWidget(self.checkbox1)self.checkbox2 = QCheckBox('復選框控件2')self.checkbox2.stateChanged.connect(lambda: self.checkboxState(self.checkbox2))layout.addWidget(self.checkbox2)self.checkbox3 = QCheckBox('半選中控件3')# 設置選中有三個狀態(即允許半選中)self.checkbox3.setTristate(True)# setCheckState函數有三種狀態:Unchecked,PartiallyChecked,Checkedself.checkbox3.setCheckState(Qt.PartiallyChecked)self.checkbox3.stateChanged.connect(lambda: self.checkboxState(self.checkbox3))layout.addWidget(self.checkbox3)self.setLayout(layout)def checkboxState(self, cb):check1Status = self.checkbox1.text() + ',isChecked=' + str(self.checkbox1.isChecked()) + ',isCheckstate=' + str(self.checkbox1.checkState()) + '\n'check2Status = self.checkbox2.text() + ',isChecked=' + str(self.checkbox2.isChecked()) + ',isCheckstate' + str(self.checkbox2.checkState()) + '\n'check3Status = self.checkbox3.text() + ',isChecked=' + str(self.checkbox3.isChecked()) + ',isCheckstate' + str(self.checkbox3.checkState()) + '\n'print(check1Status + check2Status + check3Status)if __name__ == '__main__':app = QApplication(sys.argv)main = QCheckBoxDemo()main.show()sys.exit(app.exec_())
?課時40 下拉列表控件QComboBox
1 如何將列表項添加到QComboBox控件中
2 如何獲取選中的列表項
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 17:56import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtCore import Qt # 其中有許多常量class QComboBoxDemo(QWidget):def __init__(self):super(QComboBoxDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QComboBoxDemo')self.resize(350, 100)# 垂直布局layout = QVBoxLayout()self.label = QLabel('請選擇編程語言')self.cb = QComboBox()self.cb.addItem('JavaEE')self.cb.addItem('Uniapp')self.cb.addItems(['Python', '大數據', '區塊鏈'])# 每一項都對應一個下標索引self.cb.currentIndexChanged.connect(self.selectionChange) # 此信號默認傳遞兩個參數(控件本身,索引)layout.addWidget(self.label)layout.addWidget(self.cb)self.setLayout(layout)def selectionChange(self, i):# 標簽會隨著當前選中的下拉項而改變self.label.setText(self.cb.currentText())self.label.adjustSize()for j in range(self.cb.count()):print('item' + str(j) + '=' + self.cb.itemText(j))print('current index', i, 'selection changed', self.cb.currentText())if __name__ == '__main__':app = QApplication(sys.argv)main = QComboBoxDemo()main.show()sys.exit(app.exec_())?課時41 滑塊控件QSlider
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 18:20 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import Qt # 其中有許多常量class QSliderDemo(QWidget):def __init__(self):super(QSliderDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QSlider演示')self.resize(350, 500)# 垂直布局layout = QVBoxLayout()self.label = QLabel('Hello PyQt5!')self.label.setAlignment(Qt.AlignCenter)layout.addWidget(self.label)# 滑塊分為水平和垂直兩種# 水平slider1self.slider1 = QSlider(Qt.Horizontal) # 水平,左右滑動# 設置最小值self.slider1.setMinimum(12)# 設置最大值self.slider1.setMaximum(48)# 步長self.slider1.setSingleStep(3)# 設置當前值self.slider1.setValue(18)# 設置刻度的位置,刻度在下方self.slider1.setTickPosition(QSlider.TicksBelow)# 刻度間隔self.slider1.setTickInterval(6)self.slider1.valueChanged.connect(self.valueChange)# 垂直slider2self.slider2 = QSlider(Qt.Vertical) # 垂直滑塊self.slider2.setMinimum(1)self.slider2.setMaximum(80)self.slider2.setSingleStep(5)self.slider2.setTickPosition(QSlider.TicksLeft) # 刻度條放在滑塊的左邊self.slider2.setTickInterval(10)self.slider2.valueChanged.connect(self.valueChange)layout.addWidget(self.slider1)layout.addWidget(self.slider2)self.setLayout(layout)def valueChange(self):'''注意這里是sender(),而不是slider1也不是slider2,sender()獲取當前操作的控件,這樣無論拖動哪個滑動條字體大小都會變化,因為這倆信號對應這一個槽函數'''print('當前值:%s' % self.sender().value())size = self.sender().value() # 獲得當前值# 使字號根據當前值來變化self.label.setFont(QFont('Arial', size))if __name__ == '__main__':app = QApplication(sys.argv)main = QSliderDemo()main.show()sys.exit(app.exec_())課時42 計數器控件QSpinBox
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 18:34 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import Qt # 其中有許多常量class QSpinBoxDemo(QWidget):def __init__(self):super(QSpinBoxDemo, self).__init__()self.initUI()def initUI(self):####################################### 窗口設置self.setWindowTitle('QSliderDemo')self.resize(350, 120)# 垂直布局layout = QVBoxLayout()######################################## 控件self.label = QLabel('當前值')self.label.setAlignment(Qt.AlignCenter)self.sb = QSpinBox()# 默認值self.sb.setValue(18)# 設置范圍self.sb.setRange(10, 38)# 設置步長self.sb.setSingleStep(3)####################################### 信號與槽self.sb.valueChanged.connect(self.valueChange)####################################### 組裝layout.addWidget(self.label)layout.addWidget(self.sb)self.setLayout(layout)def valueChange(self):self.label.setText('當前值:' + str(self.sb.value()))if __name__ == '__main__':app = QApplication(sys.argv)main = QSpinBoxDemo()main.show()sys.exit(app.exec_())課時43 使用 QDialog顯示通用對話框
QMessageBox??? 消息對話框
QColorDialog????? 顏色對話框
QFileDialog?? ? ?? 文件對話框
QFontDia log????? 字體對話框
QInputDialog????? 輸入對話框(獲取輸入信息)
課時44 顯示不同類型的消息對話框
?
主要用于顯示軟件的版本和作者及其他和軟件息息相關的信息
常用的消息對話框:
1.關于對話框
2.錯誤對話框
3.警告對話框
4.提問對話框
5.消息對話框
有2點差異
1.顯示的對話框圖標可能不同
2.顯示的按鈕是不一樣的
課時45 輸入對話框QInputDialog
QInputDialog.getItem? 用于顯示輸入列表,即往里傳入一個元組或列表,就會顯示一個QComboBox
QInputDialog.getText? 用于錄入普通文本
QInputDialog.getInt???? 用于輸入整數的,顯示一個計數器控件
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 19:38 import sys from PyQt5.QtWidgets import *class QInputDialogDemo(QWidget):def __init__(self):super(QInputDialogDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QInputDialogDemo')self.resize(400, 150)# 表單布局layout = QFormLayout()self.btn1 = QPushButton('獲取列表中的選項')self.btn1.clicked.connect(self.getItem)self.lineEdit1 = QLineEdit()layout.addRow(self.btn1, self.lineEdit1)self.btn2 = QPushButton('獲取字符串')self.btn2.clicked.connect(self.getText)self.lineEdit2 = QLineEdit()layout.addRow(self.btn2, self.lineEdit2)self.btn3 = QPushButton('獲取整數')self.btn3.clicked.connect(self.getInt)self.lineEdit3 = QLineEdit()layout.addRow(self.btn3, self.lineEdit3)self.setLayout(layout)# 槽函數# 下拉框def getItem(self):items = ('JavaEE', 'Uniapp', '大數據', '區塊鏈', '人工智能')# 返回的是個元組,第一個元素就是input里對應的內容,第二個元素是個布爾量,如果對話框是按OK則返回1,取消就是返回0item, ok = QInputDialog.getItem(self, '請選擇技術方向', '技術列表', items)print(ok) # 點了OK就返回True,點了Cancel就返回Falseif ok and item:self.lineEdit1.setText(item)print(ok)# 字符串def getText(self):text, ok = QInputDialog.getText(self, '文本輸入框', '輸入姓名')if ok and text:self.lineEdit2.setText(text)# 整數def getInt(self):num, ok = QInputDialog.getInt(self, '整數輸入框', '輸入數字')if ok and num:self.lineEdit3.setText(str(num))if __name__ == '__main__':app = QApplication(sys.argv)main = QInputDialogDemo()main.show()sys.exit(app.exec_())課時46? 字體對話框QFontDialog
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 19:52 import sys from PyQt5.QtWidgets import *class QFontDialogDemo(QWidget):def __init__(self):super(QFontDialogDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QFontDialogDemo')self.resize(400, 150)layout = QVBoxLayout()self.fontBtn = QPushButton('選擇字體')self.fontBtn.clicked.connect(self.getFont)layout.addWidget(self.fontBtn)self.fontLabel = QLabel('Hello,測試字體例子')layout.addWidget(self.fontLabel)self.setLayout(layout)def getFont(self):(font, ok) = QFontDialog.getFont()if ok:self.fontLabel.setFont(font)if __name__ == '__main__':app = QApplication(sys.argv)main = QFontDialogDemo()main.show()sys.exit(app.exec_())?課時47 顏色對話框QColorDialog
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 19:59 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import QPaletteclass QColorDialogDemo(QWidget):def __init__(self):super(QColorDialogDemo, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QColorDialogDemo')self.resize(400, 150)layout = QVBoxLayout()self.colorBtn = QPushButton('設置顏色')self.colorBtn.clicked.connect(self.getColor)layout.addWidget(self.colorBtn)self.colorBackBtn = QPushButton('設置背景顏色')self.colorBackBtn.clicked.connect(self.getBackColor)layout.addWidget(self.colorBackBtn)self.colorLabel = QLabel('Hello,測試顏色例子')layout.addWidget(self.colorLabel)self.setLayout(layout)def getColor(self):color = QColorDialog.getColor()# 調色板p = QPalette()# 注意WindowText(這是類屬性,常量)的大小寫,這是常量,別選錯了!!!!p.setColor(QPalette.WindowText, color)print('QPalette.WindowText =', QPalette.WindowText)print('QPalette.Window =', QPalette.Window)self.colorLabel.setPalette(p)# 設置背景顏色def getBackColor(self):color = QColorDialog.getColor()p = QPalette()p.setColor(QPalette.Window, color)# 自動填充背景self.colorLabel.setAutoFillBackground(True)self.colorLabel.setPalette(p)if __name__ == '__main__':app = QApplication(sys.argv)main = QColorDialogDemo()main.show()sys.exit(app.exec_())課時48 文件對話框QFileDialog
課時49 在窗口上繪制文本
繪圖API: 繪制文本
1.文本
2.各種圖形(直線,點,橢圓,弧,扇形,多邊形等)
3.圖像
QPainter過程:
painter = QPainter()????????? #創建繪制對象
painter. begin()?????????????? ? #開始繪制
painter. drawText(...)??????? #繪制過程
painter. end()??????? ?????????? #結束繪制
必須在paintEvent事件方法(此方法窗口自動調用,創建窗口或窗口尺寸變化時)中繪制各種元素
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 20:29 import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtGui import QPainter, QColor, QFont from PyQt5.QtCore import Qtclass DrawText(QWidget):def __init__(self):super(DrawText, self).__init__()self.setWindowTitle('在窗口上繪制文本')self.resize(300, 200)self.text = 'CSDN王家視頻教程圖書館'def paintEvent(self, event):painter = QPainter(self)painter.begin(self)print('窗口大小改變,此方法會不斷調用')# 畫筆painter.setPen(QColor(150, 43, 5)) # RGB# 字體,字號painter.setFont(QFont('SimSun', 25))# 繪圖區域,居中,繪制文本painter.drawText(event.rect(), Qt.AlignCenter, self.text)painter.end()if __name__ == '__main__':app = QApplication(sys.argv)main = DrawText()main.show()sys.exit(app.exec_())課時50 用像素點繪制正弦曲線
#核心代碼參考for i in range(1000):x = 100 * (-1 + 2.0 * i / 1000) + size.width() / 2.0 # 加上size.width()/2.0是將繪制圖像原點挪到窗口中間y = -50 * math.sin((x - size.width() / 2.0) * math.pi / 50) + size.height() / 2.0painter.drawPoint(x, y) # 說是曲線,其實是畫了1000個點,看上去有點像曲線 # @CSDN王家視頻教程圖書館 # @Time 2022/11/23 20:34 ''' 用像素點繪制正弦曲線 -2PI 2PI drawPoint(x,y) '''import sys, math from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import Qtclass DrawPoints(QWidget):def __init__(self):super(DrawPoints, self).__init__()self.resize(500, 300)self.setWindowTitle('在窗口上用像素點繪制2個周期的正弦曲線')def paintEvent(self, event):painter = QPainter() # 定義畫圖對象painter.begin(self) # 開始畫圖painter.setPen(Qt.blue)size = self.size()for i in range(1000):x = 100 * (-1 + 2.0 * i / 1000) + size.width() / 2.0 # 加上size.width()/2.0是將繪制圖像原點挪到窗口中間y = -50 * math.sin((x - size.width() / 2.0) * math.pi / 50) + size.height() / 2.0painter.drawPoint(x, y) # 說是曲線,其實是畫了1000個點,看上去有點像曲線painter.end() # 結束畫圖if __name__ == '__main__':app = QApplication(sys.argv)main = DrawPoints()main.show()sys.exit(app.exec_())課時51 繪制不同類型的直線
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 20:22 import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtGui import QPainter, QColor, QFont, QPen from PyQt5.QtCore import Qtclass DrawMutilLine(QWidget):def __init__(self):super(DrawMutilLine, self).__init__()self.setWindowTitle('設置Pen的樣式')self.resize(350, 250)def paintEvent(self, event):painter = QPainter()painter.begin(self)# 顏色,粗細,畫筆類型pen = QPen(Qt.red, 3, Qt.SolidLine) # 最后一個參數是實線painter.setPen(pen)painter.drawLine(20, 40, 250, 40)pen.setStyle(Qt.DashLine)painter.setPen(pen) # 切記設置完style之后,要再將pen設置一遍,否則不會起作用painter.drawLine(20, 80, 250, 80)pen.setStyle(Qt.DashDotDotLine)painter.setPen(pen)painter.drawLine(20, 120, 250, 120)pen.setStyle(Qt.DotLine)painter.setPen(pen)painter.drawLine(20, 160, 250, 160)pen.setStyle(Qt.CustomDashLine)pen.setDashPattern([1, 10, 5, 10]) # 線長度,間隔長度,線長度,間隔長度painter.setPen(pen)painter.drawLine(20, 200, 250, 200)painter.end()if __name__ == '__main__':app = QApplication(sys.argv)main = DrawMutilLine()main.show()sys.exit(app.exec_())課時52 繪制各種圖形
繪制各種圖形
弧
圓形
橢圓
矩形(正方形)
多邊形
繪制圖像
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 20:47 import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtGui import QPainter, QPolygon, QImage from PyQt5.QtCore import Qt, QRect, QPoint import osclass DrawAll(QWidget):def __init__(self):super(DrawAll, self).__init__()self.setWindowTitle('繪制各種圖形')self.resize(400, 600)def paintEvent(self, event):qp = QPainter(self)qp.begin(self)qp.setPen(Qt.blue)# 繪制弧# 左上角坐標,寬,高rect = QRect(0, 10, 200, 200)# 繪制區域(在其中繪制,起始角度,結束角度)# alen:一個alen等于1/16度,eg:畫45°的弧就是45*16qp.drawArc(rect, 0, 50 * 16)# 通過弧繪制圓qp.setPen(Qt.red)# rect也可直接當參數傳進去qp.drawArc(120, 10, 100, 100, 0, 360 * 16)# 繪制帶弦的弧rect1 = QRect(10, 120, 100, 100)qp.drawChord(rect1, 12, 130 * 16)# 繪制扇形rect2 = QRect(10, 240, 100, 100)qp.drawPie(rect2, 12, 130 * 16)# 橢圓(不需要指定角度)# 寬和高肯定是不一樣的,如果一樣就是圓了,所以繪制圓可以通過橢圓,也可以通過弧qp.drawEllipse(120, 120, 150, 100)# 繪制多邊形# 五邊形,需要五個點point1 = QPoint(140, 380)point2 = QPoint(270, 420)point3 = QPoint(290, 512)point4 = QPoint(290, 588)point5 = QPoint(200, 533)polygon = QPolygon([point1, point2, point3, point4, point5])qp.drawPolygon(polygon)# 繪制圖像print(os.path.exists('./and.png')) # 此路徑是否存在# 裝載圖像image = QImage('./and.png')# 將圖像(面積)縮小64倍rect3 = QRect(10, 400, image.width() / 8, image.height() / 8)qp.drawImage(rect3, image)qp.end()if __name__ == '__main__':app = QApplication(sys.argv)main = DrawAll()main.show()sys.exit(app.exec_())?課時53 用畫刷填充圖形區域
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 21:02 import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtGui import QPainter, QPolygon, QImage, QBrush from PyQt5.QtCore import Qt, QRect, QPointclass FillRect(QWidget):def __init__(self):super(FillRect, self).__init__()self.setWindowTitle('繪制各種圖形')self.resize(400, 200)def paintEvent(self, event):qp = QPainter(self)qp.begin(self)brush = QBrush(Qt.SolidPattern) # 實心qp.setBrush(brush)qp.drawRect(10, 15, 90, 60)brush = QBrush(Qt.Dense1Pattern)qp.setBrush(brush)qp.drawRect(130, 15, 90, 60)brush = QBrush(Qt.Dense2Pattern)qp.setBrush(brush)qp.drawRect(250, 15, 90, 60)brush = QBrush(Qt.Dense3Pattern)qp.setBrush(brush)qp.drawRect(10, 105, 90, 60)brush = QBrush(Qt.HorPattern)qp.setBrush(brush)qp.drawRect(130, 105, 90, 60)qp.end()if __name__ == '__main__':app = QApplication(sys.argv)main = FillRect()main.show()sys.exit(app.exec_())?課時54 讓控件支持拖拽動作
過程:
A.setDrapEnabled(True)?? 設置A支持拖拽
B. setAcceptDrops(True)?? 設置B可接收
B需要兩個事件:
1. dragEnterEvent???? 將A拖到B觸發
2. dropEvent???????????? 在B的區域放下A時觸發
?課時55 使用剪貼板
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 21:22 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import *class ClipBoardDemo(QDialog):def __init__(self):super(ClipBoardDemo, self).__init__()# 控件# 定義六個復制粘貼按鈕,用來實現復制粘貼文本,圖像和HTML網頁textCopyBtn = QPushButton('復制文本')textPasteBtn = QPushButton('粘貼文本')htmlCopyBtn = QPushButton('復制HTML')htmlPasteBtn = QPushButton('粘貼HTML')imageCopyBtn = QPushButton('復制圖像')imagePasteBtn = QPushButton('粘貼圖像')# 多行文本self.textLabel = QLabel('默認文本')# 標簽用于展示圖片self.imageLabel = QLabel()# 定義網格柵格布局layout = QGridLayout()layout.addWidget(textCopyBtn, 0, 0)layout.addWidget(imageCopyBtn, 0, 1)layout.addWidget(htmlCopyBtn, 0, 2)layout.addWidget(textPasteBtn, 1, 0)layout.addWidget(imagePasteBtn, 1, 1)layout.addWidget(htmlPasteBtn, 1, 2)layout.addWidget(self.textLabel, 2, 0, 1, 2) # 坐標,行占的單位寬度,列占的單位寬度layout.addWidget(self.imageLabel, 2, 2)self.setLayout(layout)# 信號與槽textCopyBtn.clicked.connect(self.copyText)textPasteBtn.clicked.connect(self.pasteText)htmlCopyBtn.clicked.connect(self.copyHtml)htmlPasteBtn.clicked.connect(self.pasteHtml)imageCopyBtn.clicked.connect(self.copyImage)imagePasteBtn.clicked.connect(self.pasteImage)self.setWindowTitle('剪貼板演示')# 槽函數def copyText(self):# 剪貼板對象clipboard = QApplication.clipboard()clipboard.setText('hello csdn')def pasteText(self):clipboard = QApplication.clipboard()self.textLabel.setText(clipboard.text())def copyImage(self):clipboard = QApplication.clipboard()clipboard.setPixmap(QPixmap('./csdnlogo.jpg'))def pasteImage(self):clipboard = QApplication.clipboard()# clipboard.pixmap()是從剪貼板獲得圖像self.imageLabel.setPixmap(clipboard.pixmap())def copyHtml(self):mimeData = QMimeData() # 獲得數據類型mimeData.setHtml('<b>Bold and <font color=red>Red</font></b>')clipboard = QApplication.clipboard()clipboard.setMimeData(mimeData)def pasteHtml(self):clipboard = QApplication.clipboard()mimeData = clipboard.mimeData() # 獲得剪貼板數據# 如果剪貼板數據是html,這里普通文本也可以if mimeData.hasHtml():self.textLabel.setText(mimeData.html())if __name__ == '__main__':app = QApplication(sys.argv)main = ClipBoardDemo()main.show()sys.exit(app.exec_())課時56 日歷控件
日歷控件:QCalendarWidget
課時57 設置不同風格的日期和時間
控件:QDateTimeEdit
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 21:39 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import *class DateTimeEdit1(QWidget):def __init__(self):super(DateTimeEdit1, self).__init__()self.initUI()def initUI(self):# 垂直布局vlayout = QVBoxLayout()dateTimeEdit1 = QDateTimeEdit()dateTimeEdit2 = QDateTimeEdit(QDateTime.currentDateTimeUtc()) # 傳入當前時間dateEdit = QDateTimeEdit(QDate.currentDate()) # 傳入當前日期timeEdit = QDateTimeEdit(QTime.currentTime()) # 傳入當前日期dateTimeEdit1.setDisplayFormat('yyyy-MM-dd HH:mm:ss')dateTimeEdit2.setDisplayFormat('yyyy/MM/dd HH:mm:ss')dateEdit.setDisplayFormat('yyyy.MM.dd')timeEdit.setDisplayFormat('HH:mm:ss')vlayout.addWidget(dateTimeEdit1)vlayout.addWidget(dateTimeEdit2)vlayout.addWidget(dateEdit)vlayout.addWidget(timeEdit)self.setLayout(vlayout)self.resize(300, 90)self.setWindowTitle('設置不同風格的日期和時間')if __name__ == '__main__':app = QApplication(sys.argv)main = DateTimeEdit1()main.show()sys.exit(app.exec_())?課時58 日期和時間控件的高級操作
方法?? ?描述
setDisplayFormat?? ?設置日期的時間格式
?? ?yyyy:代表年份,用4為數表示
?? ?MM:代表月份,取值范圍01-12
?? ?dd:代表日,取值范圍01-31
?? ?HH:代表小時,取值范圍00-23
?? ?mm:代表分鐘,取值范圍00-59
?? ?ss:代表秒,取值范圍00-59
setMinimumDate()?? ?設置控件的最小日期
setMaximumDate()?? ?設置控件的最大日期
time()?? ?返回編輯的時間
date()?? ?返回編輯的日期
?
?課時59 創建和使用菜單
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 21:55 import sys from PyQt5.QtWidgets import *class Menu(QMainWindow):def __init__(self):super(Menu, self).__init__()bar = self.menuBar()file = bar.addMenu('文件') # 頂層菜單欄# 文件的子菜單(方法一:直接傳文本,內部會自動創建動作QAction)file.addAction('新建')# 法二:自己用動作來創建子菜單save = QAction('保存', self) # 必須加self,代表在當前窗口加QActionsave.setShortcut('Ctrl+S') # 快捷鍵file.addAction(save)quit = QAction('退出', self)file.addAction(quit)edit = bar.addMenu('Edit') # 頂層菜單edit.addAction('copy') # 子菜單edit.addAction('paste')save.triggered.connect(self.process)self.resize(400, 300)# 槽函數# 事件自動傳給槽函數的一個實參,在本例具體指的是菜單項是否被選中,是一個bool類型的值def process(self, a):print(self.sender().text()) # 注意這里是self.而不是a.if __name__ == '__main__':app = QApplication(sys.argv)main = Menu()main.show()sys.exit(app.exec_())課時60 創建和使用工具欄
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:06 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import *class Toolbar(QMainWindow):def __init__(self):super(Toolbar, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('工具欄例子')self.resize(300, 200)tb1 = self.addToolBar('File') # 一行工具欄'''工具欄默認按鈕:只顯示圖標,將文本作為懸停提示即鼠標懸停到圖標上之后,提示就是下面的第二個參數'''new = QAction(QIcon('./csdnlogo.jpg'), '新建', self) # self代表放在當前窗口上tb1.addAction(new)open = QAction(QIcon('./csdnlogo.jpg'), '打開', self)tb1.addAction(open)save = QAction(QIcon('./csdnlogo.jpg'), '保存', self)tb1.addAction(save)'''工具欄按鈕有3種顯示狀態1.只顯示圖標2.只顯示文本3.同時顯示文本和圖標'''# 設置工具欄按鈕顯示狀態:既顯示文本又顯示圖標tb1.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) # 設置文本在圖標的下方顯示,還有好多,按ctrl查看自己試試tb2 = self.addToolBar('File1')new1 = QAction(QIcon('./csdnlogo.jpg'), '新建', self)tb2.addAction(new1)tb2.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)tb1.actionTriggered.connect(self.toolbtnpressed)tb2.actionTriggered.connect(self.toolbtnpressed)def toolbtnpressed(self, a):print('按下的工具欄按鈕是', a.text())if __name__ == '__main__':app = QApplication(sys.argv)main = Toolbar()main.show()sys.exit(app.exec_())課時61 創建和使用狀態欄?
用于顯示狀態信息,一般在窗口的最下方顯示
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:16 import sys from PyQt5.QtWidgets import *class Statusbar(QMainWindow):def __init__(self):super(Statusbar, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('狀態欄演示')self.resize(300, 200)bar = self.menuBar() # 頂層菜單欄file = bar.addMenu('File') # 給菜單欄添加選項file.addAction('show') # 子菜單file.triggered.connect(self.processTrigger)self.setCentralWidget(QTextEdit()) # 多行輸入self.statusBar = QStatusBar()self.setStatusBar(self.statusBar)def processTrigger(self, q):if q.text() == 'show':# 在狀態欄上顯示信息self.statusBar.showMessage(q.text() + '菜單被點擊了', 5000) # 信息顯示5秒if __name__ == '__main__':app = QApplication(sys.argv)main = Statusbar()main.show()sys.exit(app.exec_())課時62 使用打印機
輸出都是以圖像形式輸出,輸出到打印機
鏈接打印機開始打印 這里就不測試打印機了!
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:21 import sys from PyQt5.QtWidgets import * from PyQt5 import QtGui, QtPrintSupportclass PrintSupport(QMainWindow):def __init__(self):super(PrintSupport, self).__init__()self.setGeometry(500, 200, 300, 300)self.btn = QPushButton('打印QTextEdit控件中的內容', self)self.btn.setGeometry(20, 20, 260, 30) # x,y,w,hself.editor = QTextEdit('默認文本', self)self.editor.setGeometry(20, 60, 260, 200)self.btn.clicked.connect(self.print)def print(self):# 打印機對象printer = QtPrintSupport.QPrinter()painter = QtGui.QPainter()# 將繪制的目標重定向到打印機上painter.begin(printer) # painter畫在begin的參數上,即printer上,若是self,則畫在當前窗口上# 獲得多行輸入控件editor的整個框架screen = self.editor.grab()# 從(10,10)開始將screen上的文字輸出到打印機上# drawPixmap:從圖像文件中提取 Pixmap 并將其顯示在指定位置painter.drawPixmap(10, 10, screen)painter.end()print('print')if __name__ == '__main__':app = QApplication(sys.argv)main = PrintSupport()main.show()sys.exit(app.exec_())課時63 顯示打印對話框
因為沒有打印機 但是可以輸出為pdf文檔?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:26 import sys from PyQt5.QtPrintSupport import QPrinter, QPageSetupDialog, QPrintDialog from PyQt5.QtWidgets import *class PrintDialog(QMainWindow):def __init__(self):super(PrintDialog, self).__init__()# 打印機對象self.printer = QPrinter()self.initUI()def initUI(self):self.setGeometry(300, 300, 500, 400)self.setWindowTitle('打印對話框')self.editor = QTextEdit(self)self.editor.setGeometry(20, 20, 300, 270)self.openButton = QPushButton('打開文件', self)self.openButton.move(350, 20)self.settingButton = QPushButton('打印設置', self)self.settingButton.move(350, 50)self.printButton = QPushButton('打印文檔', self)self.printButton.move(350, 80)self.openButton.clicked.connect(self.openFile)self.settingButton.clicked.connect(self.showSettingDialog)self.printButton.clicked.connect(self.showPrintDialog)# 打開文件def openFile(self):fname = QFileDialog.getOpenFileName(self, '打開文本文件', './')print(fname)print(fname[0])if fname[0]:with open(fname[0], 'r', encoding='utf-8', errors='ignore') as f:self.editor.setText(f.read())# 顯示打印設置對話框def showSettingDialog(self):printDialog = QPageSetupDialog(self.printer, self)printDialog.exec()# 顯示打印對話框def showPrintDialog(self):printdailog = QPrintDialog(self.printer, self)if QDialog.Accepted == printdailog.exec():# 將editor里的文字輸出到打印機中self.editor.print(self.printer)if __name__ == '__main__':app = QApplication(sys.argv)main = PrintDialog()main.show()sys.exit(app.exec_())?課時64 顯示二維表數據
顯示二維表數據(QTableVi ew控件)
數據源 Model
需要創建QTableView實例和一個數據源(Model) ,然后將兩者關聯,這個體系類似于MVC模式。
一個QTableView實例可以存放不同的數據源,一個數據源也可以對應不同的QTableView實例。
MVC: Model? Viewer? Controller 即將數據Model和前端視圖Viewer分離,通過控制器Controller 來控制。
MVC的目的是將后端的數據和前端頁面的耦合度降低。
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:36 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import *class TableView(QWidget):def __init__(self):super(TableView, self).__init__()self.setWindowTitle('QTableView表格視圖控件演示')self.resize(500, 300)self.model = QStandardItemModel(4, 3) # 二維表4行3列# 數據表的字段self.model.setHorizontalHeaderLabels(['id', 'name', 'age'])self.tableView = QTableView()# 關聯QTableView控件和Modelself.tableView.setModel(self.model)# 添加數據item11 = QStandardItem('1') # 一個QStandardItem就是一個單元格item12 = QStandardItem('Kobe')item13 = QStandardItem('24')self.model.setItem(0, 0, item11)self.model.setItem(0, 1, item12)self.model.setItem(0, 2, item13)# 可跳行添加數據item31 = QStandardItem('7')item32 = QStandardItem('Durant')item33 = QStandardItem('35')self.model.setItem(2, 0, item31)self.model.setItem(2, 1, item32)self.model.setItem(2, 2, item33)# 垂直布局layout = QVBoxLayout()layout.addWidget(self.tableView)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = TableView()main.show()sys.exit(app.exec_())?課時65 顯示列數據
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:46 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import QStringListModelclass ListView(QWidget):def __init__(self):super(ListView, self).__init__()self.setWindowTitle('ListView例子')self.resize(300, 270)layout = QVBoxLayout()listView = QListView()# 數據源listModel = QStringListModel()self.list = ['列表項1', '列表項2', '列表項3']listModel.setStringList(self.list)# 關聯視圖與數據源listView.setModel(listModel)listView.clicked.connect(self.clicked)layout.addWidget(listView)self.setLayout(layout)def clicked(self, item):QMessageBox.information(self, 'QListView', '您選擇了:' + self.list[item.row()])if __name__ == '__main__':app = QApplication(sys.argv)main = ListView()main.show()sys.exit(app.exec_())課時66? 擴展的列表控件
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:50 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import QStringListModel''' QListWidget是QListView的子類 添加了很多API,支持MVC模式,也支持非MVC模式,即數據直接添加到控件上 '''class ListWidget(QMainWindow):def __init__(self):super(ListWidget, self).__init__()self.setWindowTitle('ListWidget例子')self.resize(300, 270)# 直接添加的方式適合少量的數據的時候self.listWidget = QListWidget()# self.listWidget.resize(300,120)self.listWidget.addItem('item1')self.listWidget.addItem('item2')self.listWidget.addItem('item3')self.listWidget.addItem('item4')self.listWidget.addItem('item5')self.listWidget.itemClicked.connect(self.clicked)# 設置中心控件之后,會鋪滿整個屏幕,無需再單獨設置listWidget尺寸self.setCentralWidget(self.listWidget)def clicked(self, index):QMessageBox.information(self, 'ListWidget','您選擇了:' + self.listWidget.item(self.listWidget.row(index)).text())if __name__ == '__main__':app = QApplication(sys.argv)main = ListWidget()main.show()sys.exit(app.exec_())課時67 擴展的表格控件
每一個Cell (單元格) 是一個QTableWidgetItem
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 22:52 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import *''' QTableWidget是QTableView的子類 添加了很多API,支持MVC模式,也支持非MVC模式,即數據直接添加到控件上 '''class TableWidget(QWidget):def __init__(self):super(TableWidget, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('QTableWidget演示')self.resize(430, 230)layout = QHBoxLayout()tablewidget = QTableWidget()# 4行3列tablewidget.setRowCount(4)tablewidget.setColumnCount(3)tablewidget.setHorizontalHeaderLabels(['name', 'age', 'address'])nameItem = QTableWidgetItem('文龍')tablewidget.setItem(0, 0, nameItem)ageItem = QTableWidgetItem('23')tablewidget.setItem(0, 1, ageItem)addressItem = QTableWidgetItem('北京')tablewidget.setItem(0, 2, addressItem)# 禁止編輯tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers)# 整行選擇tablewidget.setSelectionBehavior(QAbstractItemView.SelectRows)# 調整列和行tablewidget.resizeColumnsToContents()tablewidget.resizeRowsToContents()# 隱藏表格頭tablewidget.horizontalHeader().setVisible(False) # 隱藏水平方向的表格頭# tablewidget.verticalHeader().setVisible(False) #隱藏垂直方向的表格頭# 設置表格頭內容tablewidget.setVerticalHeaderLabels(['a', 'b']) # 垂直方向表格頭前兩個設為a,b# 隱藏表格線tablewidget.setShowGrid(False)layout.addWidget(tablewidget)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = TableWidget()main.show()sys.exit(app.exec_())課時68 在單元格中放置控件
在單元格中放置控件
setItem:將文本放到單元格中
setCellWidget:將控件放到單元格中
setStyleSheet設置控件的樣式(QSS)
課時69 在表格中搜索Cell和行定位
在表格中快速定位到特定的行
1.數據的定位: findItems ,返回一個列表
2.如果找到了滿足條件的單元格,會定位到單元格所在的行: setSliderPosition(row)
課時70 設置單元格字體和顏色
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 23:19 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class CellFontAndColor(QWidget):def __init__(self):super(CellFontAndColor, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('設置單元格字體和顏色')self.resize(430, 230)layout = QHBoxLayout()tableWidget = QTableWidget()tableWidget.setRowCount(4)tableWidget.setColumnCount(3)tableWidget.setHorizontalHeaderLabels(['name', 'sex', 'weigh(kg)'])newItem = QTableWidgetItem('小明') # 單元格的數據項newItem.setFont(QFont('Times', 14, QFont.Black)) # 字體,字號,顏色newItem.setForeground(QBrush(QColor(255, 0, 0)))tableWidget.setItem(0, 0, newItem)newItem = QTableWidgetItem('女')newItem.setForeground(QBrush(QColor(255, 255, 0)))newItem.setBackground(QBrush(QColor(0, 0, 255))) # rgbtableWidget.setItem(0, 1, newItem)newItem = QTableWidgetItem('100')newItem.setFont(QFont('Times', 20, QFont.Black))newItem.setForeground(QBrush(QColor(0, 0, 255)))tableWidget.setItem(0, 2, newItem)layout.addWidget(tableWidget)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = CellFontAndColor()main.show()sys.exit(app.exec_())課時71 按表格的某一列排序
按列排序
1.按哪一列排序
2.排序類型:升序或降序
sortItems( columnIndex,orderType)
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 23:23 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class CellFontAndColor(QWidget):def __init__(self):super(CellFontAndColor, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('設置單元格字體和顏色')self.resize(540, 230)layout = QHBoxLayout()self.tableWidget = QTableWidget() # 表格對象self.tableWidget.setRowCount(4)self.tableWidget.setColumnCount(3)self.tableWidget.setHorizontalHeaderLabels(['name', 'sex', 'weigh(kg)'])# 添加數據newItem = QTableWidgetItem('張三')self.tableWidget.setItem(0, 0, newItem)newItem = QTableWidgetItem('男')self.tableWidget.setItem(0, 1, newItem)newItem = QTableWidgetItem('165')self.tableWidget.setItem(0, 2, newItem)newItem = QTableWidgetItem('李四')self.tableWidget.setItem(1, 0, newItem)newItem = QTableWidgetItem('女')self.tableWidget.setItem(1, 1, newItem)newItem = QTableWidgetItem('120')self.tableWidget.setItem(1, 2, newItem)newItem = QTableWidgetItem('王五')self.tableWidget.setItem(2, 0, newItem)newItem = QTableWidgetItem('男')self.tableWidget.setItem(2, 1, newItem)newItem = QTableWidgetItem('130')self.tableWidget.setItem(2, 2, newItem)# 點擊按鈕排序self.btn = QPushButton('升序')self.btn.clicked.connect(self.order)# 常量self.orderType = Qt.DescendingOrderlayout.addWidget(self.tableWidget)layout.addWidget(self.btn)self.setLayout(layout)# 升降序來回切換def order(self):if self.orderType == Qt.DescendingOrder:self.orderType = Qt.AscendingOrderself.btn.setText('降序') # 重命名按鈕名,setText設置按鈕顯示文本else:self.orderType = Qt.DescendingOrderself.btn.setText('升序')# print(Qt.DescendingOrder)# print(self.orderType)self.tableWidget.sortItems(2, self.orderType) # 按照第三列的數據項排序# self.tableWidget.sortItems(2, Qt.DescendingOrder)if __name__ == '__main__':app = QApplication(sys.argv)main = CellFontAndColor()main.show()sys.exit(app.exec_())課時71 設置單元格的文本對齊方式
setTextAlignment
Qt. AlignRight 右對齊 ? ???? Qt.AlignBottom底端顯示
課時73 合并單元格
setSpan(row, col ,要合并的行數,要合并的列數)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 23:31 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class MergeCell(QWidget):def __init__(self):super(MergeCell, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('合并單元格')self.resize(430, 230)layout = QHBoxLayout()# 表格對象tableWidget = QTableWidget()# 四行三列tableWidget.setRowCount(4)tableWidget.setColumnCount(3)# 設置表格字段tableWidget.setHorizontalHeaderLabels(['姓名', '性別', '體重(kg)'])newItem = QTableWidgetItem('小明')tableWidget.setItem(0, 0, newItem)# setSpan(row, col, 要合并的行數,要合并的列數)tableWidget.setSpan(0, 0, 3, 1)newItem = QTableWidgetItem('男')tableWidget.setItem(0, 1, newItem)tableWidget.setSpan(0, 1, 2, 1)newItem = QTableWidgetItem('190')tableWidget.setItem(0, 2, newItem)newItem = QTableWidgetItem('test')tableWidget.setItem(2, 1, newItem)tableWidget.setSpan(2, 1, 1, 2)layout.addWidget(tableWidget)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = MergeCell()main.show()sys.exit(app.exec_())課時74 設置單元格的尺寸
單元格大小可手動拖動改變大小,當字體設置很大時,運行之后顯示的單元格大小可能不足夠顯示出文字,只會顯示三個點省略,這時就要設置單元格尺寸了。
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 23:34 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class MergeCell(QWidget):def __init__(self):super(MergeCell, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('合并單元格')self.resize(600, 400)layout = QHBoxLayout()# 表格對象tableWidget = QTableWidget()# 四行三列tableWidget.setRowCount(4)tableWidget.setColumnCount(3)# 設置表格字段tableWidget.setHorizontalHeaderLabels(['姓名', '性別', '體重(kg)'])newItem = QTableWidgetItem('小明') # 單元格的數據項newItem.setFont(QFont('Times', 40, QFont.Black)) # 字體,字號,顏色newItem.setForeground(QBrush(QColor(255, 0, 0)))tableWidget.setItem(0, 0, newItem)newItem = QTableWidgetItem('女')newItem.setForeground(QBrush(QColor(255, 255, 0)))newItem.setBackground(QBrush(QColor(0, 0, 255))) # rgbtableWidget.setItem(0, 1, newItem)newItem = QTableWidgetItem('100')newItem.setFont(QFont('Times', 60, QFont.Black))newItem.setForeground(QBrush(QColor(0, 0, 255)))tableWidget.setItem(0, 2, newItem)tableWidget.setRowHeight(0, 120) # 設置第一行高度,三個數據項都在第一行上,第一行的單元格高度都變為120tableWidget.setColumnWidth(0, 150) # 設置第一列寬度tableWidget.setRowHeight(2, 200) # 設置第三行高度,注意這是第三行,而不是第三個單元格的高度!!!!!tableWidget.setColumnWidth(2, 180) # 設置第二列寬度layout.addWidget(tableWidget)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = MergeCell()main.show()sys.exit(app.exec_())課時75 在單元格中實現圖文混排的效果
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 23:38 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class MergeCell(QWidget):def __init__(self):super(MergeCell, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('合并單元格')self.resize(600, 250)layout = QHBoxLayout()# 表格對象tableWidget = QTableWidget()# 四行四列tableWidget.setRowCount(4)tableWidget.setColumnCount(4)# 設置表格字段tableWidget.setHorizontalHeaderLabels(['姓名', '性別', '體重(kg)'])newItem = QTableWidgetItem('李寧')tableWidget.setItem(0, 0, newItem)newItem = QTableWidgetItem('男')tableWidget.setItem(0, 1, newItem)newItem = QTableWidgetItem('160')tableWidget.setItem(0, 2, newItem)newItem = QTableWidgetItem(QIcon('./and.png'), '背包')tableWidget.setItem(0, 3, newItem)layout.addWidget(tableWidget)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = MergeCell()main.show()sys.exit(app.exec_())課時76 改變單元格中圖片的尺寸
setIconSize(QSize(width, height))
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/23 23:44 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class CellImageSize(QWidget):def __init__(self):super(CellImageSize, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('改變單元格中圖片尺寸')self.resize(1000, 900)layout = QHBoxLayout()# 表格對象tableWidget = QTableWidget()# 設置單元格中圖片大小tableWidget.setIconSize(QSize(300, 200))# 五行三列tableWidget.setRowCount(5)tableWidget.setColumnCount(3)# 設置表格字段tableWidget.setHorizontalHeaderLabels(['image1', 'image2', 'image3'])# 讓列的寬度和圖片的寬度相同for i in range(3):tableWidget.setColumnWidth(i, 300)# 讓行的高度和圖片的高度相同for i in range(5):tableWidget.setRowHeight(i, 200)for k in range(15):i = k / 3 # 行j = k % 3 # 列item = QTableWidgetItem()item.setIcon(QIcon('./csdn/csdn%d.png' % (k + 1)))tableWidget.setItem(i, j, item)layout.addWidget(tableWidget)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = CellImageSize()main.show()sys.exit(app.exec_())課時77 在表格中顯示上下文菜單
1.如何彈出菜單
2.如果在滿足條件的情況下彈出菜單
QMenu. exec_()
?課時78 樹控件(QTreeWidget)的基本用法
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:00 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class BasicTreeWidget(QMainWindow):def __init__(self, parent=None):super(BasicTreeWidget, self).__init__(parent)self.setWindowTitle('樹控件(QTreeWidget)的基本用法')self.resize(500, 300)# 樹self.tree = QTreeWidget()# 為樹控件指定列數self.tree.setColumnCount(2)# 指定列標簽self.tree.setHeaderLabels(['Key', 'Value'])# 根節點root = QTreeWidgetItem(self.tree)root.setText(0, '根節點') # 0代表第一列,即Key列root.setIcon(0, QIcon('./and.png')) # 為節點設置圖標self.tree.setColumnWidth(0, 200) # 第一列列寬設為200# 添加子節點1child1 = QTreeWidgetItem(root)child1.setText(0, '子節點1') # 第一列Key為 子節點1child1.setText(1, '子節點1的數據') # 第二列Value為 子節點1的數據child1.setIcon(0, QIcon('./and.png'))# 設置子節點1開啟復選框狀態child1.setCheckState(0, Qt.Checked)# 添加子節點2child2 = QTreeWidgetItem(root)child2.setText(0, '子節點2')child2.setIcon(0, QIcon('./and.png'))# 為child2添加一個子節點child3 = QTreeWidgetItem(child2)child3.setText(0, '子節點2-1')child3.setText(1, '新的值')child3.setIcon(0, QIcon('./and.png'))# 默認所有節點都處于展開狀態self.tree.expandAll()# 將樹控件設為中心控件,即樹控件會自動鋪滿整個屏幕self.setCentralWidget(self.tree)if __name__ == '__main__':app = QApplication(sys.argv)main = BasicTreeWidget()main.show()sys.exit(app.exec_())課時79 為樹節點添加響應事件
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:08 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class TreeEvent(QMainWindow):def __init__(self, parent=None):super(TreeEvent, self).__init__(parent)self.setWindowTitle('為樹添加響應事件')self.resize(400, 300)# 樹self.tree = QTreeWidget()# 為樹控件指定列數self.tree.setColumnCount(2)# 指定列標簽self.tree.setHeaderLabels(['Key', 'Value'])# 根節點root = QTreeWidgetItem(self.tree)root.setText(0, 'root') # 0代表第一列,即Key列,值為rootroot.setText(1, '0')# 添加子節點child1child1 = QTreeWidgetItem(root)child1.setText(0, 'child1')child1.setText(1, '1')# 添加子節點child2child2 = QTreeWidgetItem(root)child2.setText(0, 'child2')child2.setText(1, '2')# 為child2添加一個子節點child3child3 = QTreeWidgetItem(child2)child3.setText(0, 'child3')child3.setText(1, '3')# 信號和槽self.tree.clicked.connect(self.onTreeClicked)# 將樹控件設為中心控件,即樹控件會自動鋪滿整個屏幕self.setCentralWidget(self.tree)def onTreeClicked(self, index): # index是被點擊節點的索引item = self.tree.currentItem() # 獲得當前單擊項print('當前處于第%d行' % index.row()) # 輸出當前行(自己父節點的第幾個值)print('key=%s,value=%s' % (item.text(0), item.text(1)))print()if __name__ == '__main__':app = QApplication(sys.argv)main = TreeEvent()main.show()sys.exit(app.exec_())?課時 80 增加,修改和刪除樹控件的節點
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:14 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class ModifyTree(QWidget):def __init__(self, parent=None):super(ModifyTree, self).__init__(parent)self.setWindowTitle('增加修改和刪除樹控件中的節點')self.resize(400, 300)operatorLayout = QHBoxLayout() # 水平布局addBtn = QPushButton('添加節點')updateBtn = QPushButton('修改節點')deleteBtn = QPushButton('刪除節點')operatorLayout.addWidget(addBtn)operatorLayout.addWidget(updateBtn)operatorLayout.addWidget(deleteBtn)addBtn.clicked.connect(self.addNode)updateBtn.clicked.connect(self.updateNode)deleteBtn.clicked.connect(self.deleteNode)# 樹self.tree = QTreeWidget()# 為樹控件指定列數self.tree.setColumnCount(2)# 指定列標簽self.tree.setHeaderLabels(['Key', 'Value'])# 根節點root = QTreeWidgetItem(self.tree)root.setText(0, 'root') # 0代表第一列,即Key列,值為rootroot.setText(1, '0')# 添加子節點child1child1 = QTreeWidgetItem(root)child1.setText(0, 'child1')child1.setText(1, '1')# 添加子節點child2child2 = QTreeWidgetItem(root)child2.setText(0, 'child2')child2.setText(1, '2')# 為child2添加一個子節點child3child3 = QTreeWidgetItem(child2)child3.setText(0, 'child3')child3.setText(1, '3')# 信號和槽self.tree.clicked.connect(self.onTreeClicked)mainLayout = QVBoxLayout(self)mainLayout.addLayout(operatorLayout)mainLayout.addWidget(self.tree)self.setLayout(mainLayout)def onTreeClicked(self, index): # index是被點擊節點的索引item = self.tree.currentItem() # 獲得當前單擊項print('當前處于第%d行' % index.row()) # 輸出當前行(自己父節點的第幾個值)print('key=%s,value=%s' % (item.text(0), item.text(1)))print()def addNode(self):print('添加節點')item = self.tree.currentItem() # 獲得當前節點print('當前節點是:', item)node = QTreeWidgetItem(item)node.setText(0, '新節點')node.setText(1, '新值')def updateNode(self):print('修改節點')item = self.tree.currentItem()item.setText(0, '修改節點')item.setText(1, '值已經被修改')def deleteNode(self):print('刪除節點')# 防止item是root時,root無父結點報錯,要使用下面的寫法rootFather = self.tree.invisibleRootItem() # 獲得根節點root的不可見的父節點for item in self.tree.selectedItems():# 父節點不為空(item.parent() or rootFather).removeChild(item)if __name__ == '__main__':app = QApplication(sys.argv)main = ModifyTree()main.show()sys.exit(app.exec_())課時81 QTreeView控件與系統定制模式
一般復雜的樹控件用QTreeView來寫
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:21 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *if __name__ == '__main__':app = QApplication(sys.argv)# 顯示目錄結構的模型model = QDirModel()tree = QTreeView()tree.setModel(model)tree.setWindowTitle('QTreeView')tree.resize(600, 400)tree.show()sys.exit(app.exec_())課時82 選項卡控件(QTabWidget)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:25 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class TabWidget(QTabWidget): # 直接一整個屏幕就是一個選項卡窗口def __init__(self, parent=None):super(TabWidget, self).__init__(parent)self.setWindowTitle('選項卡控件:QTabWidget')self.resize(400, 200)# 創建用于顯示控件的窗口self.tab1 = QWidget()self.tab2 = QWidget()self.tab3 = QWidget()# 將窗口和選項卡綁定self.addTab(self.tab1, '選項卡1')self.addTab(self.tab2, '選項卡2')self.addTab(self.tab3, '選項卡3')self.tab1UI()self.tab2UI()self.tab3UI()def tab1UI(self):# 表單布局layout = QFormLayout()layout.addRow('姓名', QLineEdit())layout.addRow('地址', QLineEdit())# 將第一個選項卡窗口重命名self.setTabText(0, '聯系方式')self.tab1.setLayout(layout) # 別忘了tab1就是一個窗口def tab2UI(self):layout = QFormLayout()sex = QHBoxLayout() # 水平布局,橫向排列# 單選框sex.addWidget(QRadioButton('男'))sex.addWidget(QRadioButton('女'))layout.addRow(QLabel('性別'), sex)layout.addRow('生日', QLineEdit())self.setTabText(1, '個人詳細信息')self.tab2.setLayout(layout)def tab3UI(self):layout = QHBoxLayout()layout.addWidget(QLabel('科目'))# 復選框layout.addWidget(QCheckBox('物理'))layout.addWidget(QCheckBox('高數'))self.setTabText(2, '教育程度')self.tab3.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = TabWidget()main.show()sys.exit(app.exec_())?課時83 堆棧窗口控件(QStackedWidget)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:30 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class StackedExample(QWidget): # 直接一整個屏幕就是一個選項卡窗口def __init__(self, parent=None):super(StackedExample, self).__init__(parent)self.setWindowTitle('堆棧窗口控件:QStackedWidget')# self.resize(400,200)self.setGeometry(800, 450, 10, 10)# 列表控件self.list = QListWidget()self.list.insertItem(0, '聯系方式')self.list.insertItem(1, '個人信息')self.list.insertItem(2, '教育程度')self.stack1 = QWidget()self.stack2 = QWidget()self.stack3 = QWidget()self.tab1UI()self.tab2UI()self.tab3UI()# 堆棧窗口控件對象self.stack = QStackedWidget()self.stack.addWidget(self.stack1)self.stack.addWidget(self.stack2)self.stack.addWidget(self.stack3)self.list.currentRowChanged.connect(self.display)hbox = QHBoxLayout()hbox.addWidget(self.list)hbox.addWidget(self.stack)self.setLayout(hbox)def tab1UI(self):# 表單布局layout = QFormLayout()layout.addRow('姓名', QLineEdit())layout.addRow('地址', QLineEdit())self.stack1.setLayout(layout) # 別忘了tab1就是一個窗口def tab2UI(self):layout = QFormLayout()sex = QHBoxLayout() # 水平布局,橫向排列# 單選框sex.addWidget(QRadioButton('男'))sex.addWidget(QRadioButton('女'))layout.addRow(QLabel('性別'), sex)layout.addRow('生日', QLineEdit())self.stack2.setLayout(layout)def tab3UI(self):layout = QHBoxLayout()layout.addWidget(QLabel('科目'))# 復選框layout.addWidget(QCheckBox('物理'))layout.addWidget(QCheckBox('高數'))self.stack3.setLayout(layout)def display(self, index):# 通過索引來切換頁面self.stack.setCurrentIndex(index)if __name__ == '__main__':app = QApplication(sys.argv)main = StackedExample()main.show()sys.exit(app.exec_())課時84 停靠控件(QDockWidget)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:35 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class DockDemo(QMainWindow): # 直接一整個屏幕就是一個選項卡窗口def __init__(self, parent=None):super(DockDemo, self).__init__(parent)self.setWindowTitle('停靠控件(QDockWidget)')self.setGeometry(800, 450, 500, 500) # x,y,w,h# self.resize(400, 200)layout = QHBoxLayout()# 停靠控件對象self.items = QDockWidget('Dockable', self)# 列表控件self.listWidget = QListWidget()self.listWidget.addItem('item1')self.listWidget.addItem('item2')self.listWidget.addItem('item3')# 將列表放到停靠控件上self.items.setWidget(self.listWidget)self.setCentralWidget(QLineEdit('單行輸入'))# 設置一開始就是懸浮狀態self.items.setFloating(True)# 在窗口上設置停靠控件,且懸浮在右側self.addDockWidget(Qt.RightDockWidgetArea, self.items)if __name__ == '__main__':app = QApplication(sys.argv)main = DockDemo()main.show()sys.exit(app.exec_())課時85 容納多文檔的窗口
相當于窗口的容器,里面可以有很多子窗口,但子窗口只能在這里面移動。
需要的類:
容納多文檔:QMdiArea
子窗口:?????? QMdiSubWindow
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:44 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class MultiWindows(QMainWindow): # 直接一整個屏幕就是一個選項卡窗口count = 0 # 記錄當前有多少個菜單項def __init__(self, parent=None):super(MultiWindows, self).__init__(parent)self.setWindowTitle('容納多文檔的窗口')self.setGeometry(800, 450, 500, 400) # x,y,w,h# 容納多文檔容器對象self.mdi = QMdiArea()bar = self.menuBar()file = bar.addMenu('File')file.addAction('New')file.addAction('cascade') # 重疊file.addAction('Tiled') # 平鋪file.triggered.connect(self.windowAction)self.setCentralWidget(self.mdi)def windowAction(self, q): # q是當前的單擊菜單項,通過按鈕名來進行不同的操作if q.text() == 'New':self.count = self.count + 1# 子窗口對象sub = QMdiSubWindow()sub.setWidget(QTextEdit())sub.setWindowTitle('子窗口' + str(self.count))self.mdi.addSubWindow(sub)sub.show()# 下面兩個是對mdi中已有的窗口排布進行操作,而不是生成窗口elif q.text() == 'cascade':self.mdi.cascadeSubWindows()elif q.text() == 'Tiled':self.mdi.tileSubWindows()if __name__ == '__main__':app = QApplication(sys.argv)main = MultiWindows()main.show()sys.exit(app.exec_())課時86 滾動條控件(QScrollBar)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:52 from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import * import sysclass ScrollBar(QWidget):def __init__(self):super(ScrollBar, self).__init__()self.initUI()def initUI(self):self.setWindowTitle('滾動條控件演示')self.setGeometry(400, 300, 300, 500)# 水平布局hbox = QHBoxLayout()# 定義控件self.label = QLabel('拖動滾動條去改變文字顏色')self.scrollbar1 = QScrollBar() # 滾動條self.scrollbar1.setMaximum(255) # 滾動條最大值# 信號與槽self.scrollbar1.sliderMoved.connect(self.sliderMoved)self.scrollbar2 = QScrollBar()self.scrollbar2.setMaximum(255)self.scrollbar2.sliderMoved.connect(self.sliderMoved)self.scrollbar3 = QScrollBar()self.scrollbar3.setMaximum(255)self.scrollbar3.sliderMoved.connect(self.sliderMoved)self.scrollbar4 = QScrollBar()self.scrollbar4.setMaximum(255)self.scrollbar4.sliderMoved.connect(self.sliderMoved1)# 向布局中添加控件hbox.addWidget(self.label)hbox.addWidget(self.scrollbar1)hbox.addWidget(self.scrollbar2)hbox.addWidget(self.scrollbar3)hbox.addWidget(self.scrollbar4)self.setLayout(hbox)# 獲得標簽的縱坐標self.y = self.label.pos().y()def sliderMoved(self):print(self.scrollbar1.value(), self.scrollbar2.value(), self.scrollbar3.value())# 調色版palette = QPalette()# 最后一個參數是透明度c = QColor(self.scrollbar1.value(), self.scrollbar2.value(), self.scrollbar3.value(), 255)# 參數一:QPalette.Foreground設置前景色,即標簽的顏色 參數2:顏色palette.setColor(QPalette.Foreground, c)self.label.setPalette(palette)def sliderMoved1(self):# 向下移動標簽self.label.move(self.label.x(), self.y + self.scrollbar4.value())if __name__ == '__main__':app = QApplication(sys.argv)main = ScrollBar()main.show()sys.exit(app.exec_())課時87 動態顯示當前時間(QTimer)
QTimer定時器,適用于多任務,即每隔一定的時間會調用一次
QThread:完成單個任務可以使用這個
多線程:用于同時完成多個任務
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 10:57 import sys from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import *class showTime(QWidget):def __init__(self, parent=None):super(showTime, self).__init__(parent)self.setWindowTitle('動態顯示當前時間')self.label = QLabel('顯示當前時間')self.startBtn = QPushButton('開始')self.endBtn = QPushButton('結束')# 柵格布局layout = QGridLayout()# 計時器對象self.timer = QTimer()self.timer.timeout.connect(self.showTime)layout.addWidget(self.label, 0, 0, 1, 2) # 占一行兩列layout.addWidget(self.startBtn, 1, 0)layout.addWidget(self.endBtn, 1, 1)self.startBtn.clicked.connect(self.startTimer)self.endBtn.clicked.connect(self.endTimer)self.setLayout(layout)def showTime(self):time = QDateTime.currentDateTime()# dddd是星期幾timeDispaly = time.toString('yyyy-MM-dd hh:mm:ss dddd')# 將標簽設置成當前時間self.label.setText(timeDispaly)def startTimer(self):# 參數是時間間隔,1000毫秒self.timer.start(1000)self.startBtn.setEnabled(False) # 不能按self.endBtn.setEnabled(True) # 可以按def endTimer(self):# 停止計時self.timer.stop()self.startBtn.setEnabled(True)self.endBtn.setEnabled(False)if __name__ == '__main__':app = QApplication(sys.argv)main = showTime()main.show()sys.exit(app.exec_())?課時88 讓窗口定時關閉
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 11:05 import sys from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import *if __name__ == '__main__':app = QApplication(sys.argv)label = QLabel('<font color=red size=140><b>Hello World,窗口在5秒后自動關閉!</b></font>')# setWindowFlag設置窗口屬性:啟動畫面,無框架label.setWindowFlags(Qt.SplashScreen | Qt.FramelessWindowHint)label.show()# 5秒之后退出整個程序QTimer.singleShot(5000, app.quit)sys.exit(app.exec_())課時89 使用線程類(QThread)編寫計數器
用到自定義信號,之前用到的信號都是系統已經定義好的,這里需要自己再定義一個。
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 11:09 import sys from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import *# 全局變量,當前計數從0開始 sec = 0class WorkThread(QThread): # 繼承QThread類# 每隔一秒發送一次信號,pyqtSignal()用來定義信號的timer = pyqtSignal()# 計數完成后發送一次信號end = pyqtSignal()def run(self):while True:self.sleep(1) # 休眠一秒if sec == 5:self.end.emit() # 發送end信號,emit()用來發送信號breakself.timer.emit() # 發送timer信號class Counter(QWidget):def __init__(self, parent=None):super(Counter, self).__init__(parent)self.setWindowTitle('使用線程類(QThread)編寫計數器')self.resize(300, 120)layout = QVBoxLayout() # 垂直布局# 數碼管self.lcdNumber = QLCDNumber()layout.addWidget(self.lcdNumber)btn = QPushButton('開始計數')layout.addWidget(btn)self.workThread = WorkThread()self.workThread.timer.connect(self.countTime)self.workThread.end.connect(self.end)btn.clicked.connect(self.work)self.setLayout(layout)def countTime(self):global sec # 聲明一下是全局變量sec += 1self.lcdNumber.display(sec)def end(self):QMessageBox.information(self, '消息', '計數結束', QMessageBox.Ok)def work(self):self.workThread.start()if __name__ == '__main__':app = QApplication(sys.argv)main = Counter()main.show()sys.exit(app.exec_())課時90 用Web瀏覽器控件(QWebEngineView)顯示網頁
PyQt5和web的交互技術
同時使用Python和web開發程序,混合開發
Python+JavaScript+Html+CSS
運行報錯問題:
from PyQt5.QtWebEngineWidgets import? *
ImportError: DLL load failed while importing QtWebEngineWidgets: 找不到指定的模塊。
參考:(已解決)from PyQt5.QtWebEngineWidgets import *:ImportError: DLL load failed / 找不到指定的模塊_嗨嗨皮皮大bobo的博客-CSDN博客
CSDN和百度了很多
我的解決方案是:將python3.9版本改為3.6版本 想著還是python過高的原因
??右鍵運行
課時91 裝載本地Web頁面
?test.html Html文件
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>測試頁面</title> </head> <body><h1>Hello PyQt5</h1><h2>Hello PyQt5</h2><h3>Hello PyQt5</h3><h4>Hello PyQt5</h4> </body> </html>localHTML Py文件
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 12:52 import sys import os from PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class localHTML(QMainWindow):def __init__(self, parent=None):super(localHTML, self).__init__(parent)self.setWindowTitle('裝載本地Web頁面')self.setGeometry(5, 30, 1355, 730)# os.getcwd()是獲取當前路徑print(os.getcwd())url = os.getcwd() + '/test.html'self.browser = QWebEngineView()# QUrl.fromLocalFile(url)self.browser.load(QUrl.fromLocalFile(url))self.setCentralWidget(self.browser)if __name__ == '__main__':app = QApplication(sys.argv)main = localHTML()main.show()sys.exit(app.exec_())課時91 顯示嵌入Web頁面
將web頁面的代碼硬編碼到代碼里面,然后顯示
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 12:58 import sys import os from PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import *class innerHTML(QMainWindow):def __init__(self, parent=None):super(innerHTML, self).__init__(parent)self.setWindowTitle('裝載本地Web頁面')self.setGeometry(5, 30, 1355, 730)self.browser = QWebEngineView()# 直接嵌入頁面源碼self.browser.setHtml(''' <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>測試頁面</title> </head> <body><h1>Hello PyQt5</h1><h2>Hello PyQt5</h2><h3>Hello PyQt5</h3><h4>Hello PyQt5</h4> </body> </html>''')self.setCentralWidget(self.browser)if __name__ == '__main__':app = QApplication(sys.argv)main = innerHTML()main.show()sys.exit(app.exec_())?課時93 PyQt5調用JavaScript代碼,并返回值
PyQt5和JavaScript交互
什么叫交互
PyQt5 <-> JavaScript
?PyQt5調用JavaScript的函數,然后JavaScript的函數返回了值給PyQt5。
運行結果:功能:分別輸入First name和Last name,然后 PyQt5調用JavaScript的函數,返回全名。
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 13:14 from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtWebEngineWidgets import * import sys import osclass WebEngineView(QWidget):"""PyQt5調用JavaScript代碼PyQt5和JavaScrip交互什么叫交互PyQt5<->JavaScript 即互相調用內部的函數"""def __init__(self):super(WebEngineView, self).__init__()self.setWindowTitle('PyQt5調用JavaScript')self.setGeometry(5, 30, 1355, 730)self.layout = QVBoxLayout()self.setLayout(self.layout)self.browser = QWebEngineView()url = os.getcwd() + '/pyqt5calljs.html'self.browser.load(QUrl.fromLocalFile(url))self.layout.addWidget(self.browser)button = QPushButton('設置全名')button.clicked.connect(self.fullname)self.layout.addWidget(button)# 接受js返回值 即pyqt5calljs.html文件中的fullname函數返回值def js_callback(self, result):print(result)def fullname(self):self.value = 'hello world'self.browser.page().runJavaScript('fullname("' + self.value + '");', self.js_callback)if __name__ == '__main__':app = QApplication(sys.argv)main = WebEngineView()print(main.__doc__)main.show()sys.exit(app.exec_())課時94 JavaScript調用PyhtonAPI計算階乘
階乘小知識:
階乘是基斯頓·卡曼(Christian Kramp,1760~1826)于 1808 年發明的運算符號,是數學術語。
一個正整數的階乘(factorial)是所有小于及等于該數的正整數的積,并且0的階乘為1。自然數n的階乘寫作n!。1808年,基斯頓·卡曼引進這個表示法。
階乘指從1乘以2乘以3乘以4一直乘到所要求的數。
例如所要求的數是4,則階乘式是1×2×3×4,得到的積是24,24就是4的階乘。 例如所要求的數是6,則階乘式是1×2×3×……×6,得到的積是720,720就是6的階乘。例如所要求的數是n,則階乘式是1×2×3×……×n,設得到的積是x,x就是n的階乘。
將Python的一個對象映射到JavaScript中
將槽函數映射到JavaScript中
總共有四個文件:
文件1????????pyqt5calljs.html
文件2????????js調用py文件(js_call_py.html)
文件3????????階乘功能類(factorial.py)
文件4????????調用類(PyFactorial.py)
?對應的pyqt5calljs.html文件如下:qwebchannel.js?
/**************************************************************************** ** ** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2014 Klar?lvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com> ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the QtWebChannel module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see http://www.qt.io/terms-conditions. For further ** information use the contact form at http://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** As a special exception, The Qt Company gives you certain additional ** rights. These rights are described in The Qt Company LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/"use strict";var QWebChannelMessageTypes = {signal: 1,propertyUpdate: 2,init: 3,idle: 4,debug: 5,invokeMethod: 6,connectToSignal: 7,disconnectFromSignal: 8,setProperty: 9,response: 10, };var QWebChannel = function(transport, initCallback) {if (typeof transport !== "object" || typeof transport.send !== "function") {console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." +" Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send));return;}var channel = this;this.transport = transport;this.send = function(data){if (typeof(data) !== "string") {data = JSON.stringify(data);}channel.transport.send(data);}this.transport.onmessage = function(message){var data = message.data;if (typeof data === "string") {data = JSON.parse(data);}switch (data.type) {case QWebChannelMessageTypes.signal:channel.handleSignal(data);break;case QWebChannelMessageTypes.response:channel.handleResponse(data);break;case QWebChannelMessageTypes.propertyUpdate:channel.handlePropertyUpdate(data);break;default:console.error("invalid message received:", message.data);break;}}this.execCallbacks = {};this.execId = 0;this.exec = function(data, callback){if (!callback) {// if no callback is given, send directlychannel.send(data);return;}if (channel.execId === Number.MAX_VALUE) {// wrapchannel.execId = Number.MIN_VALUE;}if (data.hasOwnProperty("id")) {console.error("Cannot exec message with property id: " + JSON.stringify(data));return;}data.id = channel.execId++;channel.execCallbacks[data.id] = callback;channel.send(data);};this.objects = {};this.handleSignal = function(message){var object = channel.objects[message.object];if (object) {object.signalEmitted(message.signal, message.args);} else {console.warn("Unhandled signal: " + message.object + "::" + message.signal);}}this.handleResponse = function(message){if (!message.hasOwnProperty("id")) {console.error("Invalid response message received: ", JSON.stringify(message));return;}channel.execCallbacks[message.id](message.data);delete channel.execCallbacks[message.id];}this.handlePropertyUpdate = function(message){for (var i in message.data) {var data = message.data[i];var object = channel.objects[data.object];if (object) {object.propertyUpdate(data.signals, data.properties);} else {console.warn("Unhandled property update: " + data.object + "::" + data.signal);}}channel.exec({type: QWebChannelMessageTypes.idle});}this.debug = function(message){channel.send({type: QWebChannelMessageTypes.debug, data: message});};channel.exec({type: QWebChannelMessageTypes.init}, function(data) {for (var objectName in data) {var object = new QObject(objectName, data[objectName], channel);}// now unwrap properties, which might reference other registered objectsfor (var objectName in channel.objects) {channel.objects[objectName].unwrapProperties();}if (initCallback) {initCallback(channel);}channel.exec({type: QWebChannelMessageTypes.idle});}); };function QObject(name, data, webChannel) {this.__id__ = name;webChannel.objects[name] = this;// List of callbacks that get invoked upon signal emissionthis.__objectSignals__ = {};// Cache of all properties, updated when a notify signal is emittedthis.__propertyCache__ = {};var object = this;// ----------------------------------------------------------------------this.unwrapQObject = function(response){if (response instanceof Array) {// support list of objectsvar ret = new Array(response.length);for (var i = 0; i < response.length; ++i) {ret[i] = object.unwrapQObject(response[i]);}return ret;}if (!response|| !response["__QObject*__"]|| response.id === undefined) {return response;}var objectId = response.id;if (webChannel.objects[objectId])return webChannel.objects[objectId];if (!response.data) {console.error("Cannot unwrap unknown QObject " + objectId + " without data.");return;}var qObject = new QObject( objectId, response.data, webChannel );qObject.destroyed.connect(function() {if (webChannel.objects[objectId] === qObject) {delete webChannel.objects[objectId];// reset the now deleted QObject to an empty {} object// just assigning {} though would not have the desired effect, but the// below also ensures all external references will see the empty map// NOTE: this detour is necessary to workaround QTBUG-40021var propertyNames = [];for (var propertyName in qObject) {propertyNames.push(propertyName);}for (var idx in propertyNames) {delete qObject[propertyNames[idx]];}}});// here we are already initialized, and thus must directly unwrap the propertiesqObject.unwrapProperties();return qObject;}this.unwrapProperties = function(){for (var propertyIdx in object.__propertyCache__) {object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]);}}function addSignal(signalData, isPropertyNotifySignal){var signalName = signalData[0];var signalIndex = signalData[1];object[signalName] = {connect: function(callback) {if (typeof(callback) !== "function") {console.error("Bad callback given to connect to signal " + signalName);return;}object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];object.__objectSignals__[signalIndex].push(callback);if (!isPropertyNotifySignal && signalName !== "destroyed") {// only required for "pure" signals, handled separately for properties in propertyUpdate// also note that we always get notified about the destroyed signalwebChannel.exec({type: QWebChannelMessageTypes.connectToSignal,object: object.__id__,signal: signalIndex});}},disconnect: function(callback) {if (typeof(callback) !== "function") {console.error("Bad callback given to disconnect from signal " + signalName);return;}object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];var idx = object.__objectSignals__[signalIndex].indexOf(callback);if (idx === -1) {console.error("Cannot find connection of signal " + signalName + " to " + callback.name);return;}object.__objectSignals__[signalIndex].splice(idx, 1);if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) {// only required for "pure" signals, handled separately for properties in propertyUpdatewebChannel.exec({type: QWebChannelMessageTypes.disconnectFromSignal,object: object.__id__,signal: signalIndex});}}};}/*** Invokes all callbacks for the given signalname. Also works for property notify callbacks.*/function invokeSignalCallbacks(signalName, signalArgs){var connections = object.__objectSignals__[signalName];if (connections) {connections.forEach(function(callback) {callback.apply(callback, signalArgs);});}}this.propertyUpdate = function(signals, propertyMap){// update property cachefor (var propertyIndex in propertyMap) {var propertyValue = propertyMap[propertyIndex];object.__propertyCache__[propertyIndex] = propertyValue;}for (var signalName in signals) {// Invoke all callbacks, as signalEmitted() does not. This ensures the// property cache is updated before the callbacks are invoked.invokeSignalCallbacks(signalName, signals[signalName]);}}this.signalEmitted = function(signalName, signalArgs){invokeSignalCallbacks(signalName, signalArgs);}function addMethod(methodData){var methodName = methodData[0];var methodIdx = methodData[1];object[methodName] = function() {var args = [];var callback;for (var i = 0; i < arguments.length; ++i) {if (typeof arguments[i] === "function")callback = arguments[i];elseargs.push(arguments[i]);}webChannel.exec({"type": QWebChannelMessageTypes.invokeMethod,"object": object.__id__,"method": methodIdx,"args": args}, function(response) {if (response !== undefined) {var result = object.unwrapQObject(response);if (callback) {(callback)(result);}}});};}function bindGetterSetter(propertyInfo){var propertyIndex = propertyInfo[0];var propertyName = propertyInfo[1];var notifySignalData = propertyInfo[2];// initialize property cache with current value// NOTE: if this is an object, it is not directly unwrapped as it might// reference other QObject that we do not know yetobject.__propertyCache__[propertyIndex] = propertyInfo[3];if (notifySignalData) {if (notifySignalData[0] === 1) {// signal name is optimized away, reconstruct the actual namenotifySignalData[0] = propertyName + "Changed";}addSignal(notifySignalData, true);}Object.defineProperty(object, propertyName, {configurable: true,get: function () {var propertyValue = object.__propertyCache__[propertyIndex];if (propertyValue === undefined) {// This shouldn't happenconsole.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__);}return propertyValue;},set: function(value) {if (value === undefined) {console.warn("Property setter for " + propertyName + " called with undefined value!");return;}object.__propertyCache__[propertyIndex] = value;webChannel.exec({"type": QWebChannelMessageTypes.setProperty,"object": object.__id__,"property": propertyIndex,"value": value});}});}// ----------------------------------------------------------------------data.methods.forEach(addMethod);data.properties.forEach(bindGetterSetter);data.signals.forEach(function(signal) { addSignal(signal, false); });for (var name in data.enums) {object[name] = data.enums[name];} }//required for use with nodejs if (typeof module === 'object') {module.exports = {QWebChannel: QWebChannel}; }?js調用py文件(js_call_py.html)
<html><head><title>A Demo Page</title><meta charset="UTF-8"><script src="./qwebchannel.js"></script><script language="javascript">function callback(result) {alert('計算結果:' + result)}document.addEventListener("DOMContentLoaded", function () {new QWebChannel( qt.webChannelTransport, function(channel) {window.obj = channel.objects.obj;});});function onFactorial() {if ( window.obj) {var n = parseInt(document.getElementById('n').value);window.obj.factorial(n,callback)}}</script></head><body><form><label >請輸入N:</label><input type="text" id="n"></input><br /><input type="button" value="計算階乘" onclick="onFactorial()"></form></body></html>?階乘功能類(factorial.py)
from PyQt5.QtCore import *class Factorial(QObject):@pyqtSlot(int, result=int)def factorial(self,n):if n == 0 or n == 1:return 1else:return self.factorial(n - 1) * n調用類(PyFactorial.py)
from PyQt5.QtWebChannel import QWebChannel from PyQt5.QtCore import * from PyQt5.QtWidgets import * from PyQt5.QtWebEngineWidgets import * import sys import os from factorial import *channel = QWebChannel() factorial = Factorial() class PyFactorial(QWidget):def __init__(self):super(PyFactorial, self).__init__()self.setWindowTitle('Python計算階乘')self.resize(600,300)layout=QVBoxLayout()self.browser = QWebEngineView()url = os.getcwd() + '/js_call_py.html'#裝載本地html文件self.browser.load(QUrl.fromLocalFile(url))channel.registerObject("obj",factorial)self.browser.page().setWebChannel(channel)layout.addWidget(self.browser)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)win = PyFactorial()win.show()sys.exit(app.exec_())課時95 絕對布局
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:29 import sys, math from PyQt5.QtWidgets import *class AbsoluteLayout(QWidget):def __init__(self):super(AbsoluteLayout, self).__init__()self.setWindowTitle('絕對布局')self.resize(300, 200)self.label1 = QLabel('歡迎', self)self.label1.move(15, 20)self.label2 = QLabel('學習', self)self.label2.move(35, 40)self.label3 = QLabel('PyQt5', self)self.label3.move(55, 60)self.label4 = QLabel('JavaEE', self)self.label4.move(75, 80)self.label5 = QLabel('Uniapp', self)self.label5.move(95, 100)self.label6 = QLabel('大數據', self)self.label6.move(115, 120)self.label2 = QLabel('區塊鏈', self)self.label2.move(135, 140)if __name__ == '__main__':app = QApplication(sys.argv)main = AbsoluteLayout()main.show()sys.exit(app.exec_())課時96 水平盒布局(QHBoxLayout)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:34 import sys, math from PyQt5.QtWidgets import *class HBoxLayout(QWidget):def __init__(self):super(HBoxLayout, self).__init__()self.setWindowTitle('水平盒布局')self.resize(300, 200)hlayout = QHBoxLayout()hlayout.addWidget(QPushButton('JavaEE'))hlayout.addWidget(QPushButton('Uniapp'))hlayout.addWidget(QPushButton('大數據'))hlayout.addWidget(QPushButton('區塊鏈'))hlayout.addWidget(QPushButton('人工智能'))# 設置控件之間的間距hlayout.setSpacing(20)self.setLayout(hlayout)if __name__ == '__main__':app = QApplication(sys.argv)main = HBoxLayout()main.show()sys.exit(app.exec_())課時97 設置控件的對齊方式
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:37 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class HBoxLayout(QWidget):def __init__(self):super(HBoxLayout, self).__init__()self.setWindowTitle('水平盒布局')self.resize(300, 200)hlayout = QHBoxLayout()'''參數二:拉伸量(幾個單位),eg:按鈕1后面有2個單位的拉伸,按鈕2后面有4個單位的拉伸參數三:對齊方式,eg:按鈕1是按照左上方對齊,其他以此類推'''hlayout.addWidget(QPushButton('按鈕1'), 2, Qt.AlignLeft | Qt.AlignTop)hlayout.addWidget(QPushButton('按鈕2'), 4, Qt.AlignLeft | Qt.AlignTop)hlayout.addWidget(QPushButton('按鈕3'), 1, Qt.AlignLeft | Qt.AlignTop)hlayout.addWidget(QPushButton('按鈕4'), 1, Qt.AlignLeft | Qt.AlignBottom)hlayout.addWidget(QPushButton('按鈕5'), 1, Qt.AlignLeft | Qt.AlignBottom)# 設置控件之間的間距hlayout.setSpacing(40)self.setLayout(hlayout)if __name__ == '__main__':app = QApplication(sys.argv)main = HBoxLayout()main.show()sys.exit(app.exec_())課時98? 垂直盒布局
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:42 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class VBoxLayout(QWidget):def __init__(self):super(VBoxLayout, self).__init__()self.setWindowTitle('垂直盒布局')self.resize(300, 200)hlayout = QVBoxLayout()hlayout.addWidget(QPushButton('JavaEE'))hlayout.addWidget(QPushButton('Uniapp'))hlayout.addWidget(QPushButton('大數據'))hlayout.addWidget(QPushButton('區塊鏈'))hlayout.addWidget(QPushButton('人工智能'))# 設置控件之間的間距hlayout.setSpacing(40)self.setLayout(hlayout)if __name__ == '__main__':app = QApplication(sys.argv)main = VBoxLayout()main.show()sys.exit(app.exec_())課時99 設置布局的伸縮量
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:45 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class Stretch(QWidget):def __init__(self):super(Stretch, self).__init__()self.setWindowTitle('設置伸縮量')self.resize(800, 100)btn1 = QPushButton(self)btn2 = QPushButton(self)btn3 = QPushButton(self)btn1.setText('JavaEE')btn2.setText('Uniapp')btn3.setText('大數據')layout = QHBoxLayout()# 伸縮量,在水平布局里有講過layout.addStretch(1) # 在按鈕前面添加伸縮單位layout.addWidget(btn1)layout.addStretch(2)layout.addWidget(btn2)layout.addStretch(3)layout.addWidget(btn3)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = Stretch()main.show()sys.exit(app.exec_()) # @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:47 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class Stretch(QWidget):def __init__(self):super(Stretch, self).__init__()self.setWindowTitle('設置伸縮量')self.resize(1000, 100)btn1 = QPushButton(self)btn2 = QPushButton(self)btn3 = QPushButton(self)btn4 = QPushButton(self)btn5 = QPushButton(self)btn1.setText('JavaEE')btn2.setText('Uniapp')btn3.setText('大數據')btn4.setText('區塊鏈')btn5.setText('人工智能')layout = QHBoxLayout()layout.addStretch(0) # 伸縮量設置為0,是先排列layout.addWidget(btn1)layout.addWidget(btn2)layout.addWidget(btn3)layout.addWidget(btn4)layout.addWidget(btn5)btnOK = QPushButton(self)btnOK.setText('確定')btnCancel = QPushButton(self)btnCancel.setText('取消')layout.addStretch(1)layout.addWidget(btnOK)layout.addWidget(btnCancel)self.setLayout(layout)if __name__ == '__main__':app = QApplication(sys.argv)main = Stretch()main.show()sys.exit(app.exec_())課時100 讓按鈕永遠在窗口的右下角
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:50 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class RBBtn(QWidget):def __init__(self):super(RBBtn, self).__init__()self.setWindowTitle('讓按鈕永遠在右下角')self.resize(400, 300)okBtn = QPushButton('確定')cancelBtn = QPushButton('取消')hbox = QHBoxLayout()hbox.addStretch(1)hbox.addWidget(okBtn)hbox.addWidget(cancelBtn)vbox = QVBoxLayout()btn1 = QPushButton('按鈕1')btn2 = QPushButton('按鈕2')btn3 = QPushButton('按鈕3')vbox.addStretch(0)vbox.addWidget(btn1)vbox.addWidget(btn2)vbox.addWidget(btn3)vbox.addStretch(1)# 布局之間的疊加,用addLayoutvbox.addLayout(hbox)self.setLayout(vbox)if __name__ == '__main__':app = QApplication(sys.argv)main = RBBtn()main.show()sys.exit(app.exec_())課時101 柵格布局:用循環方式實現計算器UI
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 14:57 import sys, math from PyQt5.QtWidgets import *class Calc(QWidget):def __init__(self):super(Calc, self).__init__()self.setWindowTitle('柵格布局:用循環方式實現計算器UI')grid = QGridLayout()self.setLayout(grid)names = ['Cls', 'Back', '', 'Close','7', '8', '9', '/','4', '5', '6', '*','1', '2', '3', '-','0', '.', '=', '+']positions = [(i, j) for i in range(5) for j in range(4)]print(positions)#輸出 按鈕名稱和坐標文職# 在元組前面加星號可將元組變成兩個單個的值print(*(1, 2)) # 輸出的不是元組,而是兩個值# zip函數返回一個可迭代的對象,接受多個可迭代的序列,將相應的元素組合成一對元組for position, name in zip(positions, names):if name == '':continue# print(position)# print(name)btn = QPushButton(name)grid.addWidget(btn, *position)if __name__ == '__main__':app = QApplication(sys.argv)main = Calc()main.show()sys.exit(app.exec_())?課時102 柵格布局:進行表單UI設計
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:09 import sys, math from PyQt5.QtWidgets import *class GridForm(QWidget):def __init__(self):super(GridForm, self).__init__()self.setWindowTitle('柵格布局:進行表單UI設計')# 標簽titleLabel = QLabel('標題')authorLabel = QLabel('作者')contentLabel = QLabel('內容')# 單行輸入titleEdit = QLineEdit()authorEdit = QLineEdit()# 多行輸入contentEdit = QTextEdit()grid = QGridLayout()# 控件間距grid.setSpacing(10)grid.addWidget(titleLabel, 1, 0) # 位置兩個軸都是從0開始,這里沒用而已grid.addWidget(titleEdit, 1, 1)grid.addWidget(authorLabel, 2, 0)grid.addWidget(authorEdit, 2, 1)grid.addWidget(contentLabel, 3, 0)grid.addWidget(contentEdit, 3, 1, 5, 1) # 空間上占五行一列self.setLayout(grid)self.resize(400, 300)if __name__ == '__main__':app = QApplication(sys.argv)main = GridForm()main.show()sys.exit(app.exec_())課時103 表單布局
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:15 import sys, math from PyQt5.QtWidgets import *class FormLayout(QWidget):def __init__(self):super(FormLayout, self).__init__()self.setWindowTitle('表單布局')self.resize(350, 300)# 標簽titleLabel = QLabel('標題')authorLabel = QLabel('作者')contentLabel = QLabel('內容')# 單行輸入titleEdit = QLineEdit()authorEdit = QLineEdit()# 多行輸入contentEdit = QTextEdit()formLayout = QFormLayout()formLayout.addRow(titleLabel, titleEdit)formLayout.addRow(authorLabel, authorEdit)formLayout.addRow(contentLabel, contentEdit)self.setLayout(formLayout)if __name__ == '__main__':app = QApplication(sys.argv)main = FormLayout()main.show()sys.exit(app.exec_())課時104 拖動控件之間的邊界(QSplitter)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:16 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import Qtclass Splitter(QWidget):def __init__(self):super(Splitter, self).__init__()self.setWindowTitle('Splitter例子')self.setGeometry(400, 300, 300, 200)topLeft = QFrame()topLeft.setFrameShape(QFrame.StyledPanel) # 面板類型bottom = QFrame()bottom.setFrameShape(QFrame.StyledPanel)splitter1 = QSplitter(Qt.Horizontal) # 水平拖動textEdit = QTextEdit()splitter1.addWidget(topLeft)splitter1.addWidget(textEdit)# 設置里面的控件的初始尺寸,eg:topLeft占100,textEdit占200splitter1.setSizes([100, 200])splitter2 = QSplitter(Qt.Vertical) # 垂直拖動splitter2.addWidget(splitter1)splitter2.addWidget(bottom)hbox = QHBoxLayout()hbox.addWidget(splitter2)self.setLayout(hbox)if __name__ == '__main__':app = QApplication(sys.argv)main = Splitter()main.show()sys.exit(app.exec_())課時105 信號與槽基礎
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:24 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class Demo(QWidget):def __init__(self):super(Demo, self).__init__()self.initUI()def initUI(self):self.setGeometry(300, 300, 300, 100)self.setWindowTitle('信號(Signal)與槽(Slot)')self.btn = QPushButton('我的按鈕', self)self.btn.clicked.connect(self.onClick)def onClick(self):self.btn.setText('信號已經發出')self.btn.setStyleSheet('QPushButton(max-width:500px;min-width:500px)')if __name__ == '__main__':app = QApplication(sys.argv)main = Demo()main.show()sys.exit(app.exec_())課時106 自定義信號實現對象之間的通信
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:30 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class MyTypeSignal(QObject):# 定義一個信號sendmsg = pyqtSignal(object)# 調用run來實現觸發def run(self):self.sendmsg.emit('Hello PyQt5') # 給槽傳遞一個參數class MySlot(QObject):# 槽函數def get(self, msg):print('信息:' + msg)if __name__ == '__main__':send = MyTypeSignal()slot = MySlot()send.sendmsg.connect(slot.get) # 連接信號與槽函數send.run() # 發送信號# 斷開信號與槽的連接# send.sendmsg.disconnect(slot.get)課時107 可以傳遞多個參數的信號
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:38 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class MyTypeSignal(QObject):# 定義一個信號sendmsg = pyqtSignal(object)# 發送三個參數的信號sendmsg1 = pyqtSignal(str, int, int)# 調用run來實現觸發def run(self):self.sendmsg.emit('Hello PyQt5') # 給槽傳遞一個參數def run1(self):self.sendmsg1.emit('hello', 3, 4)class MySlot(QObject):# 槽函數def get(self, msg):print('信息:' + msg)def get1(self, msg, a, b):print(msg)print(a + b)if __name__ == '__main__':send = MyTypeSignal()slot = MySlot()send.sendmsg.connect(slot.get) # 連接信號與槽函數send.sendmsg1.connect(slot.get1)send.run() # 發送信號send.run1() # 別忘了調用相應的觸發函數!!!!# 斷開信號與槽的連接# send.sendmsg.disconnect(slot.get)課時108 為類添加多個信號(重載形式的信號)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:43 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class MultiSignal(QObject):# 無參數signal1 = pyqtSignal()# 有一個整型的參數signal2 = pyqtSignal(int)# 參數一是整型,參數二是字符型signal3 = pyqtSignal(int, str)# 參數是一個列表signal4 = pyqtSignal(list)# 參數是一個字典signal5 = pyqtSignal(dict)# 聲明一個重載版本的信號,中括號之間是或的意思,也就是槽函數可以是兩個參數:int和str類型,也可以是一個參數:str類型signal6 = pyqtSignal([int, str], [str])def __init__(self):super(MultiSignal, self).__init__()self.signal1.connect(self.signalcall1)self.signal2.connect(self.signalcall2)self.signal3.connect(self.signalcall3)self.signal4.connect(self.signalcall4)self.signal5.connect(self.signalcall5)# self.signal6.connect(self.signalcall6)#默認關聯到重構的第一個槽函數上# 為了可讀性,可像下面那樣寫self.signal6[str].connect(self.signalcall6Overload)self.signal6[int, str].connect(self.signalcall6)self.signal1.emit()self.signal2.emit(10)self.signal3.emit(1, 'hello world')self.signal4.emit([1, 2, 3, 4, 5])self.signal5.emit({'name': 'Bill', 'age': 30})self.signal6[str].emit('test')self.signal6[int, str].emit(20, 'mytest')# 槽函數def signalcall1(self):print('signal1 emit')def signalcall2(self, val):print('signa2 emit,value:', val)def signalcall3(self, val, text):print('signa3 emit,value:', val, text)def signalcall4(self, val):print('signa4 emit,value:', val)def signalcall5(self, val):print('signa5 emit,value:', val)def signalcall6(self, val, text):print('signa6 emit,value:', val, text)def signalcall6Overload(self, val):print('signa6 overload emit,value:', val)if __name__ == '__main__':multiSignal = MultiSignal()課時109 信號與槽的N對N連接與斷開連接
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 15:54 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class NNSignal(QObject):signal1 = pyqtSignal() # 無參數signal2 = pyqtSignal(int)signal3 = pyqtSignal()def __init__(self):super(NNSignal, self).__init__()# 一個信號對應多個槽self.signal1.connect(self.call1)self.signal1.connect(self.call11)self.signal1.emit()# 信號綁定到槽上self.signal2.connect(self.signal1)print('*****************************')self.signal2.emit(2) # 觸發了信號1'''以上操作的運行結果call1 emitcall11 emitcall1 emitcall11 emit'''print('************************************')# 解綁self.signal1.disconnect(self.call1)self.signal1.disconnect(self.call11)self.signal2.disconnect(self.signal1)# 重新綁定self.signal1.connect(self.call1)self.signal2.connect(self.call2)# 一個槽函數綁定到多個信號上self.signal3.connect(self.call1)self.signal1.emit()self.signal2.emit(100)self.signal3.emit()def call1(self):print('call1 emit')def call11(self):print('call11 emit')def call2(self, val):print('call2 emit', val)if __name__ == '__main__':nnSignal = NNSignal()課時110 為窗口添加信號
本質就是為一個類添加信號,只不過這個類是窗口類
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:02 import sys, math from PyQt5.QtWidgets import * from PyQt5.QtCore import *class WinSignal(QWidget):# 定義一個信號btn_clicked_signal = pyqtSignal()def __init__(self):super(WinSignal, self).__init__()self.setWindowTitle('為窗口添加信號')self.resize(300, 100)btn = QPushButton('關閉窗口', self)btn.clicked.connect(self.btn_clicked)self.btn_clicked_signal.connect(self.btn_close)# 起觸發函數作用的槽函數def btn_clicked(self):self.btn_clicked_signal.emit()# 關閉窗口作用的槽函數def btn_close(self):self.close()if __name__ == '__main__':app = QApplication(sys.argv)main = WinSignal()main.show()sys.exit(app.exec_())?課時111 多線程更新UI數據
多線程更新UI數據,兩個線程中傳遞數據
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:09 import sys, math import time from PyQt5.QtWidgets import QApplication, QDialog, QLineEdit from PyQt5.QtCore import QThread, pyqtSignal, QDateTimeclass BackendThread(QThread):# 更新日期的信號update_date = pyqtSignal(str)def run(self):while True:date = QDateTime.currentDateTime()currentTime = date.toString('yyyy-MM-dd hh:mm:ss')# 信號參數是當前時間self.update_date.emit(str(currentTime))time.sleep(1) # 隔1s就發送一次信號class ThreadUpdateUI(QDialog):def __init__(self):QDialog.__init__(self)self.setWindowTitle('多線程更新UI數據')self.resize(400, 100)# 存放當前時間self.input = QLineEdit(self)self.input.resize(400, 100)self.initUI()def initUI(self):self.backend = BackendThread()self.backend.update_date.connect(self.handleDisplay)self.backend.start() # 開啟線程,自動調用run# 槽函數是主線程def handleDisplay(self, data): # data是當前時間self.input.setText(data)if __name__ == '__main__':app = QApplication(sys.argv)main = ThreadUpdateUI()main.show()sys.exit(app.exec_())課時112 信號與槽自動連接
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:22 from PyQt5 import QtCore from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton import sysclass AutoSignalSlot(QWidget):def __init__(self):super(AutoSignalSlot, self).__init__()self.resize(300, 100)self.okBtn = QPushButton('ok', self)self.okBtn1 = QPushButton('cancel', self)# 設置自動連接self.okBtn.setObjectName('okBtn')self.okBtn1.setObjectName('cancelBtn')QtCore.QMetaObject.connectSlotsByName(self)layout = QHBoxLayout()layout.addWidget(self.okBtn)layout.addWidget(self.okBtn1)self.setLayout(layout)# 傳統連接信號與槽# self.okBtn.clicked.connect(self.on_okBtn_clicked)# 命名規則:on_發送者對象(objectname)名稱_發射信號名稱(self,參數)@QtCore.pyqtSlot() # 標注為槽函數,以供自動連接使用def on_okBtn_clicked(self):print('點擊了ok按鈕')@QtCore.pyqtSlot()def on_cancelBtn_clicked(self):print('點擊了cancel按鈕')if __name__ == '__main__':app = QApplication(sys.argv)main = AutoSignalSlot()main.show()sys.exit(app.exec_())課時113 用Lambda表達式為槽函數傳遞參數
Lambda表達式:匿名函數,也就是沒有名字的函數。
將Lambda賦給一個變量,這個變量就成為了一個函數引用。或者將Lambda表達式作為一個參數傳入函數。
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:32 # Lambda表達式示例 fun = lambda: print('hello world') fun()fun = lambda x, y: print(x, y) fun('a', 'b')from PyQt5.QtWidgets import * import sysclass LambdaSlotArg(QMainWindow):def __init__(self):super(LambdaSlotArg, self).__init__()self.setWindowTitle('用Lambda表達式為槽函數傳遞參數')btn1 = QPushButton('按鈕1')btn2 = QPushButton('按鈕2')ok = 200btn1.clicked.connect(lambda: self.onButtonClick(10, ok))btn2.clicked.connect(lambda: self.onButtonClick(ok, -20))btn1.clicked.connect(lambda: QMessageBox.information(self, '結果', '單擊了btn1'))layout = QHBoxLayout()layout.addWidget(btn1)layout.addWidget(btn2)mainFrame = QWidget()mainFrame.setLayout(layout)self.setCentralWidget(mainFrame)def onButtonClick(self, m, n):print('m+n=', m + n)QMessageBox.information(self, '結果', str(m + n))if __name__ == '__main__':app = QApplication(sys.argv)main = LambdaSlotArg()main.show()sys.exit(app.exec_())?課時114 用partial對象為槽函數傳遞參數
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:43 from PyQt5.QtWidgets import * from functools import partial import sysclass PartialSlotArg(QMainWindow):def __init__(self):super(PartialSlotArg, self).__init__()self.setWindowTitle('用partial對象為槽函數傳遞參數')btn1 = QPushButton('按鈕1')btn2 = QPushButton('按鈕2')x = 20y = -123btn1.clicked.connect(partial(self.onButtonClick, 10, 20))btn2.clicked.connect(partial(self.onButtonClick, x, y))layout = QHBoxLayout()layout.addWidget(btn1)layout.addWidget(btn2)mainFrame = QWidget()mainFrame.setLayout(layout)self.setCentralWidget(mainFrame)def onButtonClick(self, m, n):print('m+n=', m + n)QMessageBox.information(self, '結果', str(m + n))if __name__ == '__main__':app = QApplication(sys.argv)main = PartialSlotArg()main.show()sys.exit(app.exec_())課時115 override(覆蓋)槽函數
系統已經定義了很多槽函數,我們能可以覆蓋重寫這些槽函數
我們通過覆蓋keyPressEvent槽函數修改了按ESC和ALT鍵的行為。當我們按ESC的時候,窗口關閉,當按ALT鍵的時候窗口標題修改為"按下了Alt鍵"。
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:49 from PyQt5.QtWidgets import * from PyQt5.QtCore import * import sysclass OverrideSlot(QWidget):def __init__(self):super().__init__()self.setWindowTitle('override(覆蓋)槽函數')# 鍵盤按下的槽函數,不需要連接,系統已經給連接了def keyPressEvent(self, e):# 如果按下Esc鍵,則關閉窗口if e.key() == Qt.Key_Escape:self.close()# 如果按下Alt鍵,修改窗口標題為 按下Alt鍵elif e.key() == Qt.Key_Alt:self.setWindowTitle('按下Alt鍵')if __name__ == '__main__':app = QApplication(sys.argv)main = OverrideSlot()main.show()sys.exit(app.exec_())?課時116 多窗口交互(1):不使用信號與槽
所謂的交互就是數據的傳遞。不使用信號與槽就是強耦合的方式,即兩個窗口之間相互調用控件。
?
DateDialog.py?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:55 from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class DateDialog(QDialog):def __init__(self, parent=None):super(DateDialog, self).__init__(parent)# 當這里面傳入self,相當于 self.setLayout(layout),而且上面的parent必須有layout = QVBoxLayout(self)'''QDateTimeEdit是一個允許用戶編輯日期時間的控件,可以使用鍵盤上的上下鍵頭按鈕來增加或減少日期的時間值,QDateTimeEdit通過setDisplayFormat()函數來設置顯示的日期時間格式'''# 日期時間輸入框self.datetime = QDateTimeEdit(self)# print(isinstance(datetime,DateDialog))# popup (n.) 彈出;彈跳裝置;發射self.datetime.setCalendarPopup(True)# 顯示當前日期self.datetime.setDateTime(QDateTime.currentDateTime())layout.addWidget(self.datetime)# 兩個按鈕buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)# 下面兩個槽函數是系統已經定義好的buttons.accepted.connect(self.accept)# reject (v.)拒絕buttons.rejected.connect(self.reject)layout.addWidget(buttons)def dateTime(self):# 返回當前日期return self.datetime.dateTime()@staticmethod # 靜態方法def getDateTime(parent=None):dialog = DateDialog(parent)# 顯示對話框result = dialog.exec_()date = dialog.dateTime()# print('date.date():',date.date()) #日期:年月日# print('date.time():',date.time())#時間:時分秒# 第三個參數是:是否點擊了okreturn (date.date(), date.time(), result == QDialog.Accepted)MutilWindow1.py
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 16:57 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from DateDialog import DateDialogclass MutilWindow1(QWidget):def __init__(self):super(MutilWindow1, self).__init__()self.setWindowTitle('多窗口交互(1):不使用信號與槽')# 單行輸入self.lineEdit = QLineEdit(self)self.btn1 = QPushButton('彈出對話框1')self.btn1.clicked.connect(self.onButton1Click)self.btn2 = QPushButton('彈出對話框2')self.btn2.clicked.connect(self.onButton2Click)# 柵格布局gridLayout = QGridLayout()gridLayout.addWidget(self.lineEdit)gridLayout.addWidget(self.btn1)gridLayout.addWidget(self.btn2)self.setLayout(gridLayout)def onButton1Click(self):dialog = DateDialog(self)result = dialog.exec_()date = dialog.dateTime()self.lineEdit.setText(date.date().toString())# 銷毀窗口dialog.destroy()def onButton2Click(self):date, time, result = DateDialog.getDateTime()self.lineEdit.setText(date.toString())if result == QDialog.Accepted:print('點擊確定按鈕')else:print('點擊取消按鈕')if __name__ == '__main__':app = QApplication(sys.argv)main = MutilWindow1()main.show()sys.exit(app.exec_())課時117 多窗口交互(2):使用信號與槽
低耦合:
如果一個窗口A與另一個窗口B交互,那么A盡量不要直接訪問B窗口中的控件,
應該在窗口A中訪問B窗口中的信號,并指定與信號綁定的槽函數
例:如果A直接訪問B窗口的控件,一旦B窗口控件發生改變,那么A和B的代碼都需要變化
如果A訪問的是B中的信號,那么B中的控件發生了改變,只需要修改B中的代碼即可。信號就是為此而生
NewDateDialog.py # @CSDN王家視頻教程圖書館 # @Time 2022/11/24 17:40 from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class NewDateDialog(QDialog):# 定義一個信號,有一個字符串型的參數Signal_OneParameter = pyqtSignal(str)def __init__(self, parent=None):super(NewDateDialog, self).__init__(parent)self.setWindowTitle('子窗口:用來發射信號')# 在布局中添加部件,垂直布局layout = QVBoxLayout(self)self.label = QLabel(self)self.label.setText('前者發射內置信號\n后者發射自定義信號')# 定義兩個日期時間編輯框self.datetime_inner = QDateTimeEdit(self)# 彈出模式self.datetime_inner.setCalendarPopup(True)# 設置為當前時間self.datetime_inner.setDateTime(QDateTime.currentDateTime())self.datetime_emit = QDateTimeEdit(self)self.datetime_emit.setCalendarPopup(True)self.datetime_emit.setDateTime(QDateTime.currentDateTime())# 放入垂直布局layout.addWidget(self.label)layout.addWidget(self.datetime_inner)layout.addWidget(self.datetime_emit)# 使用兩個button(ok和cancel)分別連接accept()和reject()槽函數buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel,Qt.Horizontal, self)buttons.accepted.connect(self.accept)buttons.rejected.connect(self.reject)layout.addWidget(buttons)self.datetime_emit.dateTimeChanged.connect(self.emit_signal)def emit_signal(self):date_str = self.datetime_emit.dateTime().toString()print(date_str)# 發出信號self.Signal_OneParameter.emit(date_str) MutilWindow2.py # @CSDN王家視頻教程圖書館 # @Time 2022/11/24 17:40 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * from NewDateDialog import NewDateDialogclass MultiWindow2(QWidget):def __init__(self, parent=None):super(MultiWindow2, self).__init__(parent)self.resize(400, 90)self.setWindowTitle('多窗口交互(2):使用信號與槽')self.open_btn = QPushButton('獲取時間')self.lineEdit_inner = QLineEdit(self)self.lineEdit_emit = QLineEdit(self)self.open_btn.clicked.connect(self.openDialog)self.lineEdit_inner.setText('接收子窗口內置信號的時間')self.lineEdit_emit.setText('接收子窗口自定義信號的時間')grid = QGridLayout()grid.addWidget(self.lineEdit_inner)grid.addWidget(self.lineEdit_emit)grid.addWidget(self.open_btn)self.setLayout(grid)def openDialog(self):dialog = NewDateDialog(self)# dateTimeChanged 是時間改變信號,即手動使日期時間發生改變就會發出信號# 連接子窗口的內置信號與主窗口的槽函數dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot)# 連接子窗口的自定義信號與主窗口的槽函數(推薦用這種)dialog.Signal_OneParameter.connect(self.deal_emit_slot)dialog.show()def deal_inner_slot(self, date):self.lineEdit_inner.setText(date.toString())def deal_emit_slot(self, dateStr):self.lineEdit_emit.setText(dateStr)if __name__ == "__main__":app = QApplication(sys.argv)form = MultiWindow2()form.show()sys.exit(app.exec_())?課時118 設置窗口中控件的風格
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 18:13 import sys from PyQt5.QtWidgets import * from PyQt5 import QtCore# 窗口可以顯示的風格樣式 print('窗口可以顯示的風格樣式:', QStyleFactory.keys())class WindowStyle(QWidget):def __init__(self):super().__init__()self.setWindowTitle('設置窗口風格')horizontalLayout = QHBoxLayout()self.styleLabel = QLabel('設置窗口風格:')# 下拉框self.styleComboBox = QComboBox()self.styleComboBox.addItems(QStyleFactory.keys())# 獲取當前窗口的風格print('當前窗口的風格:', QApplication.style().objectName())# 獲取當前窗口的風格的索引index = self.styleComboBox.findText(QApplication.style().objectName(), QtCore.Qt.MatchFixedString)# 將下拉框初始設置為當前窗口的風格的名字self.styleComboBox.setCurrentIndex(index)self.styleComboBox.activated[str].connect(self.handleStyleChanged)horizontalLayout.addWidget(self.styleLabel)horizontalLayout.addWidget(self.styleComboBox)self.setLayout(horizontalLayout)def handleStyleChanged(self, style):# 設置風格QApplication.setStyle(style)if __name__ == "__main__":app = QApplication(sys.argv)form = WindowStyle()form.show()sys.exit(app.exec_())?課時119 設置窗口樣式
setWindowFlags ????????( WindowFlags type )
FrameWindowHint????????沒有邊框的窗口
WindowStaysOnTopHint????????總在最上面的窗口
CustomizeWindowHint????????自定義窗口標題欄,以下標志必須與這個標志一起使用才有效,否則窗口將有默認的標題欄
WindowTitleHint????????顯示窗口標題欄
WindowSystemMenuHint????????顯示系統菜單
WindowMinimizeButtonHint????????顯示最小化按鈕
WindowMaximizeButtonHint????????顯示最大化按鈕
WindowMinMaxButtonsHint????????顯示最小化按鈕和最大化按鈕
WindowCloseButtonHint????????顯示關閉按鈕
setWindowFlags(FramelessWindowHint)????????直接隱藏掉
?課時120 用代碼設置窗口的最大化和最小化
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 18:43 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import *### 自定義窗口類 class WindowMaxMin(QWidget):# 構造函數def __init__(self, parent=None):'''構造函數'''# 調用父類構造函數super(WindowMaxMin, self).__init__(parent)self.resize(300, 400)self.setWindowTitle("用代碼控制窗口的最大化和最小化")self.setWindowFlags(Qt.WindowMaximizeButtonHint | Qt.WindowCloseButtonHint | Qt.WindowMinMaxButtonsHint)layout = QVBoxLayout()maxButton1 = QPushButton()maxButton1.setText('窗口最大化1 使用自己的方法')maxButton1.clicked.connect(self.maximized1)maxButton2 = QPushButton()maxButton2.setText('窗口最大化2 使用系統提供的方法')maxButton2.clicked.connect(self.showMaximized)minButton = QPushButton()minButton.setText('窗口最小化')minButton.clicked.connect(self.showMinimized)layout.addWidget(maxButton1)layout.addWidget(maxButton2)layout.addWidget(minButton)self.setLayout(layout)def maximized1(self):# 獲得桌面desktop = QApplication.desktop()# 獲取桌面可用尺寸rect = desktop.availableGeometry()self.setGeometry(rect)if __name__ == "__main__":app = QApplication(sys.argv)window = WindowMaxMin()window.show()# 應用程序事件循環sys.exit(app.exec_())課時121 項目實戰:實現繪圖應用
需要解決3個核心內容
1. 如何繪圖
在paintEvent方法中繪圖,通過調用update方法觸發painEvent的調用
2. 在哪里繪圖
在白色背景的QPixmap對象中繪圖
3. 如何通過移動鼠標進行繪圖
鼠標擁有3個事件:
(1)鼠標按下:mousePressEvent
(2)鼠標移動:mouseMoveEvent
(3)鼠標抬起:mouseReleaseEvent
課時122? QSS基礎
QSS (Qt Style Sheets)
Qt樣式表
用于設置控件的樣式
?課時123 使用QSS選擇器設置控件樣式
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 19:41 from PyQt5.QtWidgets import * import sysclass QSSSelector(QWidget):def __init__(self):super().__init__()self.setWindowTitle("QSS樣式")btn1 = QPushButton(self)btn1.setText("按鈕1")btn2 = QPushButton(self)# 設置name屬性,可根據屬性來指定按鈕btn2.setProperty('name', 'btn2')btn2.setText("按鈕2")btn3 = QPushButton(self)btn3.setProperty('name', 'btn3')btn3.setText("按鈕3")vbox = QVBoxLayout()vbox.addWidget(btn1)vbox.addWidget(btn2)vbox.addWidget(btn3)self.setLayout(vbox)if __name__ == "__main__":app = QApplication(sys.argv)form = QSSSelector()# 選擇器# 指定按鈕qssStyle = '''QPushButton[name="btn2"] { background-color:red;color:yellow;height:120;font-size:60px;}QPushButton[name="btn3"] {background-color:blue;color:yellow;height:60;font-size:30px;}'''form.setStyleSheet(qssStyle)form.show()sys.exit(app.exec_())課時124 QSS子控件選擇器
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 19:46 from PyQt5.QtWidgets import * import sysclass QSSSubControl(QWidget):def __init__(self):super().__init__()self.setWindowTitle("QSS子控件選擇器")combo = QComboBox(self)# 設置下拉框名字combo.setObjectName("myComboBox")combo.addItem("Window")combo.addItem("Linux")combo.addItem("Mac OS X")combo.move(50, 50)# 窗口的尺寸和位置self.setGeometry(250, 200, 320, 150)if __name__ == "__main__":app = QApplication(sys.argv)form = QSSSubControl()'''通過名字來引用,#myComboBox相當于web里通過id來引用drop-down是下拉子控件'''qssStyle = '''QComboBox#myComboBox::drop-down {image:url(./csdnlogo.jpg)}'''form.setStyleSheet(qssStyle)form.show()sys.exit(app.exec_())課時125 使用QSS為標簽和按鈕添加背景圖
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 19:54 from PyQt5.QtWidgets import * import sysclass LabelButtonBackground(QWidget):def __init__(self):super().__init__()label1 = QLabel(self)# 鼠標放在上面就提示label1.setToolTip('這是一個文本標簽')# QSS方式在label1上設置背景圖label1.setStyleSheet('QLabel{border-image:url(./csdnlogo.jpg);}')label1.setFixedWidth(476)label1.setFixedHeight(259)btn1 = QPushButton(self)btn1.setObjectName('btn1')btn1.setMaximumSize(60, 60)btn1.setMinimumSize(60, 60)# 正常狀態和按下狀態時按鈕圖標不同style = '''#btn1{border-radius:4px;background-image:url('./csdnlogo.jpg');}#btn1:Pressed {background-image:url('./and.png');}'''btn1.setStyleSheet(style)vbox = QVBoxLayout()vbox.addWidget(label1)vbox.addStretch()vbox.addWidget(btn1)self.setLayout(vbox)self.setWindowTitle('使用QSS為標簽和按鈕添加背景圖')if __name__ == "__main__":app = QApplication(sys.argv)form = LabelButtonBackground()form.show()sys.exit(app.exec_())?課時126 裝載QSS文件
這里報了一個文件找不到的錯誤 目前還沒有解決
QSS文件 style.qss
QMainWindow{border-image:url(./and.png); }QToolTip{border:1px solid rgb(45,45,45);background:white;color:red }裝載類 CommonHelper.py
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 20:20 #裝載類 class CommonHelper:@staticmethoddef readQSS(style):with open(style,'r') as f:return f.read()??loadQSS.py
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 20:21 import sys from PyQt5.QtWidgets import * from CommonHelper import CommonHelperclass MainWindow(QMainWindow):def __init__(self, parent=None):super(MainWindow, self).__init__(parent)self.resize(477, 258)self.setWindowTitle("加載QSS文件")btn = QPushButton()btn.setText('裝載QSS文件')# 鼠標放到上面會有提示信息btn.setToolTip('提示文本')vbox = QVBoxLayout()vbox.addWidget(btn)btn.clicked.connect(self.onClick)self.setLayout(vbox)widget = QWidget(self)self.setCentralWidget(widget)widget.setLayout(vbox)def onClick(self):styleFile = './style.qss'qssStyle = CommonHelper.readQSS(styleFile)win.setStyleSheet(qssStyle)if __name__ == "__main__":app = QApplication(sys.argv)win = MainWindow()win.show()sys.exit(app.exec_())?課時127 三種設置背景色和背景圖片的方式
1. QSS 2. QPalette 3. 直接繪制方式一 QSS?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 20:50 ''' 使用多種方式設置窗口背景色和背景圖片 1. QSS 2. QPalette 3. 直接繪制 '''import sys from PyQt5.QtWidgets import *app = QApplication(sys.argv) win = QMainWindow() win.setWindowTitle("背景圖片") win.resize(350, 250) win.setObjectName("MainWindow")# 通過QSS動態修改窗口的背景顏色和背景圖片win.setStyleSheet("#MainWindow{border-image:url(./csdnlogo.jpg);}") #win.setStyleSheet("#MainWindow{background-color:yellow}")win.show() sys.exit(app.exec())?方式二 QPalette
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 20:54 import sysfrom PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtCore import *app = QApplication(sys.argv) win = QMainWindow() win.setWindowTitle("背景圖片") win.resize(350, 250) win.setObjectName("MainWindow")# 通過QPalette設置背景圖片和背景顏色 # palette調色板 palette = QPalette() # 設置畫刷 palette.setBrush(QPalette.Background, QBrush(QPixmap("./csdnlogo.jpg"))) # palette.setColor(QPalette.Background,Qt.red) win.setPalette(palette)win.show() sys.exit(app.exec())方式三 直接繪制
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 20:57 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import *class Background1(QWidget):def __init__(self):super().__init__()self.setWindowTitle("繪制背景顏色")def paintEvent(self, event):painter = QPainter(self)painter.setBrush(Qt.yellow)painter.drawRect(self.rect())if __name__ == "__main__":app = QApplication(sys.argv)form = Background1()form.show()sys.exit(app.exec_())?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 20:58 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import *class Background2(QWidget):def __init__(self):super().__init__()self.setWindowTitle("繪制背景圖片")def paintEvent(self, event):painter = QPainter(self)pixmap = QPixmap('./csdnlogo.jpg')painter.drawPixmap(self.rect(), pixmap)if __name__ == "__main__":app = QApplication(sys.argv)form = Background2()form.show()sys.exit(app.exec_())課時127 實現不規則窗口(異形窗口)注意只對windowse系統有效果
通過mask實現異形窗口
需要一張透明的png圖,透明部分被扣出,形成一個非矩形的區域
?
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 21:03 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import *class AbnormityWindow(QWidget):def __init__(self):super().__init__()self.setWindowTitle("異形窗口")self.pix = QBitmap('mask/mask1.png')self.resize(self.pix.size())# 設置掩膜,窗口就是掩膜的形狀self.setMask(self.pix)def paintEvent(self, event):painter = QPainter(self)painter.drawPixmap(0, 0, self.pix.width(), self.pix.height(), QPixmap('./csdnlogo.jpg'))if __name__ == "__main__":app = QApplication(sys.argv)form = AbnormityWindow()form.show()sys.exit(app.exec_())?課時128 移動和關閉不規則窗口(異形窗口)
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 21:26 import sys from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtCore import *class AbnormityWindow(QWidget):def __init__(self):super().__init__()self.setWindowTitle("異形窗口")self.pix = QBitmap('./mask/mask1.png')self.resize(self.pix.size())self.setMask(self.pix)# 鼠標按下def mousePressEvent(self, event):if event.button() == Qt.LeftButton:# 鼠標按下或抬起標志位self.m_drag = True# 當前單擊點相對于窗口本身的坐標,永遠是正的self.m_DragPosition = event.globalPos() - self.pos()# print(self.m_DragPosition)# 設置光標形狀self.setCursor(QCursor(Qt.OpenHandCursor))'''# 當前單擊點相對于屏幕的坐標,包括標題欄和邊框print(event.globalPos())# 當前單擊點相對于窗口的坐標,忽略標題欄和邊框print(event.pos())'''# 左上角坐標相對于屏幕的坐標,包括標題欄和邊框print(self.pos())# 按下右鍵if event.button() == Qt.RightButton:self.close()# 鼠標移動def mouseMoveEvent(self, QMouseEvent):if Qt.LeftButton and self.m_drag:# 當左鍵移動窗體修改偏移值# QPoint'''實時計算窗口左上角坐標,注意是左上角!!!!!!這個移動是從上次的窗口位置往現在到達的位置移動,所以是現在的globalPos()減去移動之前的單擊點到窗口邊框的距離,就是當前左上角坐標'''self.move(QMouseEvent.globalPos() - self.m_DragPosition)# 鼠標抬起def mouseReleaseEvent(self, QMouseEvent):self.m_drag = False# cursor(n.)光標self.setCursor(QCursor(Qt.ArrowCursor))def paintEvent(self, event):painter = QPainter(self)painter.drawPixmap(0, 0, self.pix.width(), self.pix.height(), QPixmap('./csdnlogo.jpg'))if __name__ == "__main__":app = QApplication(sys.argv)form = AbnormityWindow()form.show()sys.exit(app.exec_())?課時129 實現異形窗口動畫效果
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 21:48 import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtGui import QPixmap, QPainter, QCursor from PyQt5.QtCore import Qt, QTimerclass AnimationWindows(QWidget):def __init__(self, parent=None):super(AnimationWindows, self).__init__(parent)self.i = 1self.mypix() # 顯示第一張的圖self.timer = QTimer() # 定時器self.timer.setInterval(500) # 即500毫秒換一幀self.timer.timeout.connect(self.timeChange)self.timer.start()# 顯示不規則 picdef mypix(self):# 通過立即調用paintEvent()來直接重新繪制窗口部件self.update()if self.i == 5:self.i = 1self.mypic = {1: './rotate/left.png', 2: "./rotate/top.png", 3: './rotate/right.png',4: './rotate/buttom.png'}self.pix = QPixmap(self.mypic[self.i])self.resize(self.pix.size())# 設置掩膜self.setMask(self.pix.mask())self.dragPosition = Nonedef mousePressEvent(self, event):if event.button() == Qt.LeftButton:self.m_drag = Trueself.m_DragPosition = event.globalPos() - self.pos()# 設置光標形狀self.setCursor(QCursor(Qt.OpenHandCursor))def mouseMoveEvent(self, QMouseEvent):if Qt.LeftButton and self.m_drag:self.move(QMouseEvent.globalPos() - self.m_DragPosition)def mouseReleaseEvent(self, QMouseEvent):self.m_drag = Falseself.setCursor(QCursor(Qt.ArrowCursor))def paintEvent(self, event):painter = QPainter(self)painter.drawPixmap(0, 0, self.pix.width(), self.pix.height(), self.pix)# 鼠標雙擊事件def mouseDoubleClickEvent(self, event):if event.button() == 1:self.i += 1self.mypix()# 每500毫秒修改paint,即換一張圖def timeChange(self):self.i += 1self.mypix()if __name__ == '__main__':app = QApplication(sys.argv)form = AnimationWindows()form.show()sys.exit(app.exec_())課時130 裝載gif動畫文件
效果暫時沒有顯示出來,后續測試
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 22:08 import sys from PyQt5.QtWidgets import QApplication,QLabel,QWidget from PyQt5.QtCore import Qt from PyQt5.QtGui import QMovieclass loadingGif(QWidget):def __init__(self):super(loadingGif, self).__init__()self.label = QLabel("", self)self.setFixedSize(128, 128)self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint)self.movie = QMovie('../loding2.gif')self.label.setMovie(self.movie)self.movie.start()if __name__ == "__main__":app = QApplication(sys.argv)form = loadingGif()form.show()sys.exit(app.exec_())課時131 縮放圖片
QImage.scaled
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 22:39 from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtCore import Qt import sysclass ScaleImage(QWidget):def __init__(self):super().__init__()self.setWindowTitle("圖片大小縮放例子")filename = './csdnlogo.jpg'img = QImage(filename)label1 = QLabel(self)label1.setFixedWidth(200)label1.setFixedHeight(200)# 參數三四:忽略比例,平滑顯示result = img.scaled(label1.width(), label1.height(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)label1.setPixmap(QPixmap.fromImage(result))vbox = QVBoxLayout()vbox.addWidget(label1)self.setLayout(vbox)if __name__ == "__main__":app = QApplication(sys.argv)win = ScaleImage()win.show()sys.exit(app.exec_())課時132 用動畫效果改變窗口的尺寸
QPropertyAnimation可以控制任何可視控件的尺寸的動態的變化,只要我們把控件的對象通過構造方法傳入即可
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 22:48 from PyQt5.QtCore import * from PyQt5.QtWidgets import * import sysclass AnimWindow(QWidget):def __init__(self):super(AnimWindow, self).__init__()self.OrigHeight = 50self.ChangeHeight = 150self.setGeometry(QRect(500, 400, 150, self.OrigHeight))self.btn = QPushButton('展開', self) # 沒用布局,直接將按鈕放入self.btn.setGeometry(10, 10, 60, 35)self.btn.clicked.connect(self.change)def change(self):currentHeight = self.height()if self.OrigHeight == currentHeight:startHeight = self.OrigHeightendHeight = self.ChangeHeightself.btn.setText('收縮')else:startHeight = self.ChangeHeightendHeight = self.OrigHeightself.btn.setText('展開')self.animation = QPropertyAnimation(self, b'geometry') # 將當前窗口傳入self.animation.setDuration(500) # 間隔時間:500毫秒# 初始尺寸self.animation.setStartValue(QRect(500, 400, 150, startHeight))# 變化后的尺寸self.animation.setEndValue(QRect(500, 400, 150, endHeight))self.animation.start()returnif __name__ == '__main__':app = QApplication(sys.argv)window = AnimWindow()window.show()sys.exit(app.exec_())課時133用動畫效果以不同速度移動窗口
# @CSDN王家視頻教程圖書館 # @Time 2022/11/24 22:55 from PyQt5.QtGui import * from PyQt5.QtCore import * from PyQt5.QtWidgets import * import sysapp = QApplication(sys.argv)window1 = QMainWindow() window1.show() window2 = QMainWindow() window2.show()animation1 = QPropertyAnimation(window1, b'geometry') animation2 = QPropertyAnimation(window2, b'geometry')group = QParallelAnimationGroup() # 并行 動畫組 并行,同時運行多個動畫 # group = QSequentialAnimationGroup() # 串行group.addAnimation(animation1) group.addAnimation(animation2)animation1.setDuration(3000) animation1.setStartValue(QRect(0, 0, 100, 30)) animation1.setEndValue(QRect(250, 250, 100, 30)) animation1.setEasingCurve(QEasingCurve.OutBounce) # 動畫特效animation2.setDuration(4000) animation2.setStartValue(QRect(250, 150, 100, 30)) animation2.setEndValue(QRect(850, 250, 100, 30)) animation2.setEasingCurve(QEasingCurve.CosineCurve)group.start()sys.exit(app.exec())?課時134 用PyInstaller打包PyQt5應用
安裝:pip3 install pyinstaller
代碼:
直接在命令行下操作
常用:pyinstaller -Fw python文件名
pyinstaller -Fw Calc. py
-W:不顯示終端
-F:將所有的庫打包成-個單獨的文件
?pip3 install pyinstaller安裝
使用pyinstaller查看可選參數
開始打包????? pyinstaller -Fw .\ScaleImage.py
打包程序完成
打包成功后項目目錄下多了兩個文件夾,包括build和dist。exe文件就存在于dist目錄下。將文件中調用的文件手動放到exe同目錄下。雙擊exe文件運行即可!
課時135 操作SQLite數據庫
#輕量級數據庫,支持多種接口,跨平臺
#現在很多移動應用 安卓 iOS 都使用SQLite作為本地數據庫
#本地數據庫只需要提供文件名,而不需要IP,用戶名,密碼啥的
#數據庫可視化工具DB Browser for SQLite:
#官網:DB Browser for SQLite
#下載:Downloads - DB Browser for SQLite
?右鍵運行生成數據庫db文件
?
課時136 使用可視化的方式對SQLite數據庫進行增刪改查操作
QTableView
QSql TableModel
?
# @CSDN王家視頻教程圖書館 # @Time 2022/11/25 0:27 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtSql import *# 初始化 def initializeModel(model):model.setTable('people')# 當字段變化時會觸發一些事件model.setEditStrategy(QSqlTableModel.OnFieldChange)# 將整個數據裝載到model中model.select()# 設置字段頭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 viewdef findrow(i):# 當前選中的行delrow = i.row()print('del row=%s' % str(delrow))def addrow():# 不是在QTableView上添加,而是在模型上添加,會自動將數據保存到數據庫中!# 參數一:數據庫共有幾行數據 參數二:添加幾行ret = model.insertRows(model.rowCount(), 1) # 返回是否插入print('數據庫共有%d行數據' % model.rowCount())print('insertRow=%s' % str(ret))if __name__ == '__main__':app = QApplication(sys.argv)db = QSqlDatabase.addDatabase('QSQLITE')db.setDatabaseName('./db1.db')model = QSqlTableModel() # MVC模式中的模型delrow = -1# 初始化將數據裝載到模型當中initializeModel(model)view = createView("展示數據", model)view.clicked.connect(findrow)dlg = QDialog()layout = QVBoxLayout()layout.addWidget(view)addBtn = QPushButton('添加一行')addBtn.clicked.connect(addrow)delBtn = QPushButton('刪除一行')delBtn.clicked.connect(lambda: model.removeRow(view.currentIndex().row()))layout.addWidget(view)layout.addWidget(addBtn)layout.addWidget(delBtn)dlg.setLayout(layout)dlg.setWindowTitle("Database Demo")dlg.resize(500, 400)dlg.show()sys.exit(app.exec())課時137 分頁顯示數據
limit關鍵字
limit n,m
n是起始點(不含),m是偏移量,例如 limit 10,20代表從11開始的20條數據,即11-30
# @CSDN王家視頻教程圖書館 # @Time 2022/11/25 0:58 import sys from PyQt5.QtWidgets import * from PyQt5.QtCore import Qt from PyQt5.QtSql import *class DataGrid(QWidget):def createTableAndInit(self):# 添加數據庫self.db = QSqlDatabase.addDatabase('QSQLITE')# 設置數據庫名稱self.db.setDatabaseName('./database.db')# 判斷是否打開if not self.db.open():return False# 聲明數據庫查詢對象query = QSqlQuery()# 創建表query.exec("create table student(id int primary key, name vchar, sex vchar, age int, deparment vchar)")# 添加記錄query.exec("insert into student values(1,'張三1','男',20,'計算機')")query.exec("insert into student values(2,'李四1','男',19,'經管')")query.exec("insert into student values(3,'王五1','男',22,'機械')")query.exec("insert into student values(4,'趙六1','男',21,'法律')")query.exec("insert into student values(5,'小明1','男',20,'英語')")query.exec("insert into student values(6,'小李1','女',19,'計算機')")query.exec("insert into student values(7,'小張1','男',20,'機械')")query.exec("insert into student values(8,'小剛1','男',19,'經管')")query.exec("insert into student values(9,'張三2','男',21,'計算機')")query.exec("insert into student values(10,'張三3','女',20,'法律')")query.exec("insert into student values(11,'王五2','男',19,'經管')")query.exec("insert into student values(12,'張三4','男',20,'計算機')")query.exec("insert into student values(13,'小李2','男',20,'機械')")query.exec("insert into student values(14,'李四2','女',19,'經管')")query.exec("insert into student values(15,'趙六3','男',21,'英語')")query.exec("insert into student values(16,'李四2','男',19,'法律')")query.exec("insert into student values(17,'小張2','女',22,'經管')")query.exec("insert into student values(18,'李四3','男',21,'英語')")query.exec("insert into student values(19,'小李3','女',19,'法律')")query.exec("insert into student values(20,'王五3','女',20,'機械')")query.exec("insert into student values(21,'張三4','男',22,'計算機')")query.exec("insert into student values(22,'小李2','男',20,'法律')")query.exec("insert into student values(23,'張三5','男',19,'經管')")query.exec("insert into student values(24,'小張3','女',20,'計算機')")query.exec("insert into student values(25,'李四4','男',22,'英語')")query.exec("insert into student values(26,'趙六2','男',20,'機械')")query.exec("insert into student values(27,'小李3','女',19,'英語')")query.exec("insert into student values(28,'王五4','男',21,'經管')")return Truedef __init__(self):super().__init__()self.setWindowTitle("分頁查詢例子")self.resize(750, 350)self.createTableAndInit()# 當前頁self.currentPage = 0# 總頁數self.totalPage = 0# 總記錄數self.totalRecrodCount = 0# 每頁顯示記錄數self.PageRecordCount = 6self.initUI()def initUI(self):# 創建窗口self.createWindow()# 設置表格self.setTableView()# 信號槽連接self.prevButton.clicked.connect(self.onPrevButtonClick)self.nextButton.clicked.connect(self.onNextButtonClick)self.switchPageButton.clicked.connect(self.onSwitchPageButtonClick)def closeEvent(self, event):# 關閉數據庫self.db.close()# 創建窗口def createWindow(self):# 操作布局operatorLayout = QHBoxLayout()self.prevButton = QPushButton("前一頁")self.nextButton = QPushButton("后一頁")self.switchPageButton = QPushButton("Go")self.switchPageLineEdit = QLineEdit()self.switchPageLineEdit.setFixedWidth(40)switchPage = QLabel("轉到第")page = QLabel("頁")operatorLayout.addWidget(self.prevButton)operatorLayout.addWidget(self.nextButton)operatorLayout.addWidget(switchPage)operatorLayout.addWidget(self.switchPageLineEdit)operatorLayout.addWidget(page)operatorLayout.addWidget(self.switchPageButton)operatorLayout.addWidget(QSplitter())# 狀態布局statusLayout = QHBoxLayout()self.totalPageLabel = QLabel()self.totalPageLabel.setFixedWidth(70)self.currentPageLabel = QLabel()self.currentPageLabel.setFixedWidth(70)self.totalRecordLabel = QLabel()self.totalRecordLabel.setFixedWidth(70)statusLayout.addWidget(self.totalPageLabel)statusLayout.addWidget(self.currentPageLabel)statusLayout.addWidget(QSplitter())statusLayout.addWidget(self.totalRecordLabel)# 設置表格屬性self.tableView = QTableView()# 表格寬度的自適應調整self.tableView.horizontalHeader().setStretchLastSection(True)self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)# 創建界面mainLayout = QVBoxLayout(self);mainLayout.addLayout(operatorLayout);mainLayout.addWidget(self.tableView);mainLayout.addLayout(statusLayout);self.setLayout(mainLayout)# 設置表格def setTableView(self):# 聲明查詢模型self.queryModel = QSqlQueryModel(self)# 設置當前頁self.currentPage = 1;# 得到總記錄數self.totalRecrodCount = self.getTotalRecordCount()# 得到總頁數self.totalPage = self.getPageCount()# 刷新狀態self.updateStatus()# 設置總頁數文本self.setTotalPageLabel()# 設置總記錄數self.setTotalRecordLabel()# 記錄查詢self.recordQuery(0)# 設置模型self.tableView.setModel(self.queryModel)print('totalRecrodCount=' + str(self.totalRecrodCount))print('totalPage=' + str(self.totalPage))# 設置表格表頭self.queryModel.setHeaderData(0, Qt.Horizontal, "編號")self.queryModel.setHeaderData(1, Qt.Horizontal, "姓名")self.queryModel.setHeaderData(2, Qt.Horizontal, "性別")self.queryModel.setHeaderData(3, Qt.Horizontal, "年齡")self.queryModel.setHeaderData(4, Qt.Horizontal, "院系")# 得到記錄數def getTotalRecordCount(self):self.queryModel.setQuery("select * from student")rowCount = self.queryModel.rowCount()print('rowCount=' + str(rowCount))return rowCount# 得到頁數def getPageCount(self):if self.totalRecrodCount % self.PageRecordCount == 0:return (self.totalRecrodCount / self.PageRecordCount)else:return (self.totalRecrodCount / self.PageRecordCount + 1)# 記錄查詢def recordQuery(self, limitIndex):szQuery = ("select * from student limit %d,%d" % (limitIndex, self.PageRecordCount))print('query sql=' + szQuery)self.queryModel.setQuery(szQuery)# 刷新狀態def updateStatus(self):szCurrentText = ("當前第%d頁" % self.currentPage)self.currentPageLabel.setText(szCurrentText)# 設置按鈕是否可用if self.currentPage == 1:self.prevButton.setEnabled(False)self.nextButton.setEnabled(True)elif self.currentPage == self.totalPage:self.prevButton.setEnabled(True)self.nextButton.setEnabled(False)else:self.prevButton.setEnabled(True)self.nextButton.setEnabled(True)# 設置總數頁文本def setTotalPageLabel(self):szPageCountText = ("總共%d頁" % self.totalPage)self.totalPageLabel.setText(szPageCountText)# 設置總記錄數def setTotalRecordLabel(self):szTotalRecordText = ("共%d條" % self.totalRecrodCount)print('*** setTotalRecordLabel szTotalRecordText=' + szTotalRecordText)self.totalRecordLabel.setText(szTotalRecordText)# 前一頁按鈕按下def onPrevButtonClick(self):print('*** onPrevButtonClick ');limitIndex = (self.currentPage - 2) * self.PageRecordCountself.recordQuery(limitIndex)self.currentPage -= 1self.updateStatus()# 后一頁按鈕按下def onNextButtonClick(self):print('*** onNextButtonClick ');limitIndex = self.currentPage * self.PageRecordCountself.recordQuery(limitIndex)self.currentPage += 1self.updateStatus()# 轉到頁按鈕按下def onSwitchPageButtonClick(self):# 得到輸入字符串szText = self.switchPageLineEdit.text()# 得到頁數pageIndex = int(szText)# 判斷是否有指定頁if pageIndex > self.totalPage or pageIndex < 1:QMessageBox.information(self, "提示", "沒有指定的頁面,請重新輸入")return# 得到查詢起始行號limitIndex = (pageIndex - 1) * self.PageRecordCount# 記錄查詢self.recordQuery(limitIndex);# 設置當前頁self.currentPage = pageIndex# 刷新狀態self.updateStatus();if __name__ == '__main__':app = QApplication(sys.argv)# 創建窗口example = DataGrid()# 顯示窗口example.show()sys.exit(app.exec_())?課時138 使用PyQtGraph進行數據可視化
首先安裝 pip3 install pyqtgraph
?右鍵運行報錯 暫未解決!
pyqtgraph_pyqt.py
# @CSDN王家視頻教程圖書館 # @Time 2022/11/25 1:15 # -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'pyqtgraph_pyqt.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, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(800, 600)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.pyqtgraph1 = GraphicsLayoutWidget(self.centralwidget)self.pyqtgraph1.setGeometry(QtCore.QRect(10, 10, 721, 251))self.pyqtgraph1.setObjectName("pyqtgraph1")self.pyqtgraph2 = GraphicsLayoutWidget(self.centralwidget)self.pyqtgraph2.setGeometry(QtCore.QRect(10, 290, 501, 281))self.pyqtgraph2.setObjectName("pyqtgraph2")MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))from pyqtgraph import GraphicsLayoutWidgetGraph.py
# @CSDN王家視頻教程圖書館 # @Time 2022/11/25 1:16 ''' 使用PyQtGraph繪圖 pip Install pyqtgraph '''from PyQt5.QtCore import pyqtSlot from PyQt5.QtWidgets import QMainWindow, QApplication import pyqtgraph as pg from pyqtgraph_pyqt import Ui_MainWindow import numpy as npclass MainWindow(QMainWindow, Ui_MainWindow):def __init__(self, parent=None):super(MainWindow, self).__init__(parent)pg.setConfigOption('background', '#f0f0f0')pg.setConfigOption('foreground', 'd')self.setupUi(self)self.draw1()self.draw2()def draw1(self):self.pyqtgraph1.clear()'''第一種繪圖方式'''print(np.random.normal(size=120))self.pyqtgraph1.addPlot(title="繪圖單條線", y=np.random.normal(size=120), pen=pg.mkPen(color='b', width=2))'''第二種繪圖方式'''plt2 = self.pyqtgraph1.addPlot(title='繪制多條線')plt2.plot(np.random.normal(size=150), pen=pg.mkPen(color='r', width=2),name="Red curve")plt2.plot(np.random.normal(size=110) + 5, pen=(0, 255, 0), name="Green curve")plt2.plot(np.random.normal(size=120) + 10, pen=(0, 0, 255), name="Blue curve")def draw2(self):plt = self.pyqtgraph2.addPlot(title='繪制條狀圖')x = np.arange(10)print(x)y1 = np.sin(x)y2 = 1.1 * np.sin(x + 1)y3 = 1.2 * np.sin(x + 2)bg1 = pg.BarGraphItem(x=x, height=y1, width=0.3, brush='r')bg2 = pg.BarGraphItem(x=x + 0.33, height=y2, width=0.3, brush='g')bg3 = pg.BarGraphItem(x=x + 0.66, height=y3, width=0.3, brush='b')plt.addItem(bg1)plt.addItem(bg2)plt.addItem(bg3)self.pyqtgraph2.nextRow()p4 = self.pyqtgraph2.addPlot(title="參數圖+顯示網格")x = np.cos(np.linspace(0, 2 * np.pi, 1000))y = np.sin(np.linspace(0, 4 * np.pi, 1000))p4.plot(x, y, pen=pg.mkPen(color='d', width=2))# p4.showGrid(x=True, y=True) # 顯示網格if __name__ == "__main__":import sysapp = QApplication(sys.argv)ui = MainWindow()ui.show()sys.exit(app.exec_())總結
以上是生活随笔為你收集整理的python【PyQt5】的环境搭建和使用(全网最全)其一的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: css改变鼠标图片大小,CSS实现鼠标经
- 下一篇: 惊叹!中科院学霸和本硕博985在读博士的