Merge branch 'master' of https://github.com/892768447/PyQt.git
This commit is contained in:
commit
b5122dc6f1
21 changed files with 634 additions and 77 deletions
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Python35</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 3.0</pydev_property>
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
<path>/${PROJECT_DIR_NAME}</path>
|
||||
</pydev_pathproperty>
|
||||
</pydev_project>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?><pydev_project>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 3.0</pydev_property>
|
||||
<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
|
||||
<path>/${PROJECT_DIR_NAME}</path>
|
||||
</pydev_pathproperty>
|
||||
</pydev_project>
|
||||
|
|
|
@ -24,9 +24,15 @@
|
|||
- [1.17 下拉选择联动](下拉选择联动/)
|
||||
- [1.18 人脸描点检测](人脸描点检测/)
|
||||
- [1.19 腾讯视频热播列表](腾讯视频热播列表/)
|
||||
- [1.20 exec()动态生成控件](partner_625781186/1.exec动态生成控件/)
|
||||
- 1.20 exec()动态生成控件
|
||||
- [1. 动态控件基础例子 - 动态生成按钮](partner_625781186/1.exec动态生成控件/dynamic_button)
|
||||
- [2. 动态控件基础例子 - 动态生成菜单](partner_625781186/1.exec动态生成控件/dynamic_Menu)
|
||||
- [3. 配合setting记录模型类型](partner_625781186/1.exec动态生成控件/)
|
||||
- [1.21 仿QQ设置面板](仿QQ设置面板/)
|
||||
- [1.22 Json生成QTreeWidget](Json生成QTreeWidget/)
|
||||
- [1.23 嵌入外部窗口](嵌入外部窗口/)
|
||||
- [1.24 必应壁纸](https://github.com/892768447/BingWallpaper)
|
||||
|
||||
|
||||
### [2.QGraphicsView练习](QGraphicsView练习/)
|
||||
- [2.1 世界地图](QGraphicsView练习/世界地图)
|
||||
|
|
35
partner_625781186/1.exec动态生成控件/dynamic_Menu/Ui_动态控件.py
Normal file
35
partner_625781186/1.exec动态生成控件/dynamic_Menu/Ui_动态控件.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'D:\pyPro\dynamic_Menu\动态控件.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.9.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(370, 403)
|
||||
Dialog.setSizeGripEnabled(True)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
Dialog = QtWidgets.QDialog()
|
||||
ui = Ui_Dialog()
|
||||
ui.setupUi(Dialog)
|
||||
Dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
|
0
partner_625781186/1.exec动态生成控件/dynamic_Menu/__init__.py
Normal file
0
partner_625781186/1.exec动态生成控件/dynamic_Menu/__init__.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
|
||||
<!-- eric project file for project dynamic_Controls -->
|
||||
<!-- Saved: 2018-04-11, 02:00:19 -->
|
||||
<!-- Copyright (C) 2018 , -->
|
||||
<Project version="5.1">
|
||||
<Language>en_US</Language>
|
||||
<Hash>b35a15d37a7cb52779310396c238b2e70ac76888</Hash>
|
||||
<ProgLanguage mixed="0">Python3</ProgLanguage>
|
||||
<ProjectType>PyQt5</ProjectType>
|
||||
<Version>0.1</Version>
|
||||
<Author></Author>
|
||||
<Email></Email>
|
||||
<Eol index="0"/>
|
||||
<Sources>
|
||||
<Source>Ui_动态控件.py</Source>
|
||||
<Source>__init__.py</Source>
|
||||
<Source>动态控件.py</Source>
|
||||
</Sources>
|
||||
<Forms>
|
||||
<Form>动态控件.ui</Form>
|
||||
</Forms>
|
||||
<Translations/>
|
||||
<Resources/>
|
||||
<Interfaces/>
|
||||
<Others/>
|
||||
<Vcs>
|
||||
<VcsType>None</VcsType>
|
||||
</Vcs>
|
||||
<FiletypeAssociations>
|
||||
<FiletypeAssociation pattern="*.e4p" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.idl" type="INTERFACES"/>
|
||||
<FiletypeAssociation pattern="*.md" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.py" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.py3" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.pyw" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.pyw3" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.qm" type="TRANSLATIONS"/>
|
||||
<FiletypeAssociation pattern="*.qrc" type="RESOURCES"/>
|
||||
<FiletypeAssociation pattern="*.rst" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.ts" type="TRANSLATIONS"/>
|
||||
<FiletypeAssociation pattern="*.txt" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.ui" type="FORMS"/>
|
||||
<FiletypeAssociation pattern="README" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="README.*" type="OTHERS"/>
|
||||
</FiletypeAssociations>
|
||||
</Project>
|
103
partner_625781186/1.exec动态生成控件/dynamic_Menu/动态控件.py
Normal file
103
partner_625781186/1.exec动态生成控件/dynamic_Menu/动态控件.py
Normal file
|
@ -0,0 +1,103 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Module implementing Dialog.
|
||||
"""
|
||||
|
||||
from PyQt5 import QtGui, QtWidgets, QtCore, QtWinExtras
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from functools import partial
|
||||
from Ui_动态控件 import Ui_Dialog
|
||||
|
||||
class Dialog(QDialog, Ui_Dialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
|
||||
super(Dialog, self).__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.dynamic1()
|
||||
|
||||
self.dynamic2()
|
||||
|
||||
# 法一
|
||||
def dynamic1(self):
|
||||
for i in range(5):
|
||||
self.pushButton = QtWidgets.QPushButton(self)
|
||||
self.pushButton.setText("pushButton%d"%i)
|
||||
self.pushButton.setObjectName("pushButton%d"%i)
|
||||
self.verticalLayout.addWidget(self.pushButton)
|
||||
self.pushButton.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.pushButton.customContextMenuRequested.connect(lambda:self.helpMenu(i))#右键请求,传入i实际上一直是4
|
||||
self.pushButton.clicked.connect(self.pr)
|
||||
|
||||
# 法二
|
||||
def dynamic2(self):
|
||||
for i in range(5, 8):
|
||||
txt="""
|
||||
self.pushButton_{i} = QtWidgets.QPushButton(self);
|
||||
self.pushButton_{i}.setText("pushButton{i}");
|
||||
self.pushButton_{i}.setObjectName("pushButton{i}");
|
||||
self.verticalLayout.addWidget(self.pushButton_{i});
|
||||
|
||||
self.pushButton_{i}.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
self.pushButton_{i}.customContextMenuRequested.connect(partial(self.helpMenu,i))#右键请求,用lambda会报错,partial需要import
|
||||
|
||||
self.pushButton_{i}.clicked.connect(self.pr)
|
||||
""".format(i=i)
|
||||
exec(txt)
|
||||
#只能法二可用的方式
|
||||
self.pushButton_5.clicked.connect(self.pr2)
|
||||
self.pushButton_6.clicked.connect(self.pr2)
|
||||
self.pushButton_7.clicked.connect(self.pr2)
|
||||
|
||||
|
||||
def helpMenu(self, *type):
|
||||
'''帮助按钮的右键菜单'''
|
||||
print(type)
|
||||
popMenu =QMenu()
|
||||
|
||||
if type[0]==5 or self.sender().text()== 'pushButton0':
|
||||
popMenu.addAction(u'关于',self.pr)
|
||||
popMenu.addSeparator()
|
||||
|
||||
elif type[0]==6 or self.sender().text()== 'pushButton1':
|
||||
popMenu.addAction(u'清理图片',self.pr)
|
||||
popMenu.addSeparator()
|
||||
|
||||
elif type[0]==7 or self.sender().text()== 'pushButton2':
|
||||
gitMenu=QMenu('同步到Git', popMenu)
|
||||
|
||||
self.pushAction=QAction(u'上传', self, triggered=lambda:self.pr)
|
||||
gitMenu.addAction(self.pushAction)
|
||||
|
||||
self.pullAction=QAction(u'下载', self, triggered=lambda:self.pr)
|
||||
gitMenu.addAction(self.pullAction)
|
||||
|
||||
gitMenu.addSeparator()
|
||||
gitMenu.addAction(u'配置仓库',lambda:self.pr)
|
||||
|
||||
popMenu.addAction(gitMenu.menuAction())#!!
|
||||
popMenu.exec_(QCursor.pos())#鼠标位置
|
||||
|
||||
def pr(self):
|
||||
'''法一和法二都可用的调用
|
||||
if self.sender().objectName=='XXX':
|
||||
self.pr2()
|
||||
'''
|
||||
print(self.sender().text())
|
||||
print(self.sender().objectName())
|
||||
print(self.pushButton.text())
|
||||
|
||||
def pr2(self):
|
||||
print(2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
ui = Dialog()
|
||||
ui.show()
|
||||
sys.exit(app.exec_())
|
23
partner_625781186/1.exec动态生成控件/dynamic_Menu/动态控件.ui
Normal file
23
partner_625781186/1.exec动态生成控件/dynamic_Menu/动态控件.ui
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>370</width>
|
||||
<height>403</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
35
partner_625781186/1.exec动态生成控件/dynamic_button/Ui_动态控件.py
Normal file
35
partner_625781186/1.exec动态生成控件/dynamic_button/Ui_动态控件.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file 'D:\pyPro\dynamic_button\动态控件.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.9.2
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
class Ui_Dialog(object):
|
||||
def setupUi(self, Dialog):
|
||||
Dialog.setObjectName("Dialog")
|
||||
Dialog.resize(370, 403)
|
||||
Dialog.setSizeGripEnabled(True)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
|
||||
self.retranslateUi(Dialog)
|
||||
QtCore.QMetaObject.connectSlotsByName(Dialog)
|
||||
|
||||
def retranslateUi(self, Dialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
Dialog = QtWidgets.QDialog()
|
||||
ui = Ui_Dialog()
|
||||
ui.setupUi(Dialog)
|
||||
Dialog.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
|
||||
<!-- eric project file for project dynamic_Controls -->
|
||||
<!-- Saved: 2018-04-11, 02:00:19 -->
|
||||
<!-- Copyright (C) 2018 , -->
|
||||
<Project version="5.1">
|
||||
<Language>en_US</Language>
|
||||
<Hash>b35a15d37a7cb52779310396c238b2e70ac76888</Hash>
|
||||
<ProgLanguage mixed="0">Python3</ProgLanguage>
|
||||
<ProjectType>PyQt5</ProjectType>
|
||||
<Version>0.1</Version>
|
||||
<Author></Author>
|
||||
<Email></Email>
|
||||
<Eol index="0"/>
|
||||
<Sources>
|
||||
<Source>Ui_动态控件.py</Source>
|
||||
<Source>__init__.py</Source>
|
||||
<Source>动态控件.py</Source>
|
||||
</Sources>
|
||||
<Forms>
|
||||
<Form>动态控件.ui</Form>
|
||||
</Forms>
|
||||
<Translations/>
|
||||
<Resources/>
|
||||
<Interfaces/>
|
||||
<Others/>
|
||||
<Vcs>
|
||||
<VcsType>None</VcsType>
|
||||
</Vcs>
|
||||
<FiletypeAssociations>
|
||||
<FiletypeAssociation pattern="*.e4p" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.idl" type="INTERFACES"/>
|
||||
<FiletypeAssociation pattern="*.md" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.py" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.py3" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.pyw" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.pyw3" type="SOURCES"/>
|
||||
<FiletypeAssociation pattern="*.qm" type="TRANSLATIONS"/>
|
||||
<FiletypeAssociation pattern="*.qrc" type="RESOURCES"/>
|
||||
<FiletypeAssociation pattern="*.rst" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.ts" type="TRANSLATIONS"/>
|
||||
<FiletypeAssociation pattern="*.txt" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="*.ui" type="FORMS"/>
|
||||
<FiletypeAssociation pattern="README" type="OTHERS"/>
|
||||
<FiletypeAssociation pattern="README.*" type="OTHERS"/>
|
||||
</FiletypeAssociations>
|
||||
</Project>
|
65
partner_625781186/1.exec动态生成控件/dynamic_button/动态控件.py
Normal file
65
partner_625781186/1.exec动态生成控件/dynamic_button/动态控件.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Module implementing Dialog.
|
||||
"""
|
||||
|
||||
from PyQt5 import QtGui, QtWidgets, QtCore, QtWinExtras
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
from Ui_动态控件 import Ui_Dialog
|
||||
|
||||
|
||||
class Dialog(QDialog, Ui_Dialog):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
|
||||
super(Dialog, self).__init__(parent)
|
||||
self.setupUi(self)
|
||||
self.dynamic1()
|
||||
self.dynamic2()
|
||||
|
||||
# 法一
|
||||
def dynamic1(self):
|
||||
for i in range(5):
|
||||
self.pushButton = QtWidgets.QPushButton(self)
|
||||
self.pushButton.setText("pushButton%d"%i)
|
||||
self.pushButton.setObjectName("pushButton%d"%i)
|
||||
self.verticalLayout.addWidget(self.pushButton)
|
||||
self.pushButton.clicked.connect(self.pr)
|
||||
# 法二
|
||||
def dynamic2(self):
|
||||
for i in range(4):
|
||||
txt="""
|
||||
self.pushButton_{i} = QtWidgets.QPushButton(self);
|
||||
self.pushButton_{i}.setText("pushButton{i}");
|
||||
self.pushButton_{i}.setObjectName("pushButton{i}");
|
||||
self.verticalLayout.addWidget(self.pushButton_{i});
|
||||
self.pushButton_{i}.clicked.connect(self.pr)
|
||||
""".format(i=i)
|
||||
exec(txt)
|
||||
#只能法二可用的方式
|
||||
self.pushButton_1.clicked.connect(self.pr2)
|
||||
self.pushButton_2.clicked.connect(self.pr2)
|
||||
self.pushButton_3.clicked.connect(self.pr2)
|
||||
|
||||
def pr(self):
|
||||
'''法一和法二都可用的调用
|
||||
if self.sender().objectName=='XXX':
|
||||
self.pr2()
|
||||
'''
|
||||
print(self.sender().text())
|
||||
print(self.sender().objectName())
|
||||
print(self.pushButton.text())
|
||||
|
||||
def pr2(self):
|
||||
print(2)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
ui = Dialog()
|
||||
ui.show()
|
||||
sys.exit(app.exec_())
|
23
partner_625781186/1.exec动态生成控件/dynamic_button/动态控件.ui
Normal file
23
partner_625781186/1.exec动态生成控件/dynamic_button/动态控件.ui
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>370</width>
|
||||
<height>403</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
102
partner_625781186/3.机制讲解/3.1 自定义事件/3.1.1 原理/myEvent.py
Normal file
102
partner_625781186/3.机制讲解/3.1 自定义事件/3.1.1 原理/myEvent.py
Normal file
|
@ -0,0 +1,102 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
@resource:http://blog.csdn.net/zzwdkxx/article/details/39338429
|
||||
@description: 自定义QEvent事件,上面网址为C++版本原理解释,此篇为python改编
|
||||
@Created on 2018年3月22日
|
||||
@email: 625781186@qq.com
|
||||
'''
|
||||
|
||||
from PyQt5 import QtGui, QtWidgets, QtCore
|
||||
from PyQt5.QtCore import *
|
||||
from PyQt5.QtGui import *
|
||||
from PyQt5.QtWidgets import *
|
||||
|
||||
|
||||
MyEventType = QEvent.registerEventType(QEvent.User+100)
|
||||
|
||||
#//长官
|
||||
|
||||
class MyEvent (QEvent):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyEvent, self).__init__(*args, **kwargs)
|
||||
print(MyEventType)
|
||||
def QEvent(self,MyEventType):
|
||||
pass
|
||||
|
||||
#//信使
|
||||
|
||||
class MySender(QCoreApplication):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MySender, self).__init__(*args, **kwargs)
|
||||
def notify(self, receiver, event):
|
||||
|
||||
if(event.type() == MyEventType):
|
||||
|
||||
print("MyEventType is coming!")
|
||||
# //return true;
|
||||
# /*这里不能return true,因为重写notify就是在事件被向下传递之前截住它,
|
||||
# 随便搞它,搞完了还得给QCoreApplication::notify向下传递,除非在mySender.notify
|
||||
# 实现了事件向下传递的那一套。直接返回的话myArmy就收不到这个事件,因为执行完这个
|
||||
# mySender.notify的return true后,事件传递被人为的在半截终止了
|
||||
# (见Qt事件处理的五个层次http:#//blog.csdn.net/michealtx/article/details/6865891 )
|
||||
# ,下面的myArmy的安装的过滤器和它自己的event都不会收到这个事件,更甭提最后干活
|
||||
# 的myEventHandler了。所以在主函数中执行完mySender.sendEvent把myEvent
|
||||
# 交给mySender.notify这个败家子儿后,就执行mySender.exec进入其它事件的循环了。这就是
|
||||
# 问题http:#//topic.csdn.net/u/20111012/19/78036d16-c163-40f9-a05c-3b7d6f4e9043.html
|
||||
# 出现的原因。感谢1+1=2大牛!非常感谢!
|
||||
# */
|
||||
|
||||
return QCoreApplication.notify(self,receiver, event)
|
||||
|
||||
#//军队
|
||||
|
||||
class MyArmy (QWidget):
|
||||
|
||||
def MyEventHandler(self,event):
|
||||
|
||||
print("The event is being handled!")
|
||||
event.accept()
|
||||
|
||||
def event(self, event):
|
||||
|
||||
if(event.type() == MyEventType):
|
||||
|
||||
print("event() is dispathing MyEvent")
|
||||
self.MyEventHandler(event) # //调用事件处理函数
|
||||
if(event.isAccepted()):
|
||||
|
||||
print("The event has been handled!")
|
||||
return True
|
||||
return QObject. event(self,event)
|
||||
|
||||
|
||||
#//监控者
|
||||
|
||||
class MyWatcher (QObject):
|
||||
|
||||
def eventFilter(self,watched, event):
|
||||
|
||||
if(event.type() == MyEventType):
|
||||
|
||||
print("I don't wanna filter MyEventType")
|
||||
return False
|
||||
|
||||
return QObject.eventFilter(self,watched, event)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
#//QCoreApplication a(argc, argv);
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
mySender = MySender(sys.argv)
|
||||
|
||||
myArmy=MyArmy ()
|
||||
myWatcher=MyWatcher ()
|
||||
myArmy.installEventFilter(myWatcher) # //安装事件过滤器
|
||||
|
||||
myEvent=MyEvent (MyEventType)
|
||||
mySender.sendEvent( myArmy, myEvent)
|
||||
mySender.exec()
|
|
@ -9,71 +9,59 @@ Created on 2017年12月11日
|
|||
@file: HotKey
|
||||
@description:
|
||||
'''
|
||||
import ctypes # @UnusedImport
|
||||
import ctypes.wintypes
|
||||
from datetime import datetime
|
||||
import sys
|
||||
|
||||
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout,\
|
||||
QMessageBox, QTextBrowser, QPushButton
|
||||
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QTextBrowser, QPushButton
|
||||
import keyboard
|
||||
|
||||
|
||||
# 参考
|
||||
# https://github.com/wujunwei/python-cookbook/blob/6e550d1a2b2b045cb07e56dd0198ccf01a2f3ea1/HotKey.py
|
||||
# https://github.com/chenyijie4238215/notebook/blob/ba11fcc43cf8d623d1d1a722c261ddc20ad6b941/global_hotkey/GlobalHotKey.py
|
||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
||||
__Version__ = "Version 1.0"
|
||||
|
||||
WM_HOTKEY = 0x0312
|
||||
MOD_ALT = 0x0001
|
||||
MOD_NONE = 0x000
|
||||
MOD_CONTROL = 0x0002
|
||||
MOD_SHIFT = 0x0004
|
||||
MOD_WIN = 0x0008
|
||||
|
||||
Modifier = {
|
||||
"None": MOD_NONE,
|
||||
"Ctrl": MOD_CONTROL,
|
||||
"Alt": MOD_ALT,
|
||||
"Shift": MOD_SHIFT,
|
||||
"Win": MOD_WIN
|
||||
}
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
KeyIds = {}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self)
|
||||
self.logView = QTextBrowser(self)
|
||||
self.logView.append("点击右上角关闭按钮会隐藏窗口,通过热键Alt+S来显示")
|
||||
self.logView.append("等待热键中")
|
||||
layout.addWidget(QPushButton("退出整个程序", self, clicked=self.onQuit))
|
||||
layout.addWidget(QPushButton(
|
||||
"退出整个程序", self, clicked=self.onQuit))
|
||||
layout.addWidget(self.logView)
|
||||
|
||||
def unregisterHotKey(self, kid):
|
||||
ctypes.windll.user32.UnregisterHotKey(ctypes.c_int(self.winId()), kid)
|
||||
keyboard.add_hotkey('alt+s', self.onShow, suppress=False) # 显示界面
|
||||
keyboard.add_hotkey('ctrl+s', self.onHide, suppress=False) # 隐藏界面
|
||||
keyboard.add_hotkey('shift+s', self.onQuit, suppress=False) # 退出程序
|
||||
|
||||
def registerHotKey(self, kid, modifier, key):
|
||||
key = str(key).upper()
|
||||
_modifier = Modifier.get(modifier, None)
|
||||
if not _modifier:
|
||||
return QMessageBox.critical(self, "错误", "modifier key {0}未找到".format(modifier))
|
||||
success = ctypes.windll.user32.RegisterHotKey(
|
||||
ctypes.c_int(self.winId()), kid, _modifier, ord(key))
|
||||
if success:
|
||||
self.KeyIds[kid] = modifier + "+" + key
|
||||
self.logView.append("热键:{0}+{1}注册{2}".format(modifier, key, "成功"))
|
||||
else:
|
||||
self.logView.append("热键:{0}+{1}注册{2}".format(modifier, key, "失败"))
|
||||
# 拦截系统的快捷键,suppress=True表示拦截,不传递到其它程序
|
||||
keyboard.add_hotkey(
|
||||
'win+s', lambda: self.logView.append('按下了win+s'), suppress=True)
|
||||
keyboard.add_hotkey(
|
||||
'win+r', lambda: self.logView.append('按下了win+r'), suppress=True)
|
||||
# 这个东西千万不能拦截掉,要出问题滴
|
||||
keyboard.add_hotkey(
|
||||
'ctrl+alt+del', lambda: self.logView.append('😏😏我知道你按了任务管理器😏😏'))
|
||||
|
||||
# 这个函数类似while True,由于这里有界面GUI的loop事件,可以达到类似的效果
|
||||
# keyboard.wait()#Block forever, like `while True`.==
|
||||
|
||||
def onShow(self):
|
||||
"""显示"""
|
||||
self.logView.append('按下alt+s')
|
||||
self.show()
|
||||
self.showNormal()
|
||||
|
||||
def onHide(self):
|
||||
"""隐藏"""
|
||||
self.logView.append('按下ctrl+s')
|
||||
self.hide()
|
||||
|
||||
def onQuit(self):
|
||||
# 退出程序
|
||||
for kid in self.KeyIds:
|
||||
self.unregisterHotKey(kid)
|
||||
"""退出函数"""
|
||||
keyboard.unhook_all_hotkeys() # 取消所有热键
|
||||
QApplication.instance().quit()
|
||||
|
||||
def closeEvent(self, event):
|
||||
|
@ -81,30 +69,9 @@ class Window(QWidget):
|
|||
self.hide()
|
||||
return event.ignore()
|
||||
|
||||
# 能监听热键,但是有个问题就是其它程序无法接受到事件
|
||||
# 比如Ctrl+S,在记事本里随便输入内容按下Ctrl+S发现无法保存
|
||||
def nativeEvent(self, eventType, message):
|
||||
if eventType == "windows_generic_MSG" or eventType == "windows_dispatcher_MSG":
|
||||
msg = ctypes.wintypes.MSG.from_address(message.__int__())
|
||||
# 这段代码无法运行
|
||||
# if ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0,
|
||||
# 0) != 0:
|
||||
if msg.message == WM_HOTKEY:
|
||||
if msg.wParam == 1: # Alt+S
|
||||
self.show()
|
||||
self.logView.append("id:{0}, {1} at time:{2}".format(
|
||||
msg.wParam, self.KeyIds.get(msg.wParam, None), datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
|
||||
return True, 0
|
||||
return super(Window, self).nativeEvent(eventType, message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
w.registerHotKey(1, "Alt", "S")
|
||||
w.registerHotKey(2, "Ctrl", "S")
|
||||
w.registerHotKey(3, "Shift", "S")
|
||||
w.registerHotKey(4, "Win", "S")
|
||||
w.registerHotKey(5, "Win", "Z")
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
# PyQt全局热键 For Windows Test
|
||||
|
||||
能监听热键,但是有个问题就是其它程序无法接受到事件<br/>
|
||||
比如Ctrl+S,在记事本里随便输入内容按下Ctrl+S发现无法保存<br/>
|
||||
pip install keyboard
|
||||
|
||||
这里还有个比较好的例子[hotkey.py](https://github.com/yeejlan/py-stock-watcher/blob/87a7b7cfdeb01b44058fac6906c9cce5fd19cac0/modules/hotkey.py)
|
||||
https://github.com/892768447/keyboard
|
||||
|
||||
# 截图
|
||||
![截图](ScreenShot/1.png)
|
||||
![截图](ScreenShot/1.gif)
|
BIN
全局热键/ScreenShot/1.gif
Normal file
BIN
全局热键/ScreenShot/1.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 245 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
1
全局热键/requirements.txt
Normal file
1
全局热键/requirements.txt
Normal file
|
@ -0,0 +1 @@
|
|||
keyboard
|
93
嵌入外部窗口/EmbedWidget.py
Normal file
93
嵌入外部窗口/EmbedWidget.py
Normal file
|
@ -0,0 +1,93 @@
|
|||
from PyQt5.QtGui import QWindow
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QListWidget,\
|
||||
QLabel
|
||||
import win32con
|
||||
import win32gui
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
self.resize(800, 600)
|
||||
layout = QVBoxLayout(self)
|
||||
|
||||
self.myhwnd = int(self.winId()) # 自己的句柄
|
||||
|
||||
layout.addWidget(QPushButton('获取所有可用、可视窗口', self,
|
||||
clicked=self._getWindowList, maximumHeight=30))
|
||||
layout.addWidget(
|
||||
QLabel('双击列表中的项目则进行嵌入目标窗口到下方\n格式为:句柄|父句柄|标题|类名', self, maximumHeight=30))
|
||||
self.windowList = QListWidget(
|
||||
self, itemDoubleClicked=self.onItemDoubleClicked, maximumHeight=200)
|
||||
layout.addWidget(self.windowList)
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""窗口关闭"""
|
||||
if self.layout().count() == 4:
|
||||
self.restore()
|
||||
super(Window, self).closeEvent(event)
|
||||
|
||||
def _getWindowList(self):
|
||||
"""清空原来的列表"""
|
||||
self.windowList.clear()
|
||||
win32gui.EnumWindows(self._enumWindows, None)
|
||||
|
||||
def onItemDoubleClicked(self, item):
|
||||
"""列表双击选择事件"""
|
||||
# 先移除掉item
|
||||
self.windowList.takeItem(self.windowList.indexFromItem(item).row())
|
||||
hwnd, phwnd, _, _ = item.text().split('|')
|
||||
# 开始嵌入
|
||||
|
||||
if self.layout().count() == 4:
|
||||
# 如果数量等于4说明之前已经嵌入了一个窗口,现在需要把它释放出来
|
||||
self.restore()
|
||||
hwnd, phwnd = int(hwnd), int(phwnd)
|
||||
# 嵌入之前的属性
|
||||
style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE)
|
||||
exstyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
|
||||
print('save', hwnd, style, exstyle)
|
||||
|
||||
widget = QWidget.createWindowContainer(QWindow.fromWinId(hwnd))
|
||||
widget.hwnd = hwnd # 窗口句柄
|
||||
widget.phwnd = phwnd # 父窗口句柄
|
||||
widget.style = style # 窗口样式
|
||||
widget.exstyle = exstyle # 窗口额外样式
|
||||
self.layout().addWidget(widget)
|
||||
|
||||
def restore(self):
|
||||
"""归还窗口"""
|
||||
# 有bug,归还后窗口没有了WS_VISIBLE样式,不可见
|
||||
widget = self.layout().itemAt(3).widget()
|
||||
print('restore', widget.hwnd, widget.style, widget.exstyle)
|
||||
win32gui.SetParent(widget.hwnd, widget.phwnd) # 让它返回它的父窗口
|
||||
win32gui.SetWindowLong(
|
||||
widget.hwnd, win32con.GWL_STYLE, widget.style | win32con.WS_VISIBLE) # 恢复样式
|
||||
win32gui.SetWindowLong(
|
||||
widget.hwnd, win32con.GWL_EXSTYLE, widget.exstyle) # 恢复样式
|
||||
win32gui.ShowWindow(
|
||||
widget.hwnd, win32con.SW_SHOW) # 显示窗口
|
||||
widget.close()
|
||||
self.layout().removeWidget(widget) # 从布局中移出
|
||||
widget.deleteLater()
|
||||
|
||||
def _enumWindows(self, hwnd, _):
|
||||
"""遍历回调函数"""
|
||||
if hwnd == self.myhwnd:
|
||||
return # 防止自己嵌入自己
|
||||
if win32gui.IsWindow(hwnd) and win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd):
|
||||
phwnd = win32gui.GetParent(hwnd)
|
||||
title = win32gui.GetWindowText(hwnd)
|
||||
name = win32gui.GetClassName(hwnd)
|
||||
self.windowList.addItem(
|
||||
'{0}|{1}|\t标题:{2}\t|\t类名:{3}'.format(hwnd, phwnd, title, name))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
11
嵌入外部窗口/README.md
Normal file
11
嵌入外部窗口/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# 内嵌外部窗口
|
||||
|
||||
### 原理思路:
|
||||
- 1.使用SetParent函数设置外部窗口的parent为Qt的窗口
|
||||
- 2.Qt使用QWidget.createWindowContainer(QWindow.fromWinId(窗口ID))生成QWidget
|
||||
- 3.使用GetWindowLong得到原来窗口的样式属性(style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE)和exstyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE))
|
||||
- 4.这里还原窗口后不会显示,用spy++发现没有了WS_VISIBLE样式(未解决)
|
||||
|
||||
截图
|
||||
|
||||
![1](ScreenShot/1.gif)
|
BIN
嵌入外部窗口/ScreenShot/1.gif
Normal file
BIN
嵌入外部窗口/ScreenShot/1.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 344 KiB |
Loading…
Reference in a new issue