update
|
@ -2,7 +2,7 @@
|
||||||
<module type="PYTHON_MODULE" version="4">
|
<module type="PYTHON_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager">
|
<component name="NewModuleRootManager">
|
||||||
<content url="file://$MODULE_DIR$" />
|
<content url="file://$MODULE_DIR$" />
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="jdk" jdkName="Python 3.4" jdkType="Python SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
<component name="TestRunnerService">
|
<component name="TestRunnerService">
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
# Animation
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月28日
|
Created on 2017年12月28日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: charts.bar.BarStack
|
@file: charts.bar.BarStack
|
||||||
@description: like http://echarts.baidu.com/demo.html#bar-stack
|
@description: like http://echarts.baidu.com/demo.html#bar-stack
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月28日
|
Created on 2017年12月28日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: charts.line.LineStack
|
@file: charts.line.LineStack
|
||||||
@description: like http://echarts.baidu.com/demo.html#line-stack
|
@description: like http://echarts.baidu.com/demo.html#line-stack
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月23日
|
Created on 2017年12月23日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: ToolTip
|
@file: ToolTip
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月23日
|
Created on 2017年12月23日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: ToolTip2
|
@file: ToolTip2
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"""
|
"""
|
||||||
Created on 2018年1月27日
|
Created on 2018年1月27日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: CityLinkage
|
@file: CityLinkage
|
||||||
@description: 下拉联动
|
@description: 下拉联动
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年2月4日
|
Created on 2018年2月4日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: TencentMovieHotPlay_Flow
|
@file: TencentMovieHotPlay_Flow
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
"""
|
||||||
Created on 2017年12月23日
|
Created on 2017年12月23日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: 添加QWidget
|
@file: AddQWidget
|
||||||
@description:
|
@description:
|
||||||
'''
|
"""
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
|
@ -0,0 +1,16 @@
|
||||||
|
# QGraphicsView
|
||||||
|
|
||||||
|
## 1、绘制世界地图
|
||||||
|
[运行 WorldMap.py](WorldMap.py)
|
||||||
|
|
||||||
|
1. 解析json数据生成 `QPolygonF`
|
||||||
|
2. 使用Ctrl+滑轮进行放大缩小
|
||||||
|
|
||||||
|
![WorldMap](ScreenShot/WorldMap.gif)
|
||||||
|
|
||||||
|
## 2、添加QWidget
|
||||||
|
[运行 AddQWidget.py](AddQWidget.py)
|
||||||
|
|
||||||
|
通过 `QGraphicsScene.addWidget` 添加自定义QWidget
|
||||||
|
|
||||||
|
![AddQWidget](ScreenShot/AddQWidget.png)
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
BIN
QGraphicsView/ScreenShot/WorldMap.gif
Normal file
After Width: | Height: | Size: 460 KiB |
|
@ -1,14 +1,14 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
"""
|
||||||
Created on 2017年12月17日
|
Created on 2017年12月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: WorldMap
|
@file: WorldMap
|
||||||
@description:
|
@description:
|
||||||
'''
|
"""
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
|
|
||||||
|
@ -128,7 +128,7 @@ class GraphicsView(QGraphicsView):
|
||||||
|
|
||||||
def initMap(self):
|
def initMap(self):
|
||||||
features = json.load(
|
features = json.load(
|
||||||
open("world.json", encoding="utf8")).get("features")
|
open("Data/world.json", encoding="utf8")).get("features")
|
||||||
for feature in features:
|
for feature in features:
|
||||||
geometry = feature.get("geometry")
|
geometry = feature.get("geometry")
|
||||||
if not geometry:
|
if not geometry:
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年2月4日
|
Created on 2018年2月4日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: TencentMovieHotPlay
|
@file: TencentMovieHotPlay
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月23日
|
Created on 2017年12月23日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: ShowImage
|
@file: ShowImage
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年2月4日
|
Created on 2018年2月4日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: TencentMovieHotPlay_ListWidget
|
@file: TencentMovieHotPlay_ListWidget
|
||||||
@description:
|
@description:
|
||||||
|
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 107 KiB |
1
QPropertyAnimation/README.en.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# QPropertyAnimation
|
|
@ -1,4 +1,4 @@
|
||||||
# Animation
|
# QPropertyAnimation
|
||||||
|
|
||||||
# 1、窗口淡入淡出
|
# 1、窗口淡入淡出
|
||||||
[运行 FadeInOut.py](FadeInOut.py)
|
[运行 FadeInOut.py](FadeInOut.py)
|
Before Width: | Height: | Size: 630 KiB After Width: | Height: | Size: 630 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月10日
|
Created on 2017年12月10日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: GetCookie
|
@file: GetCookie
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月10日
|
Created on 2017年12月10日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: GetCookie
|
@file: GetCookie
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -9,7 +9,6 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站
|
||||||
| 分类 | 目录 |
|
| 分类 | 目录 |
|
||||||
|:-------|:-------|
|
|:-------|:-------|
|
||||||
| ActiveX | [QAxWidget](QAxWidget)
|
| ActiveX | [QAxWidget](QAxWidget)
|
||||||
| 动画 | [Animation](Animation)
|
|
||||||
| 日历 | [QCalendarWidget](QCalendarWidget)
|
| 日历 | [QCalendarWidget](QCalendarWidget)
|
||||||
| 复选框 | [QCheckBox](QCheckBox)
|
| 复选框 | [QCheckBox](QCheckBox)
|
||||||
| 列视图 | [QColumnView](QColumnView)
|
| 列视图 | [QColumnView](QColumnView)
|
||||||
|
@ -37,6 +36,7 @@ https://pyqt5.com 社区是专门针对PyQt5学习和提升开设的博客网站
|
||||||
| OpenGL | [QOpenGLWidget](QOpenGLWidget)
|
| OpenGL | [QOpenGLWidget](QOpenGLWidget)
|
||||||
| 纯文本 | [QPlainTextEdit](QPlainTextEdit)
|
| 纯文本 | [QPlainTextEdit](QPlainTextEdit)
|
||||||
| 进度条 | [QProgressBar](QProgressBar)
|
| 进度条 | [QProgressBar](QProgressBar)
|
||||||
|
| 动画 | [QPropertyAnimation](QPropertyAnimation)
|
||||||
| 代理样式 | [QProxyStyle](QProxyStyle)
|
| 代理样式 | [QProxyStyle](QProxyStyle)
|
||||||
| 按钮 | [QPushButton](QPushButton)
|
| 按钮 | [QPushButton](QPushButton)
|
||||||
| 单选框 | [QRadioButton](QRadioButton)
|
| 单选框 | [QRadioButton](QRadioButton)
|
||||||
|
|
|
@ -1,44 +1,44 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年05月01日
|
Created on 2018年05月01日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: qrctest1
|
@file: qrctest1
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
from PyQt5.QtWidgets import QLabel
|
from PyQt5.QtWidgets import QLabel
|
||||||
|
|
||||||
import res_rc # @UnusedImport @UnresolvedImport
|
import res_rc # @UnusedImport @UnresolvedImport
|
||||||
|
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
|
|
||||||
|
|
||||||
class ImageView(QLabel):
|
class ImageView(QLabel):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ImageView, self).__init__(*args, **kwargs)
|
super(ImageView, self).__init__(*args, **kwargs)
|
||||||
self.resize(800, 600)
|
self.resize(800, 600)
|
||||||
|
|
||||||
# 从资源文件res_rc.py中加载
|
# 从资源文件res_rc.py中加载
|
||||||
# 转换命令pyrcc5 res.qrc -o res_rc.py
|
# 转换命令pyrcc5 res.qrc -o res_rc.py
|
||||||
# 这种方式是从通过pyrcc5转换res.qrc为res_rc.py文件,可以直接import加载
|
# 这种方式是从通过pyrcc5转换res.qrc为res_rc.py文件,可以直接import加载
|
||||||
# 此时可以通过路径:/images/head.jpg来访问
|
# 此时可以通过路径:/images/head.jpg来访问
|
||||||
self.setPixmap(QPixmap(":/images/head.jpg"))
|
self.setPixmap(QPixmap(":/images/head.jpg"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt5.QtWidgets import QApplication
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.aboutToQuit.connect(res_rc.qCleanupResources) # 退出时要清理资源
|
app.aboutToQuit.connect(res_rc.qCleanupResources) # 退出时要清理资源
|
||||||
w = ImageView()
|
w = ImageView()
|
||||||
w.show()
|
w.show()
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
|
@ -1,44 +1,44 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年05月01日
|
Created on 2018年05月01日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: qrctest2
|
@file: qrctest2
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
from PyQt5.QtCore import QResource
|
from PyQt5.QtCore import QResource
|
||||||
from PyQt5.QtGui import QPixmap
|
from PyQt5.QtGui import QPixmap
|
||||||
from PyQt5.QtWidgets import QLabel
|
from PyQt5.QtWidgets import QLabel
|
||||||
|
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
|
|
||||||
|
|
||||||
class ImageView(QLabel):
|
class ImageView(QLabel):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(ImageView, self).__init__(*args, **kwargs)
|
super(ImageView, self).__init__(*args, **kwargs)
|
||||||
self.resize(800, 600)
|
self.resize(800, 600)
|
||||||
self.setPixmap(QPixmap(":/images/head.jpg"))
|
self.setPixmap(QPixmap(":/images/head.jpg"))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt5.QtWidgets import QApplication
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
# 从二进制资源文件res.data中加载
|
# 从二进制资源文件res.data中加载
|
||||||
# 转换命令cd tools
|
# 转换命令cd tools
|
||||||
# rcc.exe -binary ../res.qrc -o ../res.data
|
# rcc.exe -binary ../res.qrc -o ../res.data
|
||||||
# 此时需要注册
|
# 此时需要注册
|
||||||
QResource.registerResource("res.data")
|
QResource.registerResource("res.data")
|
||||||
app.aboutToQuit.connect(lambda: QResource.unregisterResource("res.data"))
|
app.aboutToQuit.connect(lambda: QResource.unregisterResource("res.data"))
|
||||||
w = ImageView()
|
w = ImageView()
|
||||||
w.show()
|
w.show()
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
|
@ -1,113 +1,113 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月29日
|
Created on 2018年1月29日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: OpencvWidget
|
@file: OpencvWidget
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt5.QtCore import QTimer
|
from PyQt5.QtCore import QTimer
|
||||||
from PyQt5.QtGui import QImage, QPixmap
|
from PyQt5.QtGui import QImage, QPixmap
|
||||||
from PyQt5.QtWidgets import QLabel, QMessageBox, QApplication
|
from PyQt5.QtWidgets import QLabel, QMessageBox, QApplication
|
||||||
import cv2 # @UnresolvedImport
|
import cv2 # @UnresolvedImport
|
||||||
import dlib
|
import dlib
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
|
|
||||||
DOWNSCALE = 4
|
DOWNSCALE = 4
|
||||||
|
|
||||||
|
|
||||||
class OpencvWidget(QLabel):
|
class OpencvWidget(QLabel):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(OpencvWidget, self).__init__(*args, **kwargs)
|
super(OpencvWidget, self).__init__(*args, **kwargs)
|
||||||
self.fps = 24
|
self.fps = 24
|
||||||
self.resize(800, 600)
|
self.resize(800, 600)
|
||||||
self.setText("请稍候,正在初始化数据和摄像头。。。")
|
self.setText("请稍候,正在初始化数据和摄像头。。。")
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
try:
|
try:
|
||||||
# 检测相关
|
# 检测相关
|
||||||
self.detector = dlib.get_frontal_face_detector()
|
self.detector = dlib.get_frontal_face_detector()
|
||||||
self.predictor = dlib.shape_predictor(
|
self.predictor = dlib.shape_predictor(
|
||||||
"data/shape_predictor_68_face_landmarks.dat")
|
"data/shape_predictor_68_face_landmarks.dat")
|
||||||
cascade_fn = "data/lbpcascades/lbpcascade_frontalface.xml"
|
cascade_fn = "data/lbpcascades/lbpcascade_frontalface.xml"
|
||||||
self.cascade = cv2.CascadeClassifier(cascade_fn)
|
self.cascade = cv2.CascadeClassifier(cascade_fn)
|
||||||
if not self.cascade:
|
if not self.cascade:
|
||||||
return QMessageBox.critical(self, "错误", cascade_fn + " 无法找到")
|
return QMessageBox.critical(self, "错误", cascade_fn + " 无法找到")
|
||||||
self.cap = cv2.VideoCapture(0)
|
self.cap = cv2.VideoCapture(0)
|
||||||
if not self.cap or not self.cap.isOpened():
|
if not self.cap or not self.cap.isOpened():
|
||||||
return QMessageBox.critical(self, "错误", "打开摄像头失败")
|
return QMessageBox.critical(self, "错误", "打开摄像头失败")
|
||||||
# 开启定时器定时捕获
|
# 开启定时器定时捕获
|
||||||
self.timer = QTimer(self, timeout=self.onCapture)
|
self.timer = QTimer(self, timeout=self.onCapture)
|
||||||
self.timer.start(1000 / self.fps)
|
self.timer.start(1000 / self.fps)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "错误", str(e))
|
QMessageBox.critical(self, "错误", str(e))
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
if hasattr(self, "timer"):
|
if hasattr(self, "timer"):
|
||||||
self.timer.stop()
|
self.timer.stop()
|
||||||
self.timer.deleteLater()
|
self.timer.deleteLater()
|
||||||
self.cap.release()
|
self.cap.release()
|
||||||
del self.predictor, self.detector, self.cascade, self.cap
|
del self.predictor, self.detector, self.cascade, self.cap
|
||||||
super(OpencvWidget, self).closeEvent(event)
|
super(OpencvWidget, self).closeEvent(event)
|
||||||
self.deleteLater()
|
self.deleteLater()
|
||||||
|
|
||||||
def onCapture(self):
|
def onCapture(self):
|
||||||
_, frame = self.cap.read()
|
_, frame = self.cap.read()
|
||||||
|
|
||||||
minisize = (
|
minisize = (
|
||||||
int(frame.shape[1] / DOWNSCALE), int(frame.shape[0] / DOWNSCALE))
|
int(frame.shape[1] / DOWNSCALE), int(frame.shape[0] / DOWNSCALE))
|
||||||
tmpframe = cv2.resize(frame, minisize)
|
tmpframe = cv2.resize(frame, minisize)
|
||||||
tmpframe = cv2.cvtColor(tmpframe, cv2.COLOR_BGR2GRAY) # 做灰度处理
|
tmpframe = cv2.cvtColor(tmpframe, cv2.COLOR_BGR2GRAY) # 做灰度处理
|
||||||
tmpframe = cv2.equalizeHist(tmpframe)
|
tmpframe = cv2.equalizeHist(tmpframe)
|
||||||
|
|
||||||
# minNeighbors表示每一个目标至少要被检测到5次
|
# minNeighbors表示每一个目标至少要被检测到5次
|
||||||
faces = self.cascade.detectMultiScale(tmpframe, minNeighbors=5)
|
faces = self.cascade.detectMultiScale(tmpframe, minNeighbors=5)
|
||||||
del tmpframe
|
del tmpframe
|
||||||
if len(faces) < 1: # 没有检测到脸
|
if len(faces) < 1: # 没有检测到脸
|
||||||
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
img = QImage(
|
img = QImage(
|
||||||
frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888)
|
frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888)
|
||||||
del frame
|
del frame
|
||||||
return self.setPixmap(QPixmap.fromImage(img))
|
return self.setPixmap(QPixmap.fromImage(img))
|
||||||
# 特征点检测描绘
|
# 特征点检测描绘
|
||||||
for x, y, w, h in faces:
|
for x, y, w, h in faces:
|
||||||
x, y, w, h = x * DOWNSCALE, y * DOWNSCALE, w * DOWNSCALE, h * DOWNSCALE
|
x, y, w, h = x * DOWNSCALE, y * DOWNSCALE, w * DOWNSCALE, h * DOWNSCALE
|
||||||
# 画脸矩形
|
# 画脸矩形
|
||||||
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0))
|
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0))
|
||||||
# 截取的人脸部分
|
# 截取的人脸部分
|
||||||
tmpframe = frame[y:y + h, x:x + w]
|
tmpframe = frame[y:y + h, x:x + w]
|
||||||
# 进行特征点描绘
|
# 进行特征点描绘
|
||||||
rects = self.detector(tmpframe, 1)
|
rects = self.detector(tmpframe, 1)
|
||||||
if len(rects) > 0:
|
if len(rects) > 0:
|
||||||
landmarks = numpy.matrix(
|
landmarks = numpy.matrix(
|
||||||
[[p.x, p.y] for p in self.predictor(tmpframe, rects[0]).parts()])
|
[[p.x, p.y] for p in self.predictor(tmpframe, rects[0]).parts()])
|
||||||
for _, point in enumerate(landmarks):
|
for _, point in enumerate(landmarks):
|
||||||
pos = (point[0, 0] + x, point[0, 1] + y)
|
pos = (point[0, 0] + x, point[0, 1] + y)
|
||||||
# 在原来画面上画点
|
# 在原来画面上画点
|
||||||
cv2.circle(frame, pos, 3, color=(0, 255, 0))
|
cv2.circle(frame, pos, 3, color=(0, 255, 0))
|
||||||
# 转成Qt能显示的
|
# 转成Qt能显示的
|
||||||
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
img = QImage(
|
img = QImage(
|
||||||
frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888)
|
frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888)
|
||||||
del frame
|
del frame
|
||||||
self.setPixmap(QPixmap.fromImage(img))
|
self.setPixmap(QPixmap.fromImage(img))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
w = OpencvWidget()
|
w = OpencvWidget()
|
||||||
w.show()
|
w.show()
|
||||||
# 5秒后启动
|
# 5秒后启动
|
||||||
QTimer.singleShot(5000, w.start)
|
QTimer.singleShot(5000, w.start)
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月11日
|
Created on 2017年12月11日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: HotKey
|
@file: HotKey
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -1,163 +1,163 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月27日
|
Created on 2018年1月27日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: BubbleTips
|
@file: BubbleTips
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt5.QtCore import QRectF, Qt, QPropertyAnimation, pyqtProperty, \
|
from PyQt5.QtCore import QRectF, Qt, QPropertyAnimation, pyqtProperty, \
|
||||||
QPoint, QParallelAnimationGroup, QEasingCurve
|
QPoint, QParallelAnimationGroup, QEasingCurve
|
||||||
from PyQt5.QtGui import QPainter, QPainterPath, QColor, QPen
|
from PyQt5.QtGui import QPainter, QPainterPath, QColor, QPen
|
||||||
from PyQt5.QtWidgets import QLabel, QWidget, QVBoxLayout, QApplication,\
|
from PyQt5.QtWidgets import QLabel, QWidget, QVBoxLayout, QApplication,\
|
||||||
QLineEdit, QPushButton
|
QLineEdit, QPushButton
|
||||||
|
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
|
|
||||||
|
|
||||||
class BubbleLabel(QWidget):
|
class BubbleLabel(QWidget):
|
||||||
|
|
||||||
BackgroundColor = QColor(195, 195, 195)
|
BackgroundColor = QColor(195, 195, 195)
|
||||||
BorderColor = QColor(150, 150, 150)
|
BorderColor = QColor(150, 150, 150)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
text = kwargs.pop("text", "")
|
text = kwargs.pop("text", "")
|
||||||
super(BubbleLabel, self).__init__(*args, **kwargs)
|
super(BubbleLabel, self).__init__(*args, **kwargs)
|
||||||
# 设置无边框置顶
|
# 设置无边框置顶
|
||||||
self.setWindowFlags(
|
self.setWindowFlags(
|
||||||
Qt.Window | Qt.Tool | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint)
|
Qt.Window | Qt.Tool | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint)
|
||||||
# 设置最小宽度和高度
|
# 设置最小宽度和高度
|
||||||
self.setMinimumWidth(200)
|
self.setMinimumWidth(200)
|
||||||
self.setMinimumHeight(48)
|
self.setMinimumHeight(48)
|
||||||
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
# 左上右下的边距(下方16是因为包括了三角形)
|
# 左上右下的边距(下方16是因为包括了三角形)
|
||||||
layout.setContentsMargins(8, 8, 8, 16)
|
layout.setContentsMargins(8, 8, 8, 16)
|
||||||
self.label = QLabel(self)
|
self.label = QLabel(self)
|
||||||
layout.addWidget(self.label)
|
layout.addWidget(self.label)
|
||||||
self.setText(text)
|
self.setText(text)
|
||||||
# 获取屏幕高宽
|
# 获取屏幕高宽
|
||||||
self._desktop = QApplication.instance().desktop()
|
self._desktop = QApplication.instance().desktop()
|
||||||
|
|
||||||
def setText(self, text):
|
def setText(self, text):
|
||||||
self.label.setText(text)
|
self.label.setText(text)
|
||||||
|
|
||||||
def text(self):
|
def text(self):
|
||||||
return self.label.text()
|
return self.label.text()
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.hide()
|
self.hide()
|
||||||
self.animationGroup.stop()
|
self.animationGroup.stop()
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
super(BubbleLabel, self).show()
|
super(BubbleLabel, self).show()
|
||||||
# 窗口开始位置
|
# 窗口开始位置
|
||||||
startPos = QPoint(
|
startPos = QPoint(
|
||||||
self._desktop.screenGeometry().width() - self.width() - 100,
|
self._desktop.screenGeometry().width() - self.width() - 100,
|
||||||
self._desktop.availableGeometry().height() - self.height())
|
self._desktop.availableGeometry().height() - self.height())
|
||||||
endPos = QPoint(
|
endPos = QPoint(
|
||||||
self._desktop.screenGeometry().width() - self.width() - 100,
|
self._desktop.screenGeometry().width() - self.width() - 100,
|
||||||
self._desktop.availableGeometry().height() - self.height() * 3 - 5)
|
self._desktop.availableGeometry().height() - self.height() * 3 - 5)
|
||||||
print(startPos, endPos)
|
print(startPos, endPos)
|
||||||
self.move(startPos)
|
self.move(startPos)
|
||||||
# 初始化动画
|
# 初始化动画
|
||||||
self.initAnimation(startPos, endPos)
|
self.initAnimation(startPos, endPos)
|
||||||
|
|
||||||
def initAnimation(self, startPos, endPos):
|
def initAnimation(self, startPos, endPos):
|
||||||
# 透明度动画
|
# 透明度动画
|
||||||
opacityAnimation = QPropertyAnimation(self, b"opacity")
|
opacityAnimation = QPropertyAnimation(self, b"opacity")
|
||||||
opacityAnimation.setStartValue(1.0)
|
opacityAnimation.setStartValue(1.0)
|
||||||
opacityAnimation.setEndValue(0.0)
|
opacityAnimation.setEndValue(0.0)
|
||||||
# 设置动画曲线
|
# 设置动画曲线
|
||||||
opacityAnimation.setEasingCurve(QEasingCurve.InQuad)
|
opacityAnimation.setEasingCurve(QEasingCurve.InQuad)
|
||||||
opacityAnimation.setDuration(4000) # 在4秒的时间内完成
|
opacityAnimation.setDuration(4000) # 在4秒的时间内完成
|
||||||
# 往上移动动画
|
# 往上移动动画
|
||||||
moveAnimation = QPropertyAnimation(self, b"pos")
|
moveAnimation = QPropertyAnimation(self, b"pos")
|
||||||
moveAnimation.setStartValue(startPos)
|
moveAnimation.setStartValue(startPos)
|
||||||
moveAnimation.setEndValue(endPos)
|
moveAnimation.setEndValue(endPos)
|
||||||
moveAnimation.setEasingCurve(QEasingCurve.InQuad)
|
moveAnimation.setEasingCurve(QEasingCurve.InQuad)
|
||||||
moveAnimation.setDuration(5000) # 在5秒的时间内完成
|
moveAnimation.setDuration(5000) # 在5秒的时间内完成
|
||||||
# 并行动画组(目的是让上面的两个动画同时进行)
|
# 并行动画组(目的是让上面的两个动画同时进行)
|
||||||
self.animationGroup = QParallelAnimationGroup(self)
|
self.animationGroup = QParallelAnimationGroup(self)
|
||||||
self.animationGroup.addAnimation(opacityAnimation)
|
self.animationGroup.addAnimation(opacityAnimation)
|
||||||
self.animationGroup.addAnimation(moveAnimation)
|
self.animationGroup.addAnimation(moveAnimation)
|
||||||
self.animationGroup.finished.connect(self.close) # 动画结束时关闭窗口
|
self.animationGroup.finished.connect(self.close) # 动画结束时关闭窗口
|
||||||
self.animationGroup.start()
|
self.animationGroup.start()
|
||||||
|
|
||||||
def paintEvent(self, event):
|
def paintEvent(self, event):
|
||||||
super(BubbleLabel, self).paintEvent(event)
|
super(BubbleLabel, self).paintEvent(event)
|
||||||
painter = QPainter(self)
|
painter = QPainter(self)
|
||||||
painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿
|
painter.setRenderHint(QPainter.Antialiasing) # 抗锯齿
|
||||||
|
|
||||||
rectPath = QPainterPath() # 圆角矩形
|
rectPath = QPainterPath() # 圆角矩形
|
||||||
triPath = QPainterPath() # 底部三角形
|
triPath = QPainterPath() # 底部三角形
|
||||||
|
|
||||||
height = self.height() - 8 # 往上偏移8
|
height = self.height() - 8 # 往上偏移8
|
||||||
rectPath.addRoundedRect(QRectF(0, 0, self.width(), height), 5, 5)
|
rectPath.addRoundedRect(QRectF(0, 0, self.width(), height), 5, 5)
|
||||||
x = self.width() / 5 * 4
|
x = self.width() / 5 * 4
|
||||||
triPath.moveTo(x, height) # 移动到底部横线4/5处
|
triPath.moveTo(x, height) # 移动到底部横线4/5处
|
||||||
# 画三角形
|
# 画三角形
|
||||||
triPath.lineTo(x + 6, height + 8)
|
triPath.lineTo(x + 6, height + 8)
|
||||||
triPath.lineTo(x + 12, height)
|
triPath.lineTo(x + 12, height)
|
||||||
|
|
||||||
rectPath.addPath(triPath) # 添加三角形到之前的矩形上
|
rectPath.addPath(triPath) # 添加三角形到之前的矩形上
|
||||||
|
|
||||||
# 边框画笔
|
# 边框画笔
|
||||||
painter.setPen(QPen(self.BorderColor, 1, Qt.SolidLine,
|
painter.setPen(QPen(self.BorderColor, 1, Qt.SolidLine,
|
||||||
Qt.RoundCap, Qt.RoundJoin))
|
Qt.RoundCap, Qt.RoundJoin))
|
||||||
# 背景画刷
|
# 背景画刷
|
||||||
painter.setBrush(self.BackgroundColor)
|
painter.setBrush(self.BackgroundColor)
|
||||||
# 绘制形状
|
# 绘制形状
|
||||||
painter.drawPath(rectPath)
|
painter.drawPath(rectPath)
|
||||||
# 三角形底边绘制一条线保证颜色与背景一样
|
# 三角形底边绘制一条线保证颜色与背景一样
|
||||||
painter.setPen(QPen(self.BackgroundColor, 1,
|
painter.setPen(QPen(self.BackgroundColor, 1,
|
||||||
Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
|
Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
|
||||||
painter.drawLine(x, height, x + 12, height)
|
painter.drawLine(x, height, x + 12, height)
|
||||||
|
|
||||||
def windowOpacity(self):
|
def windowOpacity(self):
|
||||||
return super(BubbleLabel, self).windowOpacity()
|
return super(BubbleLabel, self).windowOpacity()
|
||||||
|
|
||||||
def setWindowOpacity(self, opacity):
|
def setWindowOpacity(self, opacity):
|
||||||
super(BubbleLabel, self).setWindowOpacity(opacity)
|
super(BubbleLabel, self).setWindowOpacity(opacity)
|
||||||
|
|
||||||
# 由于opacity属性不在QWidget中需要重新定义一个
|
# 由于opacity属性不在QWidget中需要重新定义一个
|
||||||
opacity = pyqtProperty(float, windowOpacity, setWindowOpacity)
|
opacity = pyqtProperty(float, windowOpacity, setWindowOpacity)
|
||||||
|
|
||||||
|
|
||||||
class TestWidget(QWidget):
|
class TestWidget(QWidget):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(TestWidget, self).__init__(*args, **kwargs)
|
super(TestWidget, self).__init__(*args, **kwargs)
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
self.msgEdit = QLineEdit(self, returnPressed=self.onMsgShow)
|
self.msgEdit = QLineEdit(self, returnPressed=self.onMsgShow)
|
||||||
self.msgButton = QPushButton("显示内容", self, clicked=self.onMsgShow)
|
self.msgButton = QPushButton("显示内容", self, clicked=self.onMsgShow)
|
||||||
layout.addWidget(self.msgEdit)
|
layout.addWidget(self.msgEdit)
|
||||||
layout.addWidget(self.msgButton)
|
layout.addWidget(self.msgButton)
|
||||||
|
|
||||||
def onMsgShow(self):
|
def onMsgShow(self):
|
||||||
msg = self.msgEdit.text().strip()
|
msg = self.msgEdit.text().strip()
|
||||||
if not msg:
|
if not msg:
|
||||||
return
|
return
|
||||||
if hasattr(self, "_blabel"):
|
if hasattr(self, "_blabel"):
|
||||||
self._blabel.stop()
|
self._blabel.stop()
|
||||||
self._blabel.deleteLater()
|
self._blabel.deleteLater()
|
||||||
del self._blabel
|
del self._blabel
|
||||||
self._blabel = BubbleLabel()
|
self._blabel = BubbleLabel()
|
||||||
self._blabel.setText(msg)
|
self._blabel.setText(msg)
|
||||||
self._blabel.show()
|
self._blabel.show()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
w = TestWidget()
|
w = TestWidget()
|
||||||
w.show()
|
w.show()
|
||||||
sys.exit(app.exec_())
|
sys.exit(app.exec_())
|
||||||
|
|
|
@ -1,57 +1,57 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月28日
|
Created on 2018年1月28日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: IronyImporter
|
@file: IronyImporter
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
import base64
|
import base64
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
|
||||||
import xxtea # @UnresolvedImport
|
import xxtea # @UnresolvedImport
|
||||||
|
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
|
|
||||||
KEY = base64.b85decode("HF5^hbNbOVOKM=(SB`7h")
|
KEY = base64.b85decode("HF5^hbNbOVOKM=(SB`7h")
|
||||||
|
|
||||||
|
|
||||||
class IronyImporter:
|
class IronyImporter:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def find_module(cls, name, path=None):
|
def find_module(cls, name, path=None):
|
||||||
name = name + ".irony"
|
name = name + ".irony"
|
||||||
if not os.path.isfile(name):
|
if not os.path.isfile(name):
|
||||||
return None
|
return None
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_module(cls, name):
|
def load_module(cls, name):
|
||||||
if name in sys.modules:
|
if name in sys.modules:
|
||||||
return sys.modules[name]
|
return sys.modules[name]
|
||||||
mod = ModuleType(name)
|
mod = ModuleType(name)
|
||||||
mod.__loader__ = cls
|
mod.__loader__ = cls
|
||||||
mod.__name__ = name
|
mod.__name__ = name
|
||||||
mod.__file__ = name + ".irony"
|
mod.__file__ = name + ".irony"
|
||||||
try:
|
try:
|
||||||
exec(xxtea.decrypt(open(mod.__file__, "rb").read(), KEY), mod.__dict__)
|
exec(xxtea.decrypt(open(mod.__file__, "rb").read(), KEY), mod.__dict__)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
return None
|
return None
|
||||||
sys.modules[name] = mod
|
sys.modules[name] = mod
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def module_repr(cls, module):
|
def module_repr(cls, module):
|
||||||
return "<module {!r} from ({!r})>".format(module.__name__, module.__file__)
|
return "<module {!r} from ({!r})>".format(module.__name__, module.__file__)
|
||||||
|
|
||||||
|
|
||||||
sys.meta_path.insert(0, IronyImporter)
|
sys.meta_path.insert(0, IronyImporter)
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月28日
|
Created on 2018年1月28日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: build
|
@file: build
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
import xxtea # @UnresolvedImport
|
import xxtea # @UnresolvedImport
|
||||||
|
|
||||||
|
|
||||||
KEY = base64.b85decode("HF5^hbNbOVOKM=(SB`7h")
|
KEY = base64.b85decode("HF5^hbNbOVOKM=(SB`7h")
|
||||||
|
|
||||||
with open("src/test.py", "rb") as fi:
|
with open("src/test.py", "rb") as fi:
|
||||||
open("test.irony", "wb").write(xxtea.encrypt(fi.read(), KEY))
|
open("test.irony", "wb").write(xxtea.encrypt(fi.read(), KEY))
|
||||||
print("ok")
|
print("ok")
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月28日
|
Created on 2018年1月28日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: main
|
@file: main
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
|
|
||||||
# 首先要引入importer
|
# 首先要引入importer
|
||||||
import IronyImporter # @UnresolvedImport @UnusedImport
|
import IronyImporter # @UnresolvedImport @UnusedImport
|
||||||
|
|
||||||
|
|
||||||
# 测试开始
|
# 测试开始
|
||||||
import test
|
import test
|
||||||
print(test)
|
print(test)
|
||||||
print(dir(test))
|
print(dir(test))
|
||||||
print(test.test(1, 5)) # @UndefinedVariable
|
print(test.test(1, 5)) # @UndefinedVariable
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月28日
|
Created on 2018年1月28日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: test
|
@file: test
|
||||||
@description:
|
@description:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
|
||||||
__Version__ = "Version 1.0"
|
__Version__ = "Version 1.0"
|
||||||
|
|
||||||
|
|
||||||
def test(a, b):
|
def test(a, b):
|
||||||
return a + b
|
return a + b
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
# 图形视图QGraphicsView
|
|
||||||
|
|
||||||
## [1、 世界地图](世界地图/)
|
|
||||||
![截图](世界地图/ScreenShot/2.png)
|
|
||||||
|
|
||||||
## [2、 添加QWidget](添加QWidget.py)
|
|
||||||
![添加QWidget](ScreenShot/添加QWidget.png)
|
|
||||||
|
|
||||||
## [3、 显示图片及缩放](显示图片及缩放.py)
|
|
||||||
按下小键盘-为缩小, +为放大
|
|
||||||
|
|
||||||
![显示图片及缩放](ScreenShot/显示图片及缩放.gif)
|
|
Before Width: | Height: | Size: 381 KiB |
|
@ -1,170 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
Created on 2018年7月26日
|
|
||||||
@author: Irony
|
|
||||||
@site: https://pyqt5.com, https://github.com/892768447
|
|
||||||
@email: 892768447@qq.com
|
|
||||||
@file: QGraphicsView练习.QGraphicsItem.Item移动
|
|
||||||
@description:
|
|
||||||
"""
|
|
||||||
from PyQt5.QtCore import Qt, QLineF, QRectF
|
|
||||||
from PyQt5.QtGui import QPainter, QColor, QPen
|
|
||||||
from PyQt5.QtWidgets import QGraphicsRectItem, QGraphicsView, QGraphicsScene,\
|
|
||||||
QStyle
|
|
||||||
|
|
||||||
|
|
||||||
__Author__ = """By: Irony
|
|
||||||
QQ: 892768447
|
|
||||||
Email: 892768447@qq.com"""
|
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony"
|
|
||||||
__Version__ = "Version 1.0"
|
|
||||||
|
|
||||||
|
|
||||||
class MoveableItem(QGraphicsRectItem):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(MoveableItem, self).__init__(*args, **kwargs)
|
|
||||||
self.setPos(0, 0)
|
|
||||||
# 可移动,可选择,有焦点,发送大小位置改变事件
|
|
||||||
self.setFlags(self.ItemIsMovable | self.ItemIsSelectable |
|
|
||||||
self.ItemIsFocusable | self.ItemSendsGeometryChanges)
|
|
||||||
# 设置接收悬停事件
|
|
||||||
self.setAcceptHoverEvents(True)
|
|
||||||
self.setBrush(QColor(247, 160, 57)) # 设置背景颜色
|
|
||||||
|
|
||||||
# 是否在调整大小的状态
|
|
||||||
self.isResizing = False
|
|
||||||
self.mousePressPos = None
|
|
||||||
self.mousePressRect = None
|
|
||||||
|
|
||||||
def paint(self, painter, option, widget):
|
|
||||||
super(MoveableItem, self).paint(painter, option, widget)
|
|
||||||
# 当鼠标选中后在边缘绘制边框
|
|
||||||
if option.state & QStyle.State_Selected:
|
|
||||||
rect = self.boundingRect()
|
|
||||||
painter.setRenderHint(QPainter.Antialiasing, True) # 抗锯齿
|
|
||||||
x, y, w, h = rect.x(), rect.y(), rect.width(), rect.height()
|
|
||||||
if option.state & QStyle.State_HasFocus: # 有焦点
|
|
||||||
painter.setPen(QPen(Qt.red, 3)) # 设置红色画笔
|
|
||||||
# 在左上、左下、右上、右下、以及四条边上画小线段
|
|
||||||
painter.drawLines(
|
|
||||||
QLineF(x, y, x + 10, y), # 左上顶点向右
|
|
||||||
QLineF(x, y, x, y + 10), # 左上顶点向下
|
|
||||||
|
|
||||||
QLineF(x, y + h, x + 10, y + h), # 左下顶点向右
|
|
||||||
QLineF(x, y + h, x, y + h - 10), # 左下顶点向上
|
|
||||||
|
|
||||||
QLineF(x + w, y, x + w - 10, y), # 右上顶点向左
|
|
||||||
QLineF(x + w, y, x + w, y + 10), # 右上顶点向下
|
|
||||||
|
|
||||||
QLineF(x + w, y + h, x + w - 10, y + h), # 右下顶点向左
|
|
||||||
QLineF(x + w, y + h, x + w, y + h - 10) # 右下顶点向上
|
|
||||||
)
|
|
||||||
|
|
||||||
def hoverMoveEvent(self, event):
|
|
||||||
super(MoveableItem, self).hoverMoveEvent(event)
|
|
||||||
# 鼠标悬停事件,用于检测鼠标位置并改变鼠标形态
|
|
||||||
cursor = self.isInResizeArea(event.pos())
|
|
||||||
if self.isResizing or (cursor and self.isSelected()):
|
|
||||||
# 正在调整中或者鼠标在可调整区域范围内并且是选中
|
|
||||||
self.setCursor(cursor)
|
|
||||||
else:
|
|
||||||
self.setCursor(Qt.ArrowCursor)
|
|
||||||
|
|
||||||
def hoverLeaveEvent(self, event):
|
|
||||||
"""鼠标悬停离开事件恢复鼠标样式"""
|
|
||||||
super(MoveableItem, self).hoverLeaveEvent(event)
|
|
||||||
self.setCursor(Qt.ArrowCursor)
|
|
||||||
|
|
||||||
def mousePressEvent(self, event):
|
|
||||||
# 鼠标按下
|
|
||||||
super(MoveableItem, self).mousePressEvent(event)
|
|
||||||
if event.button() == Qt.LeftButton and self.isInResizeArea(event.pos()):
|
|
||||||
self.isResizing = True
|
|
||||||
self.mousePressPos = event.pos()
|
|
||||||
self.mousePressRect = self.boundingRect()
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event):
|
|
||||||
# 鼠标释放开
|
|
||||||
super(MoveableItem, self).mouseReleaseEvent(event)
|
|
||||||
if event.button() == Qt.LeftButton and self.isResizing:
|
|
||||||
self.isResizing = False
|
|
||||||
self.mousePressPos = None
|
|
||||||
self.mousePressRect = None
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def mouseMoveEvent(self, event):
|
|
||||||
# 鼠标移动
|
|
||||||
if self.isResizing and self.mousePressPos:
|
|
||||||
rect = self.boundingRect()
|
|
||||||
pos = event.pos() - self.mousePressPos
|
|
||||||
w = pos.x()
|
|
||||||
h = pos.y()
|
|
||||||
x = -4 if w > 0 else 4
|
|
||||||
y = -4 if h > 0 else 4
|
|
||||||
print(x, y, -x, -y, pos)
|
|
||||||
self.setRect(rect.adjusted(x, y, -x, -y))
|
|
||||||
self.prepareGeometryChange()
|
|
||||||
else:
|
|
||||||
super(MoveableItem, self).mouseMoveEvent(event)
|
|
||||||
|
|
||||||
def isInResizeArea(self, pos):
|
|
||||||
# 检测判断鼠标所在位置是否为四个顶点的范围内
|
|
||||||
rect = self.boundingRect()
|
|
||||||
x, y, w, h = rect.x(), rect.y(), rect.width(), rect.height()
|
|
||||||
|
|
||||||
lx = pos.x() < x + 10
|
|
||||||
rx = pos.x() > x + w - 10
|
|
||||||
ty = pos.y() < y + 10
|
|
||||||
by = pos.y() > y + h - 10
|
|
||||||
# 左上角和右下角
|
|
||||||
if (lx and ty) or (rx and by):
|
|
||||||
return Qt.SizeFDiagCursor
|
|
||||||
# 右上角和左下角
|
|
||||||
if (rx and ty) or (lx and by):
|
|
||||||
return Qt.SizeBDiagCursor
|
|
||||||
# 上、下
|
|
||||||
if ty or by:
|
|
||||||
return Qt.SizeVerCursor
|
|
||||||
if lx or rx:
|
|
||||||
return Qt.SizeHorCursor
|
|
||||||
# 左、右
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
class ImageWidget(QGraphicsView):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(ImageWidget, self).__init__(*args, **kwargs)
|
|
||||||
self.resize(800, 600)
|
|
||||||
# 设置背景颜色
|
|
||||||
self.setBackgroundBrush(QColor(31, 31, 47))
|
|
||||||
# 去掉滚动条
|
|
||||||
# self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
||||||
# self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
||||||
# 设置变换中心为鼠标所在位置
|
|
||||||
self.setTransformationAnchor(self.AnchorUnderMouse)
|
|
||||||
# 不保证painter的状态
|
|
||||||
self.setOptimizationFlags(self.DontSavePainterState)
|
|
||||||
self.setViewportUpdateMode(self.SmartViewportUpdate)
|
|
||||||
self.setRenderHints(QPainter.Antialiasing |
|
|
||||||
QPainter.SmoothPixmapTransform)
|
|
||||||
|
|
||||||
# 场景
|
|
||||||
self._scene = QGraphicsScene(0, 0, self.width(), self.height())
|
|
||||||
self.setScene(self._scene)
|
|
||||||
|
|
||||||
self._scene.addItem(MoveableItem(100, 100, 200, 200))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
import cgitb
|
|
||||||
sys.excepthook = cgitb.Hook(1, None, 5, sys.stderr, 'text')
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
w = ImageWidget()
|
|
||||||
w.show()
|
|
||||||
sys.exit(app.exec_())
|
|
|
@ -1,63 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
Created on 2018年7月26日
|
|
||||||
@author: Irony
|
|
||||||
@site: https://pyqt5.com, https://github.com/892768447
|
|
||||||
@email: 892768447@qq.com
|
|
||||||
@file: QGraphicsView练习.QGraphicsItem.Item移动
|
|
||||||
@description:
|
|
||||||
"""
|
|
||||||
from PyQt5.QtGui import QPainter, QColor
|
|
||||||
from PyQt5.QtWidgets import QGraphicsRectItem, QGraphicsView, QGraphicsScene
|
|
||||||
|
|
||||||
|
|
||||||
__Author__ = """By: Irony
|
|
||||||
QQ: 892768447
|
|
||||||
Email: 892768447@qq.com"""
|
|
||||||
__Copyright__ = "Copyright (c) 2018 Irony"
|
|
||||||
__Version__ = "Version 1.0"
|
|
||||||
|
|
||||||
|
|
||||||
class MoveableItem(QGraphicsRectItem):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(MoveableItem, self).__init__(*args, **kwargs)
|
|
||||||
self.setFlag(self.ItemIsMovable) # 设置为可以动
|
|
||||||
self.setBrush(QColor(247, 160, 57)) # 设置背景颜色
|
|
||||||
|
|
||||||
|
|
||||||
class ImageWidget(QGraphicsView):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(ImageWidget, self).__init__(*args, **kwargs)
|
|
||||||
self.resize(800, 600)
|
|
||||||
# 设置背景颜色
|
|
||||||
self.setBackgroundBrush(QColor(31, 31, 47))
|
|
||||||
# 去掉滚动条
|
|
||||||
# self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
||||||
# self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
||||||
# 设置变换中心为鼠标所在位置
|
|
||||||
self.setTransformationAnchor(self.AnchorUnderMouse)
|
|
||||||
# 不保证painter的状态
|
|
||||||
self.setOptimizationFlags(self.DontSavePainterState)
|
|
||||||
self.setViewportUpdateMode(self.SmartViewportUpdate)
|
|
||||||
self.setRenderHints(QPainter.Antialiasing |
|
|
||||||
QPainter.SmoothPixmapTransform)
|
|
||||||
|
|
||||||
# 场景
|
|
||||||
self._scene = QGraphicsScene()
|
|
||||||
self.setScene(self._scene)
|
|
||||||
self.setSceneRect(0, 0, self.width(), self.height())
|
|
||||||
|
|
||||||
self._scene.addItem(MoveableItem(100, 100, 200, 200))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
w = ImageWidget()
|
|
||||||
w.show()
|
|
||||||
sys.exit(app.exec_())
|
|
294
图形视图/test/调整.py
|
@ -1,294 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Created on 2018年7月26日
|
|
||||||
# author: Irony
|
|
||||||
# site: https://pyqt5.com, https://github.com/892768447
|
|
||||||
# email: 892768447@qq.com
|
|
||||||
# file: QGraphicsView练习.QGraphicsItem.ttt
|
|
||||||
# description:
|
|
||||||
|
|
||||||
__Author__ = """By: Irony
|
|
||||||
QQ: 892768447
|
|
||||||
Email: 892768447@qq.com"""
|
|
||||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
|
||||||
__Version__ = 1.0
|
|
||||||
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt, QRectF, QPointF
|
|
||||||
from PyQt5.QtGui import QBrush, QPainterPath, QPainter, QColor, QPen, QPixmap
|
|
||||||
from PyQt5.QtWidgets import QGraphicsRectItem, QApplication, QGraphicsView, QGraphicsScene, QGraphicsItem
|
|
||||||
|
|
||||||
|
|
||||||
class GraphicsRectItem(QGraphicsRectItem):
|
|
||||||
|
|
||||||
handleTopLeft = 1
|
|
||||||
handleTopMiddle = 2
|
|
||||||
handleTopRight = 3
|
|
||||||
handleMiddleLeft = 4
|
|
||||||
handleMiddleRight = 5
|
|
||||||
handleBottomLeft = 6
|
|
||||||
handleBottomMiddle = 7
|
|
||||||
handleBottomRight = 8
|
|
||||||
|
|
||||||
handleSize = +8.0
|
|
||||||
handleSpace = -4.0
|
|
||||||
|
|
||||||
handleCursors = {
|
|
||||||
handleTopLeft: Qt.SizeFDiagCursor,
|
|
||||||
handleTopMiddle: Qt.SizeVerCursor,
|
|
||||||
handleTopRight: Qt.SizeBDiagCursor,
|
|
||||||
handleMiddleLeft: Qt.SizeHorCursor,
|
|
||||||
handleMiddleRight: Qt.SizeHorCursor,
|
|
||||||
handleBottomLeft: Qt.SizeBDiagCursor,
|
|
||||||
handleBottomMiddle: Qt.SizeVerCursor,
|
|
||||||
handleBottomRight: Qt.SizeFDiagCursor,
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""
|
|
||||||
Initialize the shape.
|
|
||||||
"""
|
|
||||||
super().__init__(*args)
|
|
||||||
self.handles = {}
|
|
||||||
self.handleSelected = None
|
|
||||||
self.mousePressPos = None
|
|
||||||
self.mousePressRect = None
|
|
||||||
self.setAcceptHoverEvents(True)
|
|
||||||
self.setFlag(QGraphicsItem.ItemIsMovable, True)
|
|
||||||
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
|
|
||||||
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
|
|
||||||
self.setFlag(QGraphicsItem.ItemIsFocusable, True)
|
|
||||||
self.updateHandlesPos()
|
|
||||||
|
|
||||||
def handleAt(self, point):
|
|
||||||
"""
|
|
||||||
Returns the resize handle below the given point.
|
|
||||||
"""
|
|
||||||
for k, v, in self.handles.items():
|
|
||||||
if v.contains(point):
|
|
||||||
return k
|
|
||||||
return None
|
|
||||||
|
|
||||||
def hoverMoveEvent(self, moveEvent):
|
|
||||||
"""
|
|
||||||
Executed when the mouse moves over the shape (NOT PRESSED).
|
|
||||||
"""
|
|
||||||
if self.isSelected():
|
|
||||||
handle = self.handleAt(moveEvent.pos())
|
|
||||||
cursor = Qt.ArrowCursor if handle is None else self.handleCursors[handle]
|
|
||||||
self.setCursor(cursor)
|
|
||||||
super().hoverMoveEvent(moveEvent)
|
|
||||||
|
|
||||||
def hoverLeaveEvent(self, moveEvent):
|
|
||||||
"""
|
|
||||||
Executed when the mouse leaves the shape (NOT PRESSED).
|
|
||||||
"""
|
|
||||||
self.setCursor(Qt.ArrowCursor)
|
|
||||||
super().hoverLeaveEvent(moveEvent)
|
|
||||||
|
|
||||||
def mousePressEvent(self, mouseEvent):
|
|
||||||
"""
|
|
||||||
Executed when the mouse is pressed on the item.
|
|
||||||
"""
|
|
||||||
self.handleSelected = self.handleAt(mouseEvent.pos())
|
|
||||||
if self.handleSelected:
|
|
||||||
self.mousePressPos = mouseEvent.pos()
|
|
||||||
self.mousePressRect = self.boundingRect()
|
|
||||||
super().mousePressEvent(mouseEvent)
|
|
||||||
|
|
||||||
def mouseMoveEvent(self, mouseEvent):
|
|
||||||
"""
|
|
||||||
Executed when the mouse is being moved over the item while being pressed.
|
|
||||||
"""
|
|
||||||
if self.handleSelected is not None:
|
|
||||||
self.interactiveResize(mouseEvent.pos())
|
|
||||||
else:
|
|
||||||
super().mouseMoveEvent(mouseEvent)
|
|
||||||
|
|
||||||
def mouseReleaseEvent(self, mouseEvent):
|
|
||||||
"""
|
|
||||||
Executed when the mouse is released from the item.
|
|
||||||
"""
|
|
||||||
super().mouseReleaseEvent(mouseEvent)
|
|
||||||
self.handleSelected = None
|
|
||||||
self.mousePressPos = None
|
|
||||||
self.mousePressRect = None
|
|
||||||
self.update()
|
|
||||||
|
|
||||||
def boundingRect(self):
|
|
||||||
"""
|
|
||||||
Returns the bounding rect of the shape (including the resize handles).
|
|
||||||
"""
|
|
||||||
o = self.handleSize + self.handleSpace
|
|
||||||
return self.rect().adjusted(-o, -o, o, o)
|
|
||||||
|
|
||||||
def updateHandlesPos(self):
|
|
||||||
"""
|
|
||||||
Update current resize handles according to the shape size and position.
|
|
||||||
"""
|
|
||||||
s = self.handleSize
|
|
||||||
b = self.boundingRect()
|
|
||||||
self.handles[self.handleTopLeft] = QRectF(b.left(), b.top(), s, s)
|
|
||||||
self.handles[self.handleTopMiddle] = QRectF(b.center().x() - s / 2, b.top(), s, s)
|
|
||||||
self.handles[self.handleTopRight] = QRectF(b.right() - s, b.top(), s, s)
|
|
||||||
self.handles[self.handleMiddleLeft] = QRectF(b.left(), b.center().y() - s / 2, s, s)
|
|
||||||
self.handles[self.handleMiddleRight] = QRectF(b.right() - s, b.center().y() - s / 2, s, s)
|
|
||||||
self.handles[self.handleBottomLeft] = QRectF(b.left(), b.bottom() - s, s, s)
|
|
||||||
self.handles[self.handleBottomMiddle] = QRectF(b.center().x() - s / 2, b.bottom() - s, s, s)
|
|
||||||
self.handles[self.handleBottomRight] = QRectF(b.right() - s, b.bottom() - s, s, s)
|
|
||||||
|
|
||||||
def interactiveResize(self, mousePos):
|
|
||||||
"""
|
|
||||||
Perform shape interactive resize.
|
|
||||||
"""
|
|
||||||
offset = self.handleSize + self.handleSpace
|
|
||||||
boundingRect = self.boundingRect()
|
|
||||||
rect = self.rect()
|
|
||||||
diff = QPointF(0, 0)
|
|
||||||
|
|
||||||
self.prepareGeometryChange()
|
|
||||||
|
|
||||||
if self.handleSelected == self.handleTopLeft:
|
|
||||||
|
|
||||||
fromX = self.mousePressRect.left()
|
|
||||||
fromY = self.mousePressRect.top()
|
|
||||||
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
|
||||||
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
|
||||||
diff.setX(toX - fromX)
|
|
||||||
diff.setY(toY - fromY)
|
|
||||||
boundingRect.setLeft(toX)
|
|
||||||
boundingRect.setTop(toY)
|
|
||||||
rect.setLeft(boundingRect.left() + offset)
|
|
||||||
rect.setTop(boundingRect.top() + offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
elif self.handleSelected == self.handleTopMiddle:
|
|
||||||
|
|
||||||
fromY = self.mousePressRect.top()
|
|
||||||
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
|
||||||
diff.setY(toY - fromY)
|
|
||||||
boundingRect.setTop(toY)
|
|
||||||
rect.setTop(boundingRect.top() + offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
elif self.handleSelected == self.handleTopRight:
|
|
||||||
|
|
||||||
fromX = self.mousePressRect.right()
|
|
||||||
fromY = self.mousePressRect.top()
|
|
||||||
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
|
||||||
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
|
||||||
diff.setX(toX - fromX)
|
|
||||||
diff.setY(toY - fromY)
|
|
||||||
boundingRect.setRight(toX)
|
|
||||||
boundingRect.setTop(toY)
|
|
||||||
rect.setRight(boundingRect.right() - offset)
|
|
||||||
rect.setTop(boundingRect.top() + offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
elif self.handleSelected == self.handleMiddleLeft:
|
|
||||||
|
|
||||||
fromX = self.mousePressRect.left()
|
|
||||||
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
|
||||||
diff.setX(toX - fromX)
|
|
||||||
boundingRect.setLeft(toX)
|
|
||||||
rect.setLeft(boundingRect.left() + offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
elif self.handleSelected == self.handleMiddleRight:
|
|
||||||
print("MR")
|
|
||||||
fromX = self.mousePressRect.right()
|
|
||||||
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
|
||||||
diff.setX(toX - fromX)
|
|
||||||
boundingRect.setRight(toX)
|
|
||||||
rect.setRight(boundingRect.right() - offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
elif self.handleSelected == self.handleBottomLeft:
|
|
||||||
|
|
||||||
fromX = self.mousePressRect.left()
|
|
||||||
fromY = self.mousePressRect.bottom()
|
|
||||||
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
|
||||||
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
|
||||||
diff.setX(toX - fromX)
|
|
||||||
diff.setY(toY - fromY)
|
|
||||||
boundingRect.setLeft(toX)
|
|
||||||
boundingRect.setBottom(toY)
|
|
||||||
rect.setLeft(boundingRect.left() + offset)
|
|
||||||
rect.setBottom(boundingRect.bottom() - offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
elif self.handleSelected == self.handleBottomMiddle:
|
|
||||||
|
|
||||||
fromY = self.mousePressRect.bottom()
|
|
||||||
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
|
||||||
diff.setY(toY - fromY)
|
|
||||||
boundingRect.setBottom(toY)
|
|
||||||
rect.setBottom(boundingRect.bottom() - offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
elif self.handleSelected == self.handleBottomRight:
|
|
||||||
|
|
||||||
fromX = self.mousePressRect.right()
|
|
||||||
fromY = self.mousePressRect.bottom()
|
|
||||||
toX = fromX + mousePos.x() - self.mousePressPos.x()
|
|
||||||
toY = fromY + mousePos.y() - self.mousePressPos.y()
|
|
||||||
diff.setX(toX - fromX)
|
|
||||||
diff.setY(toY - fromY)
|
|
||||||
boundingRect.setRight(toX)
|
|
||||||
boundingRect.setBottom(toY)
|
|
||||||
rect.setRight(boundingRect.right() - offset)
|
|
||||||
rect.setBottom(boundingRect.bottom() - offset)
|
|
||||||
self.setRect(rect)
|
|
||||||
|
|
||||||
self.updateHandlesPos()
|
|
||||||
|
|
||||||
def shape(self):
|
|
||||||
"""
|
|
||||||
Returns the shape of this item as a QPainterPath in local coordinates.
|
|
||||||
"""
|
|
||||||
path = QPainterPath()
|
|
||||||
path.addRect(self.rect())
|
|
||||||
if self.isSelected():
|
|
||||||
for shape in self.handles.values():
|
|
||||||
path.addEllipse(shape)
|
|
||||||
return path
|
|
||||||
|
|
||||||
def paint(self, painter, option, widget=None):
|
|
||||||
"""
|
|
||||||
Paint the node in the graphic view.
|
|
||||||
"""
|
|
||||||
painter.setBrush(QBrush(QColor(255, 0, 0, 100)))
|
|
||||||
painter.setPen(QPen(QColor(0, 0, 0), 1.0, Qt.SolidLine))
|
|
||||||
painter.drawRect(self.rect())
|
|
||||||
|
|
||||||
painter.setRenderHint(QPainter.Antialiasing)
|
|
||||||
painter.setBrush(QBrush(QColor(255, 0, 0, 255)))
|
|
||||||
painter.setPen(QPen(QColor(0, 0, 0, 255), 1.0, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
|
|
||||||
for handle, rect in self.handles.items():
|
|
||||||
if self.handleSelected is None or handle == self.handleSelected:
|
|
||||||
painter.drawEllipse(rect)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
|
|
||||||
grview = QGraphicsView()
|
|
||||||
scene = QGraphicsScene()
|
|
||||||
scene.setSceneRect(0, 0, 680, 459)
|
|
||||||
|
|
||||||
scene.addPixmap(QPixmap('01.png'))
|
|
||||||
grview.setScene(scene)
|
|
||||||
|
|
||||||
item = GraphicsRectItem(0, 0, 300, 150)
|
|
||||||
scene.addItem(item)
|
|
||||||
|
|
||||||
grview.fitInView(scene.sceneRect(), Qt.KeepAspectRatio)
|
|
||||||
grview.show()
|
|
||||||
sys.exit(app.exec_())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
|
@ -1,6 +0,0 @@
|
||||||
# 描绘世界地图
|
|
||||||
|
|
||||||
世界地图-使用Ctrl+滑轮进行放大缩小
|
|
||||||
|
|
||||||
![ScreenShot1](ScreenShot/1.png)
|
|
||||||
![ScreenShot2](ScreenShot/1.png)
|
|
Before Width: | Height: | Size: 103 KiB |
Before Width: | Height: | Size: 141 KiB |
108
图形视图/显示图片及缩放.py
|
@ -1,108 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
Created on 2018年3月23日
|
|
||||||
@author: Irony
|
|
||||||
@site: https://pyqt5.com, https://github.com/892768447
|
|
||||||
@email: 892768447@qq.com
|
|
||||||
@file: ImageView
|
|
||||||
@description: 图片查看
|
|
||||||
"""
|
|
||||||
from PyQt5.QtCore import QStandardPaths, Qt
|
|
||||||
from PyQt5.QtGui import QColor, QPainter, QPixmap
|
|
||||||
from PyQt5.QtOpenGL import QGLFormat
|
|
||||||
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, \
|
|
||||||
QGraphicsItem
|
|
||||||
|
|
||||||
|
|
||||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
|
||||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
|
||||||
__Version__ = 1.0
|
|
||||||
|
|
||||||
|
|
||||||
class GraphicsView(QGraphicsView):
|
|
||||||
|
|
||||||
# 背景区域颜色
|
|
||||||
backgroundColor = QColor(28, 31, 34)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(GraphicsView, self).__init__(*args, **kwargs)
|
|
||||||
self.resize(800, 600)
|
|
||||||
# 设置背景颜色
|
|
||||||
self.setBackgroundBrush(self.backgroundColor)
|
|
||||||
# 缓存背景
|
|
||||||
self.setCacheMode(self.CacheBackground)
|
|
||||||
# 设置拖拽样式
|
|
||||||
# self.setDragMode(self.ScrollHandDrag)
|
|
||||||
self.setRenderHints(
|
|
||||||
QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform)
|
|
||||||
# opengl
|
|
||||||
if QGLFormat.hasOpenGL():
|
|
||||||
self.setRenderHint(QPainter.HighQualityAntialiasing)
|
|
||||||
# 尝试通过分析需要重绘的区域来找到最佳的更新模式
|
|
||||||
self.setViewportUpdateMode(self.SmartViewportUpdate)
|
|
||||||
self._scene = QGraphicsScene(-400, -300, 800, 600, self)
|
|
||||||
self.setScene(self._scene)
|
|
||||||
|
|
||||||
# 图片item
|
|
||||||
self._itemImage = None
|
|
||||||
|
|
||||||
def keyReleaseEvent(self, event):
|
|
||||||
"""按键处理事件"""
|
|
||||||
self._scaleImage(event)
|
|
||||||
super(GraphicsView, self).keyReleaseEvent(event)
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
"""窗口关闭时清空场景中的所有item"""
|
|
||||||
self._scene.clear()
|
|
||||||
self._itemImage = None
|
|
||||||
super(GraphicsView, self).closeEvent(event)
|
|
||||||
|
|
||||||
def _scaleImage(self, event):
|
|
||||||
"""缩放图片操作"""
|
|
||||||
if not self._itemImage:
|
|
||||||
return
|
|
||||||
scale = self._itemImage.scale()
|
|
||||||
if event.key() == Qt.Key_Plus:
|
|
||||||
# 放大
|
|
||||||
if scale >= 0.91:
|
|
||||||
return
|
|
||||||
self._itemImage.setScale(scale + 0.1)
|
|
||||||
elif event.key() == Qt.Key_Minus:
|
|
||||||
# 缩小
|
|
||||||
if scale <= 0.11:
|
|
||||||
return
|
|
||||||
self._itemImage.setScale(scale - 0.1)
|
|
||||||
|
|
||||||
def loadImage(self):
|
|
||||||
path, _ = QFileDialog.getOpenFileName(
|
|
||||||
self, '请选择图片', QStandardPaths.writableLocation(QStandardPaths.DesktopLocation), '图片文件(*.jpg *.png)')
|
|
||||||
if not path:
|
|
||||||
return
|
|
||||||
if self._itemImage:
|
|
||||||
# 删除以前的item
|
|
||||||
self._scene.removeItem(self._itemImage)
|
|
||||||
del self._itemImage
|
|
||||||
self._itemImage = self._scene.addPixmap(QPixmap(path))
|
|
||||||
self._itemImage.setFlag(QGraphicsItem.ItemIsMovable)
|
|
||||||
self._itemImage.setScale(0.1) # 默认加载比例
|
|
||||||
|
|
||||||
size = self._itemImage.pixmap().size()
|
|
||||||
# 调整图片在中间
|
|
||||||
self._itemImage.setPos(
|
|
||||||
-size.width() * self._itemImage.scale() / 2,
|
|
||||||
-size.height() * self._itemImage.scale() / 2
|
|
||||||
)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
print(os.getpid())
|
|
||||||
from PyQt5.QtWidgets import QApplication, QPushButton
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
w = GraphicsView()
|
|
||||||
w.show()
|
|
||||||
ww = QPushButton('选择文件', clicked=w.loadImage)
|
|
||||||
ww.show()
|
|
||||||
sys.exit(app.exec_())
|
|
|
@ -1,78 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
Created on 2018年3月24日
|
|
||||||
@author: Irony
|
|
||||||
@site: https://pyqt5.com, https://github.com/892768447
|
|
||||||
@email: 892768447@qq.com
|
|
||||||
@file: SimpleImagePs
|
|
||||||
@description: 图片查看
|
|
||||||
"""
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtGui import QCursor
|
|
||||||
from PyQt5.QtWidgets import QMainWindow, QToolBar
|
|
||||||
from SimpleImageView import SimpleImageView # @UnresolvedImport
|
|
||||||
|
|
||||||
|
|
||||||
__Author__ = """By: Irony
|
|
||||||
QQ: 892768447
|
|
||||||
Email: 892768447@qq.com"""
|
|
||||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
|
||||||
__Version__ = 1.0
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(MainWindow, self).__init__(*args, **kwargs)
|
|
||||||
# 获取可用主屏桌面大小
|
|
||||||
screenRect = QApplication.instance().desktop().availableGeometry()
|
|
||||||
# 设置为桌面的2/3大
|
|
||||||
self.resize(
|
|
||||||
int(screenRect.width() * 2 / 3), int(screenRect.height() * 2 / 3))
|
|
||||||
# 初始化中心控件
|
|
||||||
self._imageView = SimpleImageView(self)
|
|
||||||
self.setCentralWidget(self._imageView)
|
|
||||||
# 初始化菜单栏
|
|
||||||
self._initMenuBar()
|
|
||||||
# 初始化工具条
|
|
||||||
self._initToolBar()
|
|
||||||
|
|
||||||
def _initMenuBar(self):
|
|
||||||
"""菜单栏"""
|
|
||||||
menuBar = self.menuBar()
|
|
||||||
menu = menuBar.addMenu('文件')
|
|
||||||
menu.addAction('打开', self._imageView.loadImage)
|
|
||||||
menu.addAction('关闭')
|
|
||||||
menu.addAction('退出')
|
|
||||||
|
|
||||||
def _initToolBar(self):
|
|
||||||
"""工具条"""
|
|
||||||
toolBar = QToolBar('工具栏', self)
|
|
||||||
self.addToolBar(Qt.LeftToolBarArea, toolBar)
|
|
||||||
toolBar.addAction('灰度', self._imageView._greyScale)
|
|
||||||
toolBar.addAction('亮度')
|
|
||||||
toolBar.addAction('暖色调')
|
|
||||||
toolBar.addAction('冷色调')
|
|
||||||
toolBar.addAction('饱和度')
|
|
||||||
toolBar.addAction('模糊')
|
|
||||||
toolBar.addAction('锐化', self._ruihua)
|
|
||||||
|
|
||||||
def _ruihua(self):
|
|
||||||
# 得到按钮的大概位置
|
|
||||||
print(self.mapFromGlobal(QCursor.pos()))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
print('pid:', os.getpid())
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
app.setApplicationDisplayName('简单图片处理')
|
|
||||||
app.setApplicationName('简单图片处理')
|
|
||||||
app.setApplicationVersion('1.0')
|
|
||||||
w = MainWindow()
|
|
||||||
w.show()
|
|
||||||
sys.exit(app.exec_())
|
|
|
@ -1,19 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
from PyQt5.QtCore import QObject
|
|
||||||
|
|
||||||
# Created on 2018年3月26日
|
|
||||||
# author: Irony
|
|
||||||
# site: https://pyqt5.com, https://github.com/892768447
|
|
||||||
# email: 892768447@qq.com
|
|
||||||
# file: QGraphicsView练习.简单图像处理.SimpleImageThread
|
|
||||||
# description:
|
|
||||||
|
|
||||||
__Author__ = """By: Irony
|
|
||||||
QQ: 892768447
|
|
||||||
Email: 892768447@qq.com"""
|
|
||||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
|
||||||
__Version__ = 1.0
|
|
||||||
|
|
||||||
class ToGrey(QObject):
|
|
||||||
pass
|
|
|
@ -1,158 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
"""
|
|
||||||
Created on 2018年3月24日
|
|
||||||
@author: Irony
|
|
||||||
@site: https://pyqt5.com, https://github.com/892768447
|
|
||||||
@email: 892768447@qq.com
|
|
||||||
@file: SimpleImageView
|
|
||||||
@description: 图片视图
|
|
||||||
"""
|
|
||||||
import struct
|
|
||||||
from time import time
|
|
||||||
|
|
||||||
from PIL import Image
|
|
||||||
from PIL.Image import fromarray
|
|
||||||
from PIL.ImageQt import fromqpixmap
|
|
||||||
from PyQt5.QtCore import QStandardPaths, Qt
|
|
||||||
from PyQt5.QtGui import QColor, QPainter, QPixmap, QImage, qRgb, qRed, qGreen,\
|
|
||||||
qBlue, QCursor
|
|
||||||
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, \
|
|
||||||
QGraphicsItem
|
|
||||||
import numpy
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from PyQt5.QtOpenGL import QGLFormat # , QGL, QGLWidget
|
|
||||||
hasOpenGL = True
|
|
||||||
except Exception as e:
|
|
||||||
print(e)
|
|
||||||
hasOpenGL = False
|
|
||||||
|
|
||||||
__Author__ = """By: Irony
|
|
||||||
QQ: 892768447
|
|
||||||
Email: 892768447@qq.com"""
|
|
||||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
|
||||||
__Version__ = 1.0
|
|
||||||
|
|
||||||
|
|
||||||
class SimpleImageView(QGraphicsView):
|
|
||||||
|
|
||||||
# 背景区域颜色
|
|
||||||
backgroundColor = QColor(28, 31, 34)
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(SimpleImageView, self).__init__(*args, **kwargs)
|
|
||||||
# 设置背景颜色
|
|
||||||
self.setBackgroundBrush(self.backgroundColor)
|
|
||||||
# 缓存背景
|
|
||||||
self.setCacheMode(self.CacheBackground)
|
|
||||||
# 设置拖拽样式
|
|
||||||
# self.setDragMode(self.ScrollHandDrag)
|
|
||||||
self.setRenderHints(
|
|
||||||
QPainter.Antialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform)
|
|
||||||
# opengl
|
|
||||||
if hasOpenGL and QGLFormat.hasOpenGL():
|
|
||||||
# self.setViewport(QGLWidget(QGLFormat(QGL.SampleBuffers), self))
|
|
||||||
self.setRenderHint(QPainter.HighQualityAntialiasing)
|
|
||||||
self.setViewportUpdateMode(self.FullViewportUpdate)
|
|
||||||
else:
|
|
||||||
# 尝试通过分析需要重绘的区域来找到最佳的更新模式
|
|
||||||
self.setViewportUpdateMode(self.SmartViewportUpdate)
|
|
||||||
self._scene = QGraphicsScene(self)
|
|
||||||
self.setScene(self._scene)
|
|
||||||
|
|
||||||
# 图片item
|
|
||||||
self._itemImage = None
|
|
||||||
self._itemImageNew = None
|
|
||||||
|
|
||||||
def keyReleaseEvent(self, event):
|
|
||||||
"""按键处理事件"""
|
|
||||||
self._scaleImage(event)
|
|
||||||
super(SimpleImageView, self).keyReleaseEvent(event)
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
|
||||||
"""窗口关闭时清空场景中的所有item"""
|
|
||||||
self._scene.clear()
|
|
||||||
self._itemImage = None
|
|
||||||
self._itemImageNew = None
|
|
||||||
super(SimpleImageView, self).closeEvent(event)
|
|
||||||
|
|
||||||
def _scaleImage(self, event):
|
|
||||||
"""缩放图片操作"""
|
|
||||||
item = self._scene.focusItem()
|
|
||||||
if not item:
|
|
||||||
item = self._scene.items()
|
|
||||||
if not item:
|
|
||||||
return
|
|
||||||
item = item[0]
|
|
||||||
# 获取item的缩放度
|
|
||||||
scale = item.scale()
|
|
||||||
if event.key() == Qt.Key_Plus:
|
|
||||||
# 放大
|
|
||||||
if scale >= 0.91:
|
|
||||||
return
|
|
||||||
item.setScale(scale + 0.1)
|
|
||||||
elif event.key() == Qt.Key_Minus:
|
|
||||||
# 缩小
|
|
||||||
if scale <= 0.11:
|
|
||||||
return
|
|
||||||
item.setScale(scale - 0.1)
|
|
||||||
|
|
||||||
def loadImage(self):
|
|
||||||
path, _ = QFileDialog.getOpenFileName(
|
|
||||||
self, '请选择图片', QStandardPaths.writableLocation(QStandardPaths.DesktopLocation), '图片文件(*.jpg *.png)')
|
|
||||||
if not path:
|
|
||||||
return
|
|
||||||
if self._itemImageNew:
|
|
||||||
self._scene.removeItem(self._itemImageNew)
|
|
||||||
del self._itemImageNew
|
|
||||||
self._itemImageNew = None
|
|
||||||
if self._itemImage:
|
|
||||||
# 删除以前的item
|
|
||||||
self._scene.removeItem(self._itemImage)
|
|
||||||
del self._itemImage
|
|
||||||
self._itemImage = None
|
|
||||||
self._itemImage = self._scene.addPixmap(QPixmap(path))
|
|
||||||
self._itemImage.setFlag(QGraphicsItem.ItemIsMovable)
|
|
||||||
self._itemImage.setFlag(QGraphicsItem.ItemIsFocusable)
|
|
||||||
self._itemImage.setScale(0.1) # 默认加载比例
|
|
||||||
self._scene.setFocusItem(self._itemImage)
|
|
||||||
print(self._itemImage.zValue())
|
|
||||||
|
|
||||||
size = self._itemImage.pixmap().size()
|
|
||||||
# 调整图片在中间
|
|
||||||
self._itemImage.setPos(
|
|
||||||
-size.width() * self._itemImage.scale() / 2,
|
|
||||||
-size.height() * self._itemImage.scale() / 2
|
|
||||||
)
|
|
||||||
|
|
||||||
def _greyScale(self):
|
|
||||||
if not self._itemImage:
|
|
||||||
return
|
|
||||||
if self._itemImageNew:
|
|
||||||
self._scene.removeItem(self._itemImageNew)
|
|
||||||
del self._itemImageNew
|
|
||||||
self._itemImageNew = None
|
|
||||||
t = time()
|
|
||||||
# QPixmap 转 PIL Image 转 numpy array
|
|
||||||
image = numpy.array(fromqpixmap(self._itemImage.pixmap()).convert('L'))
|
|
||||||
image = fromarray(image).toqpixmap()
|
|
||||||
self._itemImageNew = self._scene.addPixmap(image)
|
|
||||||
self._itemImageNew.setFlag(QGraphicsItem.ItemIsFocusable)
|
|
||||||
self._itemImageNew.setFlag(QGraphicsItem.ItemIsMovable)
|
|
||||||
self._itemImageNew.setScale(self._itemImage.scale()) # 默认加载比例
|
|
||||||
self._scene.setFocusItem(self._itemImageNew)
|
|
||||||
print(self._itemImageNew.zValue())
|
|
||||||
print(time() - t)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
from PyQt5.QtWidgets import QApplication
|
|
||||||
app = QApplication(sys.argv)
|
|
||||||
w = SimpleImageView()
|
|
||||||
w.resize(800, 600)
|
|
||||||
w.show()
|
|
||||||
sys.exit(app.exec_())
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: RestartMainWindow
|
@file: RestartMainWindow
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月30日
|
Created on 2018年1月30日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: CalendarWidget
|
@file: CalendarWidget
|
||||||
@description: 日历
|
@description: 日历
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月26日
|
Created on 2018年1月26日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: FileSystemModel
|
@file: FileSystemModel
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月20日
|
Created on 2018年1月20日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: CircleLabel
|
@file: CircleLabel
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: critical
|
@file: critical
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: information
|
@file: information
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: question
|
@file: question
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: warning
|
@file: warning
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: critical
|
@file: critical
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: information
|
@file: information
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: question
|
@file: question
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月17日
|
Created on 2018年1月17日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: warning
|
@file: warning
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月30日
|
Created on 2018年1月30日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: ProgressBar
|
@file: ProgressBar
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月29日
|
Created on 2018年1月29日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: ButtonHover
|
@file: ButtonHover
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年2月1日
|
Created on 2018年2月1日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: PushButtonFont
|
@file: PushButtonFont
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年2月1日
|
Created on 2018年2月1日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: PushButtonLine
|
@file: PushButtonLine
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2018年1月20日
|
Created on 2018年1月20日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: ScrollBar
|
@file: ScrollBar
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月10日
|
Created on 2017年12月10日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: CustomPaintWidget
|
@file: CustomPaintWidget
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月10日
|
Created on 2017年12月10日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: CustomWidget
|
@file: CustomWidget
|
||||||
@description:
|
@description:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
'''
|
'''
|
||||||
Created on 2017年12月10日
|
Created on 2017年12月10日
|
||||||
@author: Irony."[讽刺]
|
@author: Irony."[讽刺]
|
||||||
@site: http://alyl.vip, http://orzorz.vip, https://coding.net/u/892768447, https://github.com/892768447
|
@site: https://pyqt5.com https://github.com/892768447
|
||||||
@email: 892768447@qq.com
|
@email: 892768447@qq.com
|
||||||
@file: test
|
@file: test
|
||||||
@description:
|
@description:
|
||||||
|
|