背景:因為項目需要,要開發一個在PC上運行的應用程序,生成一個跟隨鼠標運動的窗口,並且監聽鼠標的點擊事件,並在窗口上做相應的顯示。
平台:Win7 64位 + Python27 64位
支持庫:PyHook + PyQt5
模塊的安裝這里就不多說了,網上有很多。需要注意的是,PyHook對Python3的支持不是很好,會出現卡死的問題, 還有PyQt5貌似只支持64位。廢話不多說了,開始造~
第一步:
先用PyQt5生成一個自定義的窗口:
1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import sys 5 from PyQt5.QtCore import * 6 from PyQt5.QtGui import * 7 from PyQt5.QtWidgets import * 8 9 class newWindow(QWidget): 10 def __init__(self, parent=None): 11 super(newWindow, self).__init__(parent) 12 self.mypix() 13 self.setWindowFlags(Qt.FramelessWindowHint) #去除界面邊框 14 self.setWindowFlags(Qt.WindowStaysOnTopHint)#窗口顯示在屏幕最上方 15 self.setAttribute(Qt.WA_TranslucentBackground)#背景透明 16 17 #顯示不規則圖片 18 def mypix(self): 19 self.update() 20 self.pix=QPixmap('./1.png','0',Qt.AvoidDither|Qt.ThresholdAlphaDither|Qt.ThresholdDither) 21 self.resize(self.pix.size()) 22 self.setMask(self.pix.mask()) 23 24 def paintEvent(self, QPaintEvent): 25 painter=QPainter(self) 26 painter.drawPixmap(0,0,self.pix.width(),self.pix.height(),self.pix) 27 28 if __name__=="__main__": 29 app = QApplication(sys.argv) 30 31 w = newWindow() 32 w.setWindowTitle('一個窗口') 33 w.show() 34 35 sys.exit(app.exec_())
顯示效果如下:
窗口出來了,下一步救贖讓它跟隨着鼠標進行移動了
第二步 監聽鼠標事件
1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import pyHook 5 import pythoncom 6 7 class MouseListener(): 8 9 def __init__(self): 10 11 #新建鈎子管理器 12 hookmanager = pyHook.HookManager() 13 #注冊動作回調函數 14 hookmanager.MouseLeftDown = self.onMouseLeftDown 15 hookmanager.MouseLeftUp = self.onMouseRelease 16 hookmanager.MouseMiddleDown = self.onMouseMiddleDown 17 hookmanager.MouseMiddleUp = self.onMouseRelease 18 hookmanager.MouseRightDown = self.onMouseRightDown 19 hookmanager.MouseRightUp = self.onMouseRelease 20 hookmanager.MouseMove = self.onMouseMove 21 #鈎取鼠標事件 22 hookmanager.HookMouse() 23 #推送window事件消息 24 pythoncom.PumpMessages() 25 26 27 28 def onMouseLeftDown(self, event): 29 print("MouseLeft Down!") 30 31 return True 32 33 def onMouseMiddleDown(self, event): 34 print("MouseMiddle Down!") 35 36 return True 37 38 def onMouseRightDown(self, event): 39 print("MouseRight Down!") 40 41 return True 42 43 def onMouseRelease(self, event): 44 print("Button release!") 45 46 return True 47 48 def onMouseMove(self, event): 49 print("Mouse Move!") 50 51 return True 52 53 54 if __name__=="__main__": 55 mouseListener = MouseListener()
結果如下:
現在最后的問題就是如何結合這兩個程序了。
因為Qt界面本身是一個死循環,而監聽器里的pythoncom.PumpMessage()也是一個死循環。很自然的想法就是開啟多線程。
開啟多線程會出現兩個問題: 1、因為是死循環,關閉窗口之后,子線程還是在運行,無法關閉。正常手段無法關閉,只能強制關閉,
但是還是會出現問題。
2、可能是兩個死循環有影響的原因,當鼠標移動到窗口的時候會卡死。
感興趣的可以試試,代碼就不貼了,下面的寫解決辦法。
絞盡腦汁,頭發都掉了一斤還是解決不了!無意中發現去掉pythoncom.PumpMessages()這個語句,程序居然可以運行。哈哈,天不絕我!!!^-^
1 #!usr/bin/env python 2 #-*- coding:utf-8 -*- 3 4 import pyHook 5 import pythoncom 6 7 import sys 8 from PyQt5.QtCore import * 9 from PyQt5.QtGui import * 10 from PyQt5.QtWidgets import * 11 12 13 class newWindow(QWidget): 14 def __init__(self, parent=None): 15 super(newWindow, self).__init__(parent) 16 self.mypix() 17 self.setWindowFlags(Qt.FramelessWindowHint) #去除界面邊框 18 self.setWindowFlags(Qt.WindowStaysOnTopHint)#窗口顯示在屏幕最上方 19 self.setAttribute(Qt.WA_TranslucentBackground)#背景透明 20 #新建鈎子管理器 21 self.hookmanager = pyHook.HookManager() 22 self.hookmanager.MouseMove = self.onMouseMove 23 #鈎取鼠標事件 24 self.hookmanager.HookMouse() 25 26 #顯示不規則圖片 27 def mypix(self): 28 self.update() 29 self.pix=QPixmap('./1.png','0',Qt.AvoidDither|Qt.ThresholdAlphaDither|Qt.ThresholdDither) 30 self.resize(self.pix.size()) 31 self.setMask(self.pix.mask()) 32 33 def paintEvent(self, QPaintEvent): 34 painter=QPainter(self) 35 painter.drawPixmap(0,0,self.pix.width(),self.pix.height(),self.pix) 36 37 38 def closeEvent(self, QEvent): 39 self.hookmanager.UnhookMouse() 40 sys.exit() 41 42 def onMouseMove(self, event): 43 #print("Mouse Move!") 44 (x, y) = event.Position 45 self.move(x, y) 46 return True 47 48 49 if __name__=="__main__": 50 app = QApplication(sys.argv) 51 52 w = newWindow() 53 w.setWindowTitle('一個窗口') 54 w.show() 55 56 sys.exit(app.exec_())
OK,問題解決了,解釋這么簡單!(PS: 我的IDLE運行,關閉時會出現Runtime Error! 直接用命令行運行就不會出現這個問題了)
總結:猜測可能是Qt界面本身就是有類似於pythoncom.PumpMessages()這樣功能的語句,所以前面會出現鼠標移動到界面上就出現卡死的現象。
主要還是對底層不太了解,折騰了許久。