用Python写一个跟随鼠标运动的自定义窗口
背景:因为项目需要,要开发一个在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()这样功能的语句,所以前面会出现鼠标移动到界面上就出现卡死的现象。
主要还是对底层不太了解,折腾了许久。