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_())
