天天看點

PyQt5-事件處理機制

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