PyQt5庫(一)
一、 簡介
1、 什麼是 Qt
使用 C++ 語言編寫的跨平臺 GUI 庫,支援Windows 、MacOS和Linux。由於 Qt 使用C++語言編寫,所以使用Qt開發的GUI程式的介面風格與當前作業系統完全相同,而且執行效率很高
2、 什麼是PyQt
PyQt實現了一個Python模組集。它有超過300類,將近6000個函式和方法。它是一個多平臺的工具包,可以執行在所有主要作業系統上,包括UNIX,Windows和Mac。 PyQt採用雙許可證,開發人員可以選擇GPL和商業許可。在此之前,GPL的版本只能用在Unix上,從PyQt的版本4開始,GPL許可證可用於所有支援的平臺 ,同時Qt能實現的功能PyQt都能實現
3、 環境搭建
安裝 PyQt5
pip install pyqt5
官方文件:【https://www.riverbankcomputing.com/static/Docs/PyQt5/sip-classes.html】
二、 基本結構
1、 第一個程式
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, qApp
import sys
# 建立一個應用程式
# sys.argv 當別人通過命令列執行這個程式的時候,可以設定一種功能(接收命令列傳遞的引數)
app = QApplication(sys.argv)
print(app.arguments()) # 得到命令列的引數
print(qApp.arguments()) # qApp為全域性變數
# 建立一個視窗
w = QWidget()
# 視窗尺寸
w.resize(300, 150)
# 移動視窗,視窗左上角的座標
w.move(300, 300)
# 設定視窗的標題
w.setWindowTitle("第一個基於pyqt5的桌面應用")
# 設定標籤
label = QLabel(w)
label.setText("hello world")
label.move(150, 75)
# 顯示視窗
w.show()
# 進入程式的訊息迴圈,並通過exit函式確保主迴圈安全結束,相當於無限迴圈
# 檢測整個程式所接收到的使用者互動資訊
sys.exit(app.exec_())
2、 控制元件操作
步驟:
-
建立控制元件
-
# 設定標籤 label = QLabel(contain)
引數:
- contain:代表要在哪個控制元件(容器)上面展示,可以為空
當我們建立一個控制元件之後,如果說,這個控制元件沒有父控制元件,則把它當作頂層控制元件(視窗)
-
-
設定控制元件
- 大小,樣式,位置,樣式等
- 頂層控制元件有許可權去設定視窗內容,結構等
-
展示控制元件
- 當控制元件沒有父控制元件時,要使用 show 方法去展示控制元件
3、 快速生成程式碼
在pycharm中的活動模板配置如下程式碼,快速生成程式碼
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("$test$") # 設定標題
self.resize($500$, $500$) # 設定視窗大小
self.move($300$, $300$) # 移動視窗
self.setup_ui() # 呼叫建立控制元件的方法
def setup_ui(self): # 新增控制元件的操作
pass
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗
w = Window()
# 顯示視窗
w.show()
sys.exit(app.exec_())
4、 物件導向
提高程式碼的可維護性
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
class Window(QWidget):
def __init__(self):
super(Window, self).__init__()
self.setWindowTitle("Hello") # 設定標題
self.resize(300, 150) # 設定視窗大小
self.move(300, 300) # 移動視窗
self.setup_label() # 呼叫建立控制元件的方法
def setup_label(self): # 新增控制元件的操作
label = QLabel(self)
label.setText("Hello World")
label.move(150, 75)
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗
w = Window()
# 顯示視窗
w.show()
sys.exit(app.exec_())
三、 基類控制元件
什麼是控制元件?
- 一個程式介面上的各個獨立的標準,一塊矩形區域
- 每類控制元件都具備不同的功能
- 同時,有些控制元件有相似的功能,可以通過繼承關係學習
1、 QObject
1.1 設定標識
1.1.1 語法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.Qt import *
obj = QObject(self)
obj.setObjectName("notice") # 設定Qt物件名稱
print(obj.objectName()) # 獲得Qt物件名稱
obj.setProperty("notice_l", "error") # 設定物件的屬性
obj.setProperty("notice_l2", "warning")
print(obj.property("notice_l")) # 獲得一個物件的屬性值
print(obj.dynamicPropertyNames()) # 獲取一個物件中所有通過setProperty設定的屬性名稱
1.1.2 應用場景
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
# @file: Demo.py
# @time: 2022/3/28 9:20
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("QObject") # 設定標題
self.resize(500, 300) # 設定視窗大小
self.move(500, 500) # 移動視窗
self.setup_ui() # 呼叫建立控制元件的方法
def setup_ui(self): # 新增控制元件的操作
self.qObject_ui()
def qObject_ui(self): # 所有類的基類
# 案例演示
label = QLabel(self) # 建立標籤
label.setText("Hello") # 設定標籤內容
label.setObjectName("notice") # id 為 notice
label.setProperty("level", "error") # 屬性選擇器
with open("QStyle.qss", "r") as f:
"""
檔案內容為:
QLabel#notice[level='error'] {
font-size: 20px;
color: blue;
}
"""
qApp.setStyleSheet(f.read())
# label.setStyleSheet("font-size: 20px; color: blue;")
# qss 樣式表,相當於前端的 css 樣式表,可以將其放入一個 `.qss` 的檔案中,方便分離和讀取,同時,所有符合條件的內容都會變成相應的樣式
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗
w = Window()
# 顯示視窗
w.show()
sys.exit(app.exec_())
1.3 父子物件
1.3.1 語法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj2.setParent(obj1) # 設定父子關係
obj3.setObjectName("2") # 設定id
obj3.setParent(obj2)
print(obj1, obj2.parent()) # 獲取父類,返回記憶體地址
print(obj2, obj1.children()) # 獲取所有直系子物件
print(obj1.findChild(QObject)) # 獲取後代,遞迴查詢,只返回一個
print(obj1.findChild(QObject, "2")) # 獲取id為2的後代,只返回一個
print(obj1.findChildren(QObject)) # 獲取符合條件的所有後代
1.3.2 應用場景
記憶體管理機制,父控制元件刪除,那麼子控制元件也會自動刪除
- 按鈕和對話方塊本身是父子控制元件關係
- 當對話方塊被刪除時,內部的子控制元件也會自動刪除——非常合理
- 我們操作的時候,是操作的對話方塊控制元件本身,而不是內部的子控制元件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
obj1 = QObject()
obj2 = QObject()
obj1.setParent(obj2)
# 監聽 obj2 物件被釋放
obj2.destroyed.connect(lambda: print("obj2,被釋放"))
print("刪除父物件")
del obj1
print("刪除完成")
如果一個控制元件,沒有任何父控制元件,那麼就會被當成頂層控制元件——多個頂層視窗相互獨立
如果想要一個控制元件被包含在另外一個控制元件內部,就需要設定父子關係
- 顯示位置受父控制元件約束
- 生命週期也被符物件接管
案例:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
win1 = QWidget()
win1.setStyleSheet("background-color: blue;")
win1.setWindowTitle("blue")
win1.resize(500, 500)
win1.show()
win2 = QWidget(win1)
win2.setStyleSheet("background-color: red;")
win2.setWindowTitle("red")
win2.resize(100, 100)
# win2.setParent(win1) # win1 為父物件,win2 = QWidget(win1) 效果一樣
win2.show()
l1 = QLabel()
b1 = QPushButton()
l1.setParent(win1)
b1.setParent(win1)
l1.setText("label")
b1.setText("button")
l1.move(200, 200)
b1.move(300, 200)
l2 = QLabel()
l2.setParent(win1)
l2.setText("Label")
l2.move(100, 200)
# 遍歷設定樣式
for i in win1.findChildren(QLabel):
i.setStyleSheet("color: green;")
l1.show()
b1.show()
l2.show()
sys.exit(app.exec_())
1.4 訊號操作
1.4.1 訊號與槽機制
訊號和槽是Qt中的核心機制,主要作用在於物件之間進行通訊
- 當達到某個條件時,執行某個操作
訊號(widget):
- 當一個控制元件的狀態發生改變時,向外發出資訊
槽(connect):
- 一個執行某些操作的函式/方法
所有繼承自 QWidget 的控制元件都支援訊號與槽機制
1.4.2 機制描述
手動操作:
- 訊號和槽相關聯
自動操作:
- 當訊號發出時,連線槽函式會自動執行
1.4.3 訊號處理
訊號:
objectNameChange(objectName)
:物件名稱發生改變時,發射此訊號destroyed(obj)
:物件被銷燬時,發射訊號blockSignals(True)
:臨時阻斷連線receivers(widget)
:檢視當前訊號連線了多少個槽
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
def destroy():
print("物件被摧毀")
obj1 = QObject()
obj2 = QObject()
obj1.setParent(obj2)
# obj.destroyed
obj1.destroyed.connect(lambda: destroy())
# obj.objectNameChanged
obj1.objectNameChanged.connect(lambda name: print("物件名稱被改變: " + name))
obj1.setObjectName("xxx")
# obj1.objectNameChanged.disconnect() # 斷開槽與訊號的連線
obj1.blockSignals(True) # 臨時阻斷連線
obj1.setObjectName("1")
print("連線數量:" + str(obj1.receivers(obj1.objectNameChanged))) # 檢視有多少個槽連線這個訊號
obj1.blockSignals(False) # 再次開啟連線
obj1.objectNameChanged.connect(lambda name: print("第二個連線:" + name))
print("連線數量:" + str(obj1.receivers(obj1.objectNameChanged))) # 檢視有多少個槽連線這個訊號
obj1.setObjectName("2")
del obj2
1.4.4 案例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("test") # 設定標題
self.resize(300, 300) # 設定視窗大小
self.move(200, 300) # 移動視窗
self.setup_ui() # 呼叫建立控制元件的方法
def ret():
print("標題變化了")
# self.windowTitleChanged.disconnect() # 斷開槽與訊號的關係
self.blockSignals(True) # 臨時斷開連線也行
self.windowTitleChanged.connect(ret)
def setup_ui(self): # 新增控制元件的操作
self.btn() # 新增按鈕
def btn(self):
b = QPushButton(self)
b.setText("點選我")
def ret():
self.setWindowTitle("hello")
b.clicked.connect(ret)
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗
w = Window()
# 顯示視窗
w.show()
sys.exit(app.exec_())
1.5 型別判定
1.5.1 語法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
obj = QObject(w)
w1 = QWidget(w)
l = QLabel(w)
print(w.isWidgetType()) # 判斷是繼承控制元件型別
print(obj.isWidgetType()) # 判斷是否繼承控制元件型別
print(l.isWidgetType()) # 判斷是否繼承控制元件型別
print(w.inherits("QWidget")) # 判斷是否繼承控制元件型別
print(obj.inherits("QLabel")) # 判斷是否繼承標籤型別
print(l.inherits("QLabel")) # 判斷是否繼承標籤型別
sys.exit(app.exec_())
1.5.2 案例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("test") # 設定標題
self.resize(500, 500) # 設定視窗大小
self.move(300, 300) # 移動視窗
self.setup_ui() # 呼叫建立控制元件的方法
def setup_ui(self): # 新增控制元件的操作
l = QLabel(self)
l.setText("first")
l.move(100, 100)
l2 = QLabel(self)
l2.setText("second")
l2.move(200, 100)
btn = QPushButton(self)
btn.setText("點我")
btn.move(300, 100)
for i in self.findChildren(QWidget):
if i.inherits("QLabel"): # 如果為 label 型別,修改樣式
i.setStyleSheet("color: red; font-size: 20px")
else:
i.setStyleSheet("color: blue; font-size: 20px")
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗
w = Window()
# 顯示視窗
w.show()
sys.exit(app.exec_())
1.6 物件刪除
1.6.1 語法
刪除一個物件時,也會解除它與父物件之間的關係
obj.deleteLater()
:其並沒有將物件立即銷燬,而是向主訊息迴圈傳送了一個event,下一次主訊息迴圈收到這個event之後才會銷燬物件- 這樣做的好處是可以在這些延遲刪除的時間裡面完成一些操作;壞處是記憶體釋放會不及時
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
obj1 = QObject()
obj2 = QObject()
obj3 = QObject()
obj3.setParent(obj2)
obj2.setParent(obj1)
obj1.destroyed.connect(lambda: print("obj1被釋放"))
obj2.destroyed.connect(lambda: print("obj2被釋放"))
obj3.destroyed.connect(lambda: print("obj3被釋放"))
# obj1.deleteLater()
obj2.deleteLater() # 等下一個迴圈開始時才會真正釋放
# del obj2 # 直接刪除,但是這是把變數和物件的關聯替換了,使得系統無法訪問物件,不是真的刪除
print(obj1)
w.show()
sys.exit(app.exec_())
1.7 事件處理
訊號與槽機制是對事件機制的高階封裝
事件機制更偏離底層
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
class App(QApplication):
def notify(self, rev, evt):
if rev.inherits("QPushButton") and evt.type() == QEvent.MouseButtonPress: # 過濾器,只檢視按鈕事件,並且只檢視滑鼠點選事件
print("底層執行原理:")
print(rev, evt)
return super().notify(rev, evt) # 分發事件
class Btn(QPushButton):
def event(self, evt):
if evt.type() == QEvent.MouseButtonPress: # 事件過濾
print("按鈕點選了", evt) # 裡面很多事件
return super().event(evt)
def mousePressEvent(self, evt):
print("滑鼠被點選了。。。。。。。。。。") # 如果只有這行程式碼的話,沒有執行訊號與槽的操作
return super().mousePressEvent(evt)
app = App(sys.argv)
w = QWidget()
btn = Btn(w)
btn.setText("按鈕")
btn.move(100, 100)
btn.pressed.connect(lambda: print("按鈕被按下"))
btn.clicked.connect(lambda: print("按鈕被點選"))
btn.released.connect(lambda: print("按鈕被鬆開"))
w.show()
sys.exit(app.exec_())
1.8 定時器操作
1.8.1 語法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
class MyObject(QObject):
def timerEvent(self, evt):
print(evt, "1") # 每個1秒列印
return super().timerEvent(evt)
app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle("定時器")
w.resize(500, 500)
obj = MyObject()
t_id = obj.startTimer(1000) # 1秒執行一次,通過繼承的方法來啟動計時器
obj.killTimer(t_id) # 關閉定時器
w.show()
sys.exit(app.exec_())
1.8.2 應用場景
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
class MyLabel(QLabel):
def __init__(self, sec, *args, **kwargs): # 使用不定長引數傳參
super().__init__(*args, **kwargs)
self.move(20, 20)
self.setText(sec)
self.setStyleSheet("font-size: 20px; color: red;")
self.t_id = self.startTimer(1000) # 1秒執行一次,通過繼承的方法來啟動計時器
def timerEvent(self, evt):
# 倒數計時原理
sec = int(self.text())
sec -= 1
self.setText(str(sec))
if (sec == 0):
self.killTimer(self.t_id) # 關閉定時器
class MyQWidget(QWidget):
def __init__(self, *args, **kwargs):
super(MyQWidget, self).__init__(*args, **kwargs)
self.setWindowTitle("定時器")
self.resize(500, 500)
self.startTimer(1000) # 動畫
def timerEvent(self, evt):
current_w, current_h = self.width(), self.height()
if current_w > 1000 and current_h > 1000:
current_w -= 20
current_h -= 20
elif current_h < 1000 and current_w < 1000:
current_w += 20
current_h += 20
self.resize(current_w, current_h)
app = QApplication(sys.argv)
w = MyQWidget()
MyLabel("10", w) # 同時,10秒倒數計時
w.show()
sys.exit(app.exec_())
2、 QWidget
2.1 簡介
介紹
-
其為所有可視控制元件的基類
-
是一個最簡單的空白控制元件
-
控制元件是使用者介面的最小元素
- 接收各種事件(滑鼠、鍵盤等)
- 繪製在桌面上面,展示給使用者看
-
每個控制元件都是矩形的,它們按Z軸順序排序
-
控制元件由其父控制元件和前面的控制元件剪下
-
沒有父控制元件的控制元件稱之為視窗
2.2 繼承
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
print(QWidget.__bases__) # 直系父類
print(QWidget.mro()) # 所有父類,祖宗類
父類幾乎所有的方法,子類都可以使用
2.3 控制元件建立
語法:
w = QWidget(parent) # 如果沒有父類,可以不用填寫
2.4 大小位置
2.4.1 獲取
控制元件的座標系統:
- 以左上角為座標原點,縱軸為垂直方向,橫軸為水平方向
獲取位置:
(x(), y()) / pos()
:- 相對於父控制元件的位置,包含視窗框架;頂層控制元件則相對於桌面的位置
QPoint(x, y)
(width(), height()) / size()
:- 控制元件的寬度和高度,不包含視窗框架
QSize(width, height)
geometry()
:- 使用者區域相對於父控制元件的位置和尺寸的組合,不包含視窗框架
QRect(x, y, width, height)
rect()
:- 控制元件尺寸的組合,不包含視窗框架
QRect(0, 0, width, height)
frameSize()
:- 框架大小
frameGeometry()
:- 框架位置和尺寸
- 注意:
- 控制元件顯示完畢之後,具體位置或者尺寸資料才會正確
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.move(100, 100)
w.resize(200, 200)
w.show()
# 桌面顯示後獲取的資料才準確
print(w.x())
print(w.width())
print(w.geometry())
print(w.rect())
print(w.frameSize())
print(w.frameGeometry())
sys.exit(app.exec_())
2.4.2 設定
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
move(x, y) 操作的是 x, y 也就是 pos,包含視窗框架
resize(width, height) 操作的是寬高:不包含視窗框架
setGeometry(x_noFrame, y_noFrame, width, height) 此處參照為使用者區域,即不包含框架
adjustSize() 根據內容自適應大小
setFixedSize() 設定固定尺寸
"""
app = QApplication(sys.argv)
w = QWidget()
"""
w.move(100, 100)
w.resize(200, 200)
# 下面這行程式碼和上面兩行程式碼的作用類似
w.setGeometry(100, 100, 200, 200)
"""
w.setFixedSize(500, 500) # 不可以修改它的大小
w.show()
sys.exit(app.exec_())
2.5 尺寸最值
2.5.1 獲取
獲取:
(minimumWidth(), minimumHeight()) / minimumSize()
- 最小尺寸
(maximumWidth(), msximumHeight()) / maximumSize()
- 最大尺寸
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
w.show()
print(w.minimumSize()) # 得到最小尺寸
print(w.maximumSize()) # 得到最大尺寸
sys.exit(app.exec_())
2.5.2 設定
設定最大最小尺寸
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
w.setMaximumWidth(1000) # 限定最大寬度
w.setMaximumHeight(1000) # 限定最大高度
w.setMaximumSize(1000, 1000) # 限定最大寬度和高度
w.setMinimumSize(100, 100) # 限定最小寬度和高度
w.setMinimumWidth(100) # 限定最小寬度
w.setMinimumHeight(100) # 限定最小高度
w.show()
sys.exit(app.exec_())
限定最值尺寸後,如果修改後的尺寸超過這個最值,最終大小為最值大小
2.6 內容邊距
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
l = QLabel(w)
l.setText("Hello World")
l.setStyleSheet("background-color: red; font-size: 20px; font-weight: 500;")
l.resize(300, 300)
l.setContentsMargins(110, 0, 0, 0) # 設定內容外邊距
print(l.contentsRect().getRect()) # 得到內容區域
print(l.getContentsMargins()) # 得到內容外邊距
w.show()
sys.exit(app.exec_())
必須是控制元件本身有足夠空間
2.7 滑鼠相關
2.7.1 設定滑鼠形狀
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
pixmap = QPixmap(r"D:\35005\Pictures\Screenshots\微信圖片_20220302175157.jpg") # 傳入圖片設定滑鼠圖示
pixmap_new = pixmap.scaled(50, 50) # 輸入縮放的尺寸
cursor = QCursor(pixmap_new) # 例項化滑鼠物件
# w.setCursor(Qt.BusyCursor) # 設定滑鼠形狀,引數裡面輸入滑鼠樣式
w.setCursor(cursor, 0, 0) # 也可以傳入一個滑鼠物件,後面的數字傳入的意思是以左上角為標準
w.unsetCursor() # 取消設定滑鼠的形狀
w.show()
sys.exit(app.exec_())
常見的滑鼠樣式查詢:https://www.riverbankcomputing.com/static/Docs/PyQt5/api/qtcore/qt.html#CursorShape
如果滑鼠進入了控制元件的範圍內,形狀發生變化
2.7.2 重置滑鼠形狀
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
current_cursor = w.cursor() # 獲取滑鼠物件
print(current_cursor.pos()) # 獲得滑鼠相對於電腦螢幕的位置座標
current_cursor.setPos(10, 10) # 設定滑鼠的位置
w.show()
sys.exit(app.exec_())
2.7.3 滑鼠跟蹤
所謂的滑鼠跟蹤,其實就是設定檢測滑鼠移動事件的條件
滑鼠跟蹤:
- 滑鼠移動時,不處於按下狀態,也會觸發 mouseMoveEvent 事件
滑鼠不跟蹤:
- 滑鼠移動時,必須處於按下狀態,才會觸發 mouseMoveEvent 事件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
class MyWidget(QWidget):
def mouseMoveEvent(self, me):
print("滑鼠移動了", me.localPos()) # 當不跟蹤時,滑鼠要按下才會觸發
# me.pos()和 me.localPos() 得到滑鼠相對於控制元件的位置
app = QApplication(sys.argv)
w = MyWidget()
w.setWindowTitle("滑鼠事件")
w.resize(500, 500)
w.setMouseTracking(True) # 開啟滑鼠跟蹤
print(w.hasMouseTracking()) # 判定是否開啟滑鼠跟蹤
w.show()
sys.exit(app.exec_())
2.7.4 案例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
# 滑鼠按下移動標籤
class MyWidget(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.resize(500, 500)
self.setWindowTitle("滑鼠事件案例")
self.label = QLabel(self)
self.setup_ui()
def mouseMoveEvent(self, me):
x, y = me.x(), me.y()
self.label.move(x, y)
def setup_ui(self):
self.label.resize(100, 100)
self.label.setText("按住我!")
self.label.setStyleSheet("background-color: green; font-weight: bold;")
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyWidget()
w.show()
sys.exit(app.exec_())
2.8 事件
2.8.1 API
顯示和關閉事件:
showEvent(QShowEvent) # 控制元件顯示是呼叫
closeEvent(QCloseEvent) # 控制元件關閉時呼叫
移動事件:
moveEvent(QMoveEvent) # 控制元件移動時呼叫
調整大小事件:
resizeEvent(QResizeEvent) # 控制元件大小改變時呼叫
滑鼠事件:
enterEvent(QEvent) # 滑鼠進入時觸發
leaveEvent(QEvent) # 滑鼠離開時觸發
mousePressEvent(QMouseEvent) # 滑鼠按下時觸發
mouseReleaseEvent(QMouseEvent) # 滑鼠按下時觸發
mouseDoubleClickEvent(QMouseEvent) # 滑鼠雙擊時觸發
mouseMoveEvent(QMouseEvent) # 滑鼠按下後移動時觸發,設定追蹤後,沒按下也能觸發
鍵盤事件:
keyPressEvent(QKeyEvent) # 鍵盤按下時使用
keyReleaseEvent(QKeyEvent) # 鍵盤松開時使用
焦點事件:
focusInEvent(QFocusEvent) # 獲得焦點
focuseOutEvent(QFocusEvent) # 失去焦點
拖拽事件:
dragEnterEvent(QDragEnterEvent) # 拖拽進入控制元件時使用
dragLeaveEvent(QDragLeaveEvent) # 拖拽離開控制元件時使用
dragMoveEvent(QDragMoveEvent) # 拖拽在控制元件內移動時使用
dropEvent(QDropEvent) # 拖拽放下時使用
繪製事件:
paintEvent(QPaintEvent) # 顯示控制元件,更新控制元件時使用
改變事件:
changeEvent(QEvent) # 窗體改變,字型改變時呼叫
右鍵選單:
contextMenuEvent(QContextMenuEvent) # 訪問右鍵選單時使用
輸入法:
inputMethodEvent(QInputMethodEvent) # 輸入法切換呼叫
當一個控制元件被觸發了一個特定的行為時,就會呼叫特定的方法,來將事件傳遞給開發人員,方便處理
重寫事件方法,就可以監聽相關的資訊
2.8.2 示例
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("test") # 設定標題
self.resize(500, 500) # 設定視窗大小
self.move(100, 100) # 移動視窗
def showEvent(self, ev):
print("視窗被展示了出來", ev)
def closeEvent(self, ev):
print("視窗關閉", ev)
def moveEvent(self, ev):
print("視窗移動", ev.pos())
def resizeEvent(self, ev):
print("控制元件大小改變", ev.size())
def enterEvent(self, ev):
print("滑鼠進入了", ev)
def leaveEvent(self, ev):
print("滑鼠離開了", ev)
def mousePressEvent(self, ev):
print("滑鼠按下了", ev.button())
def mouseReleaseEvent(self, ev):
print("滑鼠鬆開", ev)
def mouseDoubleClickEvent(self, ev):
print("滑鼠雙擊了", ev.flags())
def mouseMoveEvent(self, ev):
print("滑鼠在移動", ev)
def keyPressEvent(self, ev):
print("鍵盤按下了:", chr(ev.key()))
def keyReleaseEvent(self, ev):
print("鍵盤松開了:", chr(ev.key()))
def focusInEvent(self, ev):
print("獲得焦點")
def focusOutEvent(self, ev):
print("失去焦點")
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗
w = Window()
# 顯示視窗
w.show()
sys.exit(app.exec_())
2.8.3 事件傳遞
如果一個控制元件沒有處理該事件,則會自動傳遞給父控制元件進行處理
事件物件具有兩種特殊方法:
accept()
:- 自己處理這個事件,並告訴系統不要在向上層傳遞
ignore()
:- 自己忽略這個事件,但是會執行;告訴系統,繼續往後傳遞
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
class Window(QWidget):
def mousePressEvent(self, ev):
print("頂層滑鼠按下")
class MidWindow(QWidget):
def mousePressEvent(self, ev):
ev.ignore() # 轉發給父物件,但是也會接收物件
print(ev.isAccepted())
print("中間滑鼠按下")
class Label(QLabel):
def mousePressEvent(self, ev):
print("標籤控制元件滑鼠按下")
ev.accept() # 不用轉發給父物件,接收物件
print(ev.isAccepted())
app = QApplication(sys.argv)
w = Window()
w.setWindowTitle("事件轉發")
w.resize(500, 500)
m_w = MidWindow(w)
m_w.resize(300, 300)
m_w.setAttribute(Qt.WA_StyledBackground, True)
m_w.setStyleSheet("background-color: yellow;")
label = Label(m_w)
label.setText("這是一個標籤")
label.setStyleSheet("background-color: skyblue;")
label.move(110, 110)
# 注意這個底層事件會被頂層事件覆蓋
w.show()
sys.exit(app.exec_())
2.8.4 案例
-
建立一個視窗包含一個標籤
- 滑鼠進入標籤時,展示歡迎光臨
- 滑鼠離開標籤時,展示謝謝惠顧
#!/usr/bin/env python # -*- coding: UTF-8 -*- # @author: kun from PyQt5.Qt import * import sys class Label(QLabel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.resize(200, 200) self.move(100, 100) self.setStyleSheet("background-color: skyblue;") def enterEvent(self, *args, **kwargs): self.setText("歡迎光臨") def leaveEvent(self, *args, **kwargs): self.setText("謝謝惠顧") app = QApplication(sys.argv) w = QWidget() w.setWindowTitle("滑鼠操作案例1") w.resize(500, 500) label = Label(w) w.show() sys.exit(app.exec_())
-
建立一個視窗,監聽使用者按鍵
- 監聽使用者輸入Tab鍵
- 監聽使用者輸入Ctrl + S 組合鍵
- 監聽使用者輸入Ctrl + Shift + v 組合鍵
#!/usr/bin/env python # -*- coding: UTF-8 -*- # @author: kun from PyQt5.Qt import * import sys class Label(QLabel): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.resize(200, 200) self.move(100, 100) self.setStyleSheet("background-color: skyblue; font-weight: 500;") self.grabKeyboard() # 捕獲鍵盤事件 # self.releaseKeyborad() # 停止捕獲鍵盤事件 def keyPressEvent(self, ev): # 監聽 Tab 鍵 if ev.key() == Qt.Key_Tab: # 監聽普通鍵 self.setText('使用者點選的是Tab鍵') # 監聽 Ctrl + C 修飾鍵 Ctrl 並且 普通鍵 C Qt.AltModifier:其為 Alt 組合鍵 if ev.modifiers() == Qt.ControlModifier and ev.key() == Qt.Key_C: self.setText("正在複製文字內容") # 監聽 Ctrl + Shift + v 修飾鍵 Ctrl + Shift (使用按位或組合獲取) 並且普通鍵 V if ev.modifiers() == Qt.ControlModifier | Qt.ShiftModifier and ev.key() == Qt.Key_V: self.setText("正在貼上內容") app = QApplication(sys.argv) w = QWidget() w.setWindowTitle("滑鼠操作案例1") w.resize(500, 500) label = Label(w) w.show() sys.exit(app.exec_())
-
完成視窗,使用者區支援拖拽
- 確定滑鼠移動的距離(向量 x, y)
- 原始視窗座標點 + 向量
#!/usr/bin/env python # -*- coding: UTF-8 -*- # @author: kun from PyQt5.Qt import * class Window(QWidget): def __init__(self): super().__init__() self.move_flag = False # 判斷是否在移動 self.setWindowTitle("內容拖動") # 設定標題 self.resize(500, 500) # 設定視窗大小 self.move(100, 100) # 移動視窗 self.mouse = () # 移動前的座標 self.origin = () # 原始的座標 def mousePressEvent(self, evt): """ print(evt.localPos()) # 得到是相對於視窗左上角的座標 print(evt.globalPos()) # 得到的是相對於電腦左上角的座標 """ if evt.button() == Qt.LeftButton: self.move_flag = True # 設定標記 self.mouse = (evt.globalX(), evt.globalY()) self.origin = (self.x(), self.y()) # 左上角座標 def mouseMoveEvent(self, evt): if self.move_flag: # 相對移動 move_x = evt.globalX() - self.mouse[0] move_y = evt.globalY() - self.mouse[1] self.move(self.origin[0] + move_x, self.origin[1] + move_y) def mouseReleaseEvent(self, evt): # 確定最終位置 self.move_flag = False if __name__ == '__main__': # 可以通過導包來執行視窗 import sys app = QApplication(sys.argv) # 建立視窗 w = Window() # 顯示視窗 w.show() sys.exit(app.exec_())
2.9 父子關係
2.9.1 語法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle("父子關係")
w.resize(500, 500)
l1 = QLabel(w)
l1.setText("標籤1")
l2 = QLabel(w)
l2.setText("標籤2")
l2.move(50, 0)
l3 = QLabel(w)
l3.setText("標籤3")
l3.move(100, 0)
print(w.childAt(50, 0)) # 獲得對應座標的子控制元件
print(l2.parentWidget()) # 獲得父控制元件
print(w.childrenRect().getRect()) # 列印子控制元件所佔有的矩形區域
w.show()
sys.exit(app.exec_())
2.9.2 案例
建立視窗,若干個Label控制元件,實現點選功能
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
# class MyLabel(QLabel): # 藉助子控制元件
# def mousePressEvent(self, evt):
# for i in self.parentWidget().findChildren(MyLabel): # 獲取父控制元件
# i.setStyleSheet("")
# self.setStyleSheet("background-color: red;")
class MyWidget(QWidget):
def mousePressEvent(self, evt):
subLabel = self.childAt(evt.x(), evt.y())
if subLabel: # 如果點選了標籤;避免了報錯
for i in self.findChildren(QLabel): # 獲取所有子控制元件,並清空樣式
i.setStyleSheet("")
subLabel.setStyleSheet("background-color: red;") # 給制定內容修改樣式
app = QApplication(sys.argv)
w = MyWidget()
w.setWindowTitle("父子關係")
w.resize(500, 500)
for i in range(11):
l = QLabel(w)
l.setText(f"標籤{i}")
l.move(50 * i, 50 * i)
w.show()
sys.exit(app.exec_())
2.10 層級控制
高層級控制元件會被低層級控制元件覆蓋
語法:
lower() # 將控制元件層級降低到最底層
raise_() # 將控制元件提升到最上層
a.stzckUnder(b) # 讓 a 放在 b 下面
注意:以上操作專指同級順序
應用:需要調整控制元件Z軸順序
2.11 頂層視窗
2.11.1 基本語法
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
icon = QIcon(r"D:\35005\Pictures\Screenshots\微信圖片_20220302175157.jpg") # 建立圖示物件
w.setWindowIcon(icon) # 設定視窗圖示
print(w.windowIcon()) # 獲取圖示物件
w.setWindowTitle("Hello") # 預設為 python
print(w.windowTitle()) # 獲取視窗的標題
w.setWindowOpacity(0.9) # 設定不透明度,範圍是 0 ~ 1
print(w.windowOpacity()) # 獲取視窗不透明度
w.setWindowState(Qt.WindowActive)
# 設定視窗狀態,有 無狀態(WindowNoSate) 最小化(WindowMinimized)
# 最大化(WindowMaximized) 全屏(WindowFullScreen) 活動視窗(WindowActive)
print(w.windowState()) # 獲取視窗狀態
w.show()
sys.exit(app.exec_())
2.11.2 最大化和最小化
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
# w.showMaximized() # 最大化展示
# w.showMinimized() # 最小化展示
# w.showNormal() # 正常展示
# w.showFullScreen() # 全屏展示
print(w.isMinimized()) # 檢視是否為最小化
print(w.isMaximized()) # 檢視是否為最大化
print(w.isFullScreen()) # 檢視是否為全屏
w.show()
sys.exit(app.exec_())
2.11.3 視窗標誌
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.setWindowFlags(Qt.WindowStaysOnTopHint) # 設定頂層視窗的外觀標誌
w.show()
sys.exit(app.exec_())
屬性 描述 Qt.MSWindowsFixedSizeDialogHint 固定視窗,無法調整大小 Qt.FramelessWindowHint 視窗無邊框 Qt.CustomizeWindowHint 有邊框,無標題欄與按鈕,不能移動和拖動 Qt.WindowTitleHint 新增標題欄與關閉按鈕 Qt.WindowSystemMenuHint 新增系統目錄和關閉按鈕 Qt.WindowMaximizeButtonHint 啟用最大化按鈕與關閉按鈕,禁止最小化按鈕 Qt.WindowMinimizeButtonHint 啟用最小化按鈕與關閉按鈕,禁止最大化按鈕 Qt.WindowMinMaxButtonsHint 啟用最大化與最小化按鈕和關閉按鈕 Qt.WindowCloseButtonHint 新增一個關閉按鈕 Qt.WindowContextHelpButtonHint 新增問號與關閉按鈕,像對話方塊一樣 Qt.WindowStaysOnTopHint 視窗始終處於頂部位置 Qt.windowStaysOnButtonHint 視窗始終處於底部位置
2.11.4 案例
建立一個視窗,要求:
- 無邊框,無標題欄
- 視窗半透明
- 自定義最大化,最小化,關閉按鈕
- 支援拖拽使用者區移動
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
class Window(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle("案例") # 設定標題
self.move_flag = False # 預設沒有移動
self.resize(500, 500) # 設定視窗大小
self.move(300, 300) # 移動視窗
self.setWindowOpacity(0.9) # 設定視窗透明
self.setup_ui() # 呼叫建立控制元件的方法
self.origin = () # 初始座標,相對於視窗的
self.mouse = () # 滑鼠按下時,滑鼠相對於視窗的座標
def setup_ui(self): # 新增控制元件的操作
def close_w():
self.deleteLater() # 刪除主視窗
btn_close = QPushButton(self)
btn_close.clicked.connect(close_w)
btn_close.setText("X")
btn_close.move(self.width() - 25, 8)
def max_or_min(btn):
if self.isMaximized():
self.showNormal()
btn.setText("+")
else:
self.showMaximized()
btn.setText("-")
count = 1
self.findChild(QLabel).resize(self.width(), 45)
for i in self.findChildren(QPushButton):
i.move(self.width() - count * 25, 8) # 動態化設定按鍵的位置
count += 1
btn_maxOrMin = QPushButton(self)
btn_maxOrMin.move(self.width() - 50, 8)
btn_maxOrMin.clicked.connect(lambda: max_or_min(btn_maxOrMin))
btn_maxOrMin.setText("+")
qApp.setStyleSheet("""QPushButton{
font-size: 20px;
color: black;
font-weight: 800;
border: 2px solid black;
margin: 5px;
}""") # 設定樣式
# 設定視窗頭部框架
label = QLabel(self)
label.resize(self.width(), 45)
label.setStyleSheet("background-color: skyblue;")
label.lower()
# 設定視窗移動
def mousePressEvent(self, evt):
if evt.button() == Qt.LeftButton:
self.move_flag = True
self.mouse = (evt.globalX(), evt.globalY())
self.origin = (self.x(), self.y())
def mouseMoveEvent(self, evt):
self.move(evt.globalX() - self.mouse[0] + self.origin[0],
evt.globalY() - self.mouse[1] + self.origin[1]) if self.move_flag else None
def mouseReleaseEvent(self, *args, **kwargs):
self.move_flag = False
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗,同時無邊框,無標題欄
w = Window(flags=Qt.FramelessWindowHint)
# 顯示視窗
w.show()
sys.exit(app.exec_())
2.12 互動狀態
2.12.1 是否可見
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
setEnabled(bool) # 設定控制元件是否可用
isEnabled() # 獲取控制元件是否可用
"""
app = QApplication(sys.argv)
w = QWidget()
btn = QPushButton(w)
btn.setText("點選")
print(btn.isEnabled()) # 判斷按鈕是否可用
btn.pressed.connect(lambda: btn.setEnabled(False)) # 點選後按鈕禁用
w.show()
sys.exit(app.exec_())
2.12.2 顯示和隱藏
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
# 顯示和隱藏
setVisible(bool) # 設定控制元件是否可見,傳遞的引數值為 True 也不一定可見,如果父控制元件沒有展示,那麼子控制元件為 True 也不可見
setHidden(bool) # 設定隱藏
show() # 設定顯示
hide() # 設定隱藏
isHidden() # 獲取相對於父控制元件是否隱藏
isVisible() # 獲取是否可見
isVisibleTo(widget) # 獲取相對於widget控制元件是否可見,即該控制元件是否跟著widget控制元件一起顯示
"""
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
btn = QPushButton(w)
print(btn.isVisible()) # 判斷控制元件是否可見
btn.clicked.connect(lambda: btn.hide()) # 隱藏按鈕
print(w.isHidden()) # 判斷視窗是否隱藏
w.setVisible(True) # 使得視窗可見,先繪製父視窗
# w.setHidden(False) # 效果一樣
sys.exit(app.exec_())
2.12.3 是否可編輯
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
setWindowModified(bool) # 設定是否被編輯
isWindowModified() # 視窗是否被編輯
"""
app = QApplication(sys.argv)
w = QWidget()
w.setWindowTitle("[*]互動狀態")
w.setWindowModified(True) # 可編輯狀態會顯示 [] 裡面的*號,即有 * 號就處於被編輯狀態
print(w.isWindowModified()) # 判斷視窗是否處於可編輯狀態
w.setVisible(True) # 和show作用類似
sys.exit(app.exec_())
2.12.4 是否為活躍視窗
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w1 = QWidget()
w2 = QWidget()
w2.show()
w1.show()
print(w2.isActiveWindow()) # 展示是否處於活躍視窗
print(w1.isActiveWindow())
sys.exit(app.exec_())
2.12.5 控制元件關閉
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
setAttribute(Qt.WA_DeleteOnClose, True) # 如果加了這行程式碼,視窗/控制元件就會在關閉的同時刪除,效果和deleteLater類似
close() # 效果和setVisible類似
"""
app = QApplication(sys.argv)
w1 = QWidget()
w2 = QWidget()
w2.destroyed.connect(lambda: print("w2銷燬"))
w1.destroyed.connect(lambda: print("w1銷燬"))
w2.show()
w1.show()
w1.setAttribute(Qt.WA_DeleteOnClose, True) # 如果加了這行程式碼,視窗/控制元件就會在關閉的同時刪除,效果和deleteLater類似
w1.close() # 效果和setVisible類似
w2.setVisible(False) # 使得視窗不可見,但是視窗並沒有刪除
w2.deleteLater() # 銷燬視窗/控制元件
sys.exit(app.exec_())
2.12.6 案例
建立一個視窗,包含一個文字框和一個按鈕和一個標籤:
- 預設狀態下,標籤隱藏,文字框和按鈕顯示,按鈕為不可使用狀態
- 當文字框有內容時,讓按鈕可用,否則不可用
- 當文字框內容為kun時,點選按鈕顯示標籤,並且展示文字為登入成功,否則為失敗
涉及知識點:
- 文字框的建立
- QLineEdit類
- 文字框內容監測
- testChanged 訊號
- 文字框內容獲取
- text() 方法
- 按鈕狀態設定
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import hashlib
class Window(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("案例[*]") # 設定標題
self.resize(500, 500) # 設定視窗大小
self.move(100, 100) # 移動視窗
self.setup_ui() # 呼叫建立控制元件的方法
def setup_ui(self): # 新增控制元件的操作 5 + 40 + 5 + 40 + 5
qApp.setStyleSheet("*{font-size: 15px; line-height: 15px;}") # 設定樣式
# 建立文字框
text = QLineEdit(self)
text.resize(300, 40)
text.move(100, 5)
def change_():
self.setWindowModified(True)
btn.setEnabled(len(text.text()) > 0) # 當有文字框內容時,按鈕可用
text.textChanged.connect(change_) # 繫結事件
# 建立按鈕
btn = QPushButton(self)
btn.resize(80, 40)
btn.setText("登入")
btn.move(210, 50)
btn.setEnabled(False) # 按鈕不可用
def click_():
label.setVisible(True) # 顯示標籤
# 使用 hash 加密
salt = hashlib.md5("liu".encode("utf-8"))
salt.update(text.text().encode("utf-8"))
content = salt.hexdigest()
if content == 'a8b2a2561ec21479990c48706a743c9a': # 條件判斷
label.setText("登入成功")
else:
label.setText("登入失敗")
text.setText("")
self.setWindowModified(False)
btn.clicked.connect(click_) # 繫結事件
# 建立標籤
label = QLabel(self)
label.resize(100, 40)
label.move(220, 95)
label.setVisible(False) # 標籤隱藏
if __name__ == '__main__':
# 可以通過導包來執行視窗
import sys
app = QApplication(sys.argv)
# 建立視窗
w = Window()
# 顯示視窗
w.show()
sys.exit(app.exec_())
2.13 資訊提示
2.13.1 狀態提示
滑鼠懸停在空間上一會兒後,展示內容在狀態列上面
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QMainWindow() # 使用組合視窗
w.resize(500, 500)
w.statusBar() # 建立狀態列,可以顯示狀態提示
l = QLabel(w)
l.setStatusTip("這是資訊提示") # 設定狀態提示
l.setText("你好")
print(l.statusTip()) # 獲取狀態提示
w.show()
sys.exit(app.exec_())
2.13.2 工具提示
滑鼠懸停在控制元件上一會兒後,展示在旁邊
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
l = QLabel(w)
l.setToolTip("這是一個工具提示")
l.setText("坤坤")
l.setToolTipDuration(1000) # 工具提示展示時間為 1 秒
print(l.toolTip()) # 獲取工具提示
w.show()
sys.exit(app.exec_())
2.13.3 意思提示
切換到檢視這是啥模式,點選該控制元件時顯示
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
w = QWidget(flags=Qt.WindowContextHelpButtonHint) # 這是啥模式
w.resize(500, 500)
l = QLabel(w)
l.setWhatsThis("這是啥,這是一個意思提示") # 設定一個意思提示
l.setText("坤坤")
print(l.whatsThis()) # 獲取意思提示
w.show()
sys.exit(app.exec_())
2.14 焦點控制
2.14.1 單個控制元件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
setFocus() # 指定控制元件獲取焦點
setFocusPolicy(mode) # 設定焦點獲取策略
- 引數
Qt.TabFocus 通過 Tab 獲取焦點
Qt.ClickFocus 通過點選獲取焦點
Qt.StrongFocus 通過以上兩種方式獲取焦點
Qt.NoFocus 不能通過以上兩種方式獲取焦點
clearFocus() # 取消焦點
"""
app = QApplication(sys.argv)
# 建立三個文字框
w = QWidget()
w.resize(500, 500)
t1 = QLineEdit(w)
t2 = QLineEdit(w)
t2.move(50, 50)
t2.setFocus() # 設定焦點
t2.setFocusPolicy(Qt.TabFocus) # 獲取焦點的方式
t2.clearFocus() # 取消焦點
t3 = QLineEdit(w)
t3.move(100, 100)
w.show()
sys.exit(app.exec_())
2.14.2 父控制元件
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# @author: kun
from PyQt5.Qt import *
import sys
"""
focusWidget() # 獲取子控制元件中當前焦距的控制元件
focusNextChild() # 聚焦下一個子控制元件
focusPreviousChild() # 聚焦上一個子控制元件
focusNextPrevChild() # true:下一個 false:上一個
setTabOrder(pre_widget, next_widget) # 靜態方法,用於設定子控制元件獲取焦點的先後順序
"""
app = QApplication(sys.argv)
w = QWidget()
w.resize(500, 500)
t1 = QLineEdit(w)
t1.setFocus() # 給 t1 設定焦點
t2 = QLineEdit(w)
t2.move(50, 50)
t3 = QLineEdit(w)
t3.move(100, 100)
w.show()
# QWidget.setTabOrder(t3, t2) # 按 tab 獲取焦點的順序 t3 > t2 > t1
w.focusNextChild() # 聚焦下一個子控制元件
w.focusNextPrevChild(True) # 結果是t3有焦點
print(w.focusWidget()) # 獲取子控制元件中當前焦距的控制元件
sys.exit(app.exec_())
2.15 訊號
windowTitleChanged(QString) # 視窗標題改變訊號
windowIconChanged(QIcon) # 視窗圖示改變訊號
customContentMenuRequested(Qpoint) # 自定義上下文選單請求訊號
基類控制元件學習完成,下面我們開始學習具體的子類控制元件