PyQt中提供了兩種針對事件處理的機制:一種是信号和槽,另一種則是事件;事件處理在PyQt中是比較底層的,這裡的事件常見如下類型:
鍵盤事件、滑鼠事件、拖放事件、滾輪事件、定時事件、焦點事件、進入和離開事件(光标移入控件或者移出),移動事件(視窗位置變化),
顯示和隐藏事件,視窗事件(視窗是否為目前視窗)、以及常見的Qt事件:Socket事件、剪貼闆事件、文字改變事件,布局改變事件;
PyQt提供了5中事件處理和過濾方法,弱到強,其中前兩者常用;
(1)重寫事件具體的函數(例如:mousePressEvent()/keyPressEvent()....)
(2)重新實作QObject.event()一般用在PyQt沒有提供該事件的處理函數的情況下,即添加一個新的事件;
(3)通過事件過濾器
對QObject調用installEventFilter,則相當于為QObject安裝了一個事件過濾器;對于QObject的全部事件來說,他們會先傳遞到事件過濾函數eventFilter中;
在函數中我們可以放棄或者修改某些事件,如果該過濾事件比較多,則會降低性能;
(4)在QApplication中設定事件過濾器
這種方式比前者更強大,QApplication的事件過濾器會捕獲所有QObject的事件,且第一個獲得事件,即在任意一個事件過濾器之前捕獲;
(5)重寫QApplication中notify()方法;
使用notify方法來分發事件;想在任意事件處理器之前捕獲事件,則唯一方法就是從寫notify方法;
例如:(1)(2)重寫具體事件和event函數;
1 #事件機制
2 #信号與槽(QTabWidget略)自定義參數
3 from PyQt5.QtWidgets import QComboBox,QTableView,QAbstractItemView,QHeaderView,QTableWidget, QTableWidgetItem, QMessageBox,QListWidget,QListWidgetItem, QStatusBar, QMenuBar,QMenu,QAction,QLineEdit,QStyle,QFormLayout, QVBoxLayout,QWidget,QApplication ,QHBoxLayout, QPushButton,QMainWindow,QGridLayout,QLabel
4 from PyQt5.QtGui import QIcon,QPixmap,QStandardItem,QStandardItemModel,QCursor,QFont,QBrush,QColor,QPainter
5 from PyQt5.QtCore import QStringListModel,QAbstractListModel,QModelIndex,QSize,Qt,QObject,pyqtSignal,QTimer,QEvent
6
7 import sys
8 class Win(QWidget):
9 def __init__(self,parent=None):
10
11 super(Win, self).__init__(parent)
12 self.message=""
13 self.btn1=QPushButton("點選1",self)
14 self.btn1.move(20,40)
15 self.btn1.clicked.connect(lambda :self.btnFn(1))#點選按鈕,執行btnFn方法
16
17 self.btn2 = QPushButton("點選2", self)
18 self.btn2.move(140,40)
19 self.btn2.clicked.connect(lambda: self.btnFn(2)) # 點選按鈕,執行btnFn方法
20 def btnFn(self,flag):
21 if flag==1:
22 print("點選了第一個按鈕")
23 else:
24 print("點選了第二個按鈕")
25
26
27 #上面之前的執行個體,下面從寫按鍵事件方法
28 ###第一種方式
29 def keyPressEvent(self, QKeyEvent):#重寫按鍵事件
30 if QKeyEvent.key()==Qt.Key_A:#按A建
31 self.btn1.click()
32 if QKeyEvent.key()==Qt.Key_Tab:
33 print("TABTAB")
34
35 def closeEvent(self, QCloseEvent):#重寫關閉視窗事件
36 print("重寫關閉視窗事件closeEvent")
37
38 def contextMenuEvent(self, even):#重寫上下文菜單事件
39 menu=QMenu(self)
40 oneAction=menu.addAction("One")
41 oneAction.triggered.connect(self.one)
42
43 menu.addSeparator()#菜單添加分割線
44 twoAction=menu.addAction("Two")
45 twoAction.triggered.connect(self.two)
46
47 menu.exec_(even.globalPos())#事件觸發在任意位置
48
49 def one(self):
50 print("one")
51 self.message="Menu option One"
52 self.update()
53 def two(self):
54 print("two")
55 self.message="Menu option Two"
56 self.update()
57
58 def paintEvent(self, event):#重寫繪制事件
59 painter=QPainter(self)
60 painter.setRenderHint(QPainter.TextAntialiasing)
61 painter.drawText(self.rect(),Qt.AlignCenter,self.message)
62 QTimer.singleShot(15000,self.clearMessage)#清空資料
63 QTimer.singleShot(15000,self.update)#更新目前元件
64
65 def clearMessage(self):
66 self.message=""
67
68 def resizeEvent(self, event):#更新窗體大小事件
69 self.message="視窗大小調整為:QSize({0},{1})".format(event.size().width(),event.size().height())
70 self.update()
71
72 ###第二種方式,一般适用于PyQt沒有提供事件處理函數情況,需要自定義事件,例如:
73 #Tab按鍵不會傳遞給keyPressEvent;
74 #第二種方式則是重寫event函數,所有針對視窗的事件都會傳遞給event函數,event會根據事件的類型,講事件配置設定給不同函數處理;
75
76 def event(self,event):
77 #?????下面捕獲不到tab按鍵的事件,if判斷始終未false,不知道為何,待解決;???
78 if ( event.type() == QEvent.KeyPress and event.key() == Qt.Key_Tab ):
79 print("Tab")
80 self.message="在event()中捕獲Tab按鍵觸發的事件"
81 self.update()
82 return True
83 return QWidget.event(self,event)
84
85
86 if __name__==\'__main__\':
87
88 app=QApplication(sys.argv)
89 win = Win()
90 win.show()
91 sys.exit(app.exec_())
例如:(3)事件過濾器;單擊按鈕擷取左鍵或者右鍵單擊事件;
1 #事件機制
2 from PyQt5.QtWidgets import QDialog,QComboBox,QTableView,QAbstractItemView,QHeaderView,QTableWidget, QTableWidgetItem, QMessageBox,QListWidget,QListWidgetItem, QStatusBar, QMenuBar,QMenu,QAction,QLineEdit,QStyle,QFormLayout, QVBoxLayout,QWidget,QApplication ,QHBoxLayout, QPushButton,QMainWindow,QGridLayout,QLabel
3 from PyQt5.QtGui import QIcon,QPixmap,QStandardItem,QStandardItemModel,QCursor,QFont,QBrush,QColor,QPainter,QMouseEvent,QImage,QTransform
4 from PyQt5.QtCore import QStringListModel,QAbstractListModel,QModelIndex,QSize,Qt,QObject,pyqtSignal,QTimer,QEvent
5
6 import sys
7 class Win(QWidget):
8 def __init__(self,parent=None):
9 super(Win, self).__init__(parent)
10 self.resize(400,400)
11
12 self.btn=QPushButton("按鈕",self)
13 self.btn.move(50,50)
14 self.btn.setMinimumWidth(220)
15
16 self.image=QImage("./image/7.ico")
17 self.label=QLabel(\'圖檔\',self)
18 self.label.setMinimumWidth(600 )
19 self.label.setMinimumHeight(400)
20 self.label.move(100,150)
21 self.label.setPixmap(QPixmap(self.image))
22
23 #對按鈕添加事件過濾器
24 self.btn.installEventFilter(self)
25
26 def eventFilter(self,obj, event):
27 if obj==self.btn:
28 if event.type()==QEvent.MouseButtonPress:
29 mouseEvent=QMouseEvent(event)
30 if mouseEvent.buttons()==Qt.LeftButton:
31 self.btn.setText("按滑鼠左鍵縮小圖檔")
32 transform=QTransform()
33 transform.scale(0.5,0.5)#設定縮放多少倍
34 self.label.setPixmap(QPixmap.fromImage(self.image.transformed(transform)))#将label中圖檔設定縮放效果
35 if mouseEvent.buttons()==Qt.RightButton:
36 self.btn.setText("按滑鼠右鍵放大圖檔")
37 transform = QTransform()
38 transform.scale(1.5, 1.5)#設定縮放多少倍
39 self.label.setPixmap(QPixmap.fromImage(self.image.transformed(transform)))
40 return QWidget.eventFilter(self,obj,event)
41
42 if __name__==\'__main__\':
43
44 app=QApplication(sys.argv)
45 win = Win()
46 win.show()
47 sys.exit(app.exec_())
關于(4)和(5)略,這裡不寫例子了;
補充:
第四種在QApplication中安裝事件監聽,隻需要修改上面程式即可:
将
app=QApplication(sys.argv)
win = Win()
#
app.installEventFilter(win) #安裝事件過濾器,将前面代碼中按鈕的installEventFilter注釋掉即可
#
win.show()
sys.exit(app.exec_())