update site
This commit is contained in:
parent
7d0a51c98d
commit
c2e0d0c7a5
57 changed files with 2565 additions and 2545 deletions
|
@ -96,6 +96,7 @@ encoding//\u754C\u9762\u7F8E\u5316/\u5404\u7C7B\u8FDB\u5EA6\u6761/MetroLineProgr
|
|||
encoding//\u754C\u9762\u7F8E\u5316/\u5404\u7C7B\u8FDB\u5EA6\u6761/PercentProgressBar.py=utf-8
|
||||
encoding//\u754C\u9762\u7F8E\u5316/\u6C34\u6CE2\u7EB9\u8FDB\u5EA6\u6761/ProgressBar.py=utf-8
|
||||
encoding//\u754C\u9762\u7F8E\u5316/\u6C34\u6CE2\u7EB9\u8FDB\u5EA6\u6761/TestWidget.py=utf-8
|
||||
encoding//\u754C\u9762\u7F8E\u5316/\u8FB9\u6846\u52A8\u753B\u9634\u5F71/AnimationShadowEffect.py=utf-8
|
||||
encoding//\u7A0B\u5E8F\u91CD\u542F/AutoRestart.py=utf-8
|
||||
encoding//\u7A97\u53E3\u91CD\u542F/RestartMainWindow.py=utf-8
|
||||
encoding//\u7B80\u5355\u7684\u7A97\u53E3\u8D34\u8FB9\u9690\u85CF/WeltHideWindow.py=utf-8
|
||||
|
|
|
@ -1,74 +1,74 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月6日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@email: 892768447@qq.com
|
||||
@file: TableView
|
||||
@description:
|
||||
'''
|
||||
from PyQt5.QAxContainer import QAxWidget
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QFileDialog,\
|
||||
QMessageBox
|
||||
|
||||
|
||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
||||
__Version__ = "Version 1.0"
|
||||
|
||||
|
||||
class AxWidget(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AxWidget, self).__init__(*args, **kwargs)
|
||||
self.resize(800, 600)
|
||||
layout = QVBoxLayout(self)
|
||||
self.axWidget = QAxWidget(self)
|
||||
layout.addWidget(self.axWidget)
|
||||
layout.addWidget(QPushButton('选择excel,word,pdf文件',
|
||||
self, clicked=self.onOpenFile))
|
||||
|
||||
def onOpenFile(self):
|
||||
path, _ = QFileDialog.getOpenFileName(
|
||||
self, '请选择文件', '', 'excel(*.xlsx *.xls);;word(*.docx *.doc);;pdf(*.pdf)')
|
||||
if not path:
|
||||
return
|
||||
if _.find('*.doc'):
|
||||
return self.openOffice(path, 'Word.Application')
|
||||
if _.find('*.xls'):
|
||||
return self.openOffice(path, 'Excel.Application')
|
||||
if _.find('*.pdf'):
|
||||
return self.openPdf(path)
|
||||
|
||||
def openOffice(self, path, app):
|
||||
self.axWidget.clear()
|
||||
if not self.axWidget.setControl(app):
|
||||
return QMessageBox.critical(self, '错误', '没有安装 %s' % app)
|
||||
self.axWidget.dynamicCall(
|
||||
'SetVisible (bool Visible)', 'false') # 不显示窗体
|
||||
self.axWidget.setProperty('DisplayAlerts', False)
|
||||
self.axWidget.setControl(path)
|
||||
|
||||
def openPdf(self, path):
|
||||
self.axWidget.clear()
|
||||
if not self.axWidget.setControl('Adobe PDF Reader'):
|
||||
return QMessageBox.critical(self, '错误', '没有安装 Adobe PDF Reader')
|
||||
self.axWidget.dynamicCall('LoadFile(const QString&)', path)
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.axWidget.close()
|
||||
self.axWidget.clear()
|
||||
self.layout().removeWidget(self.axWidget)
|
||||
del self.axWidget
|
||||
super(AxWidget, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = AxWidget()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月6日
|
||||
@author: Irony."[讽刺]
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: TableView
|
||||
@description:
|
||||
'''
|
||||
from PyQt5.QAxContainer import QAxWidget
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QFileDialog,\
|
||||
QMessageBox
|
||||
|
||||
|
||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
||||
__Version__ = "Version 1.0"
|
||||
|
||||
|
||||
class AxWidget(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AxWidget, self).__init__(*args, **kwargs)
|
||||
self.resize(800, 600)
|
||||
layout = QVBoxLayout(self)
|
||||
self.axWidget = QAxWidget(self)
|
||||
layout.addWidget(self.axWidget)
|
||||
layout.addWidget(QPushButton('选择excel,word,pdf文件',
|
||||
self, clicked=self.onOpenFile))
|
||||
|
||||
def onOpenFile(self):
|
||||
path, _ = QFileDialog.getOpenFileName(
|
||||
self, '请选择文件', '', 'excel(*.xlsx *.xls);;word(*.docx *.doc);;pdf(*.pdf)')
|
||||
if not path:
|
||||
return
|
||||
if _.find('*.doc'):
|
||||
return self.openOffice(path, 'Word.Application')
|
||||
if _.find('*.xls'):
|
||||
return self.openOffice(path, 'Excel.Application')
|
||||
if _.find('*.pdf'):
|
||||
return self.openPdf(path)
|
||||
|
||||
def openOffice(self, path, app):
|
||||
self.axWidget.clear()
|
||||
if not self.axWidget.setControl(app):
|
||||
return QMessageBox.critical(self, '错误', '没有安装 %s' % app)
|
||||
self.axWidget.dynamicCall(
|
||||
'SetVisible (bool Visible)', 'false') # 不显示窗体
|
||||
self.axWidget.setProperty('DisplayAlerts', False)
|
||||
self.axWidget.setControl(path)
|
||||
|
||||
def openPdf(self, path):
|
||||
self.axWidget.clear()
|
||||
if not self.axWidget.setControl('Adobe PDF Reader'):
|
||||
return QMessageBox.critical(self, '错误', '没有安装 Adobe PDF Reader')
|
||||
self.axWidget.dynamicCall('LoadFile(const QString&)', path)
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.axWidget.close()
|
||||
self.axWidget.clear()
|
||||
self.layout().removeWidget(self.axWidget)
|
||||
del self.axWidget
|
||||
super(AxWidget, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = AxWidget()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created on 2018年5月6日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file:
|
||||
# description:
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
def sum(x, y):
|
||||
return x + y
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created on 2018年5月6日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file:
|
||||
# description:
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
def sum(x, y):
|
||||
return x + y
|
||||
|
|
|
@ -1,152 +1,152 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年4月8日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file:
|
||||
@description:
|
||||
"""
|
||||
import json
|
||||
import webbrowser
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QWidget,\
|
||||
QLabel, QSpacerItem, QSizePolicy, QHBoxLayout
|
||||
import chardet
|
||||
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = "Copyright (c) 2018 Irony"
|
||||
__Version__ = "Version 1.0"
|
||||
|
||||
|
||||
class ItemWidget(QWidget):
|
||||
"""自定义的item"""
|
||||
|
||||
def __init__(self, text, badge, *args, **kwargs):
|
||||
super(ItemWidget, self).__init__(*args, **kwargs)
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(QLabel(text, self, styleSheet='color: white;'))
|
||||
layout.addSpacerItem(QSpacerItem(
|
||||
60, 1, QSizePolicy.Maximum, QSizePolicy.Minimum))
|
||||
if badge and len(badge) == 2: # 后面带颜色的标签
|
||||
layout.addWidget(QLabel(
|
||||
badge[0], self, alignment=Qt.AlignCenter,
|
||||
styleSheet="""min-width: 80px;
|
||||
max-width: 80px;
|
||||
min-height: 38px;
|
||||
max-height: 38px;
|
||||
color: white;
|
||||
border:none;
|
||||
border-radius: 4px;
|
||||
background: %s""" % badge[1]
|
||||
))
|
||||
|
||||
|
||||
class JsonTreeWidget(QTreeWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(JsonTreeWidget, self).__init__(*args, **kwargs)
|
||||
self.setEditTriggers(self.NoEditTriggers)
|
||||
self.header().setVisible(False)
|
||||
# 帮点单击事件
|
||||
self.itemClicked.connect(self.onItemClicked)
|
||||
|
||||
def onItemClicked(self, item):
|
||||
"""item单击事件"""
|
||||
if item.url: # 调用浏览器打开网址
|
||||
webbrowser.open_new_tab(item.url)
|
||||
|
||||
def parseData(self, datas, parent=None):
|
||||
"""解析json数据"""
|
||||
for data in datas:
|
||||
url = data.get('url', '')
|
||||
items = data.get('items', [])
|
||||
# 生成item
|
||||
_item = QTreeWidgetItem(parent)
|
||||
_item.setIcon(0, QIcon(data.get('icon', '')))
|
||||
_widget = ItemWidget(
|
||||
data.get('name', ''),
|
||||
data.get('badge', []),
|
||||
self
|
||||
)
|
||||
_item.url = url # 可以直接设置变量值
|
||||
self.setItemWidget(_item, 0, _widget)
|
||||
if url:
|
||||
continue # 跳过
|
||||
# 解析儿子
|
||||
if items:
|
||||
self.parseData(items, _item)
|
||||
|
||||
def loadData(self, path):
|
||||
"""加载json数据"""
|
||||
datas = open(path, 'rb').read()
|
||||
datas = datas.decode(chardet.detect(datas).get('encoding', 'utf-8'))
|
||||
self.parseData(json.loads(datas), self)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet("""QTreeView {
|
||||
outline: 0px;
|
||||
background: rgb(47, 64, 78);
|
||||
}
|
||||
QTreeView::item {
|
||||
min-height: 92px;
|
||||
}
|
||||
QTreeView::item:hover {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView::item:selected {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::item:selected:active{
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView::item:selected:!active{
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::branch:has-siblings:!adjoins-item {
|
||||
background: green;
|
||||
}
|
||||
QTreeView::branch:closed:has-children:has-siblings {
|
||||
background: rgb(47, 64, 78);
|
||||
}
|
||||
|
||||
QTreeView::branch:has-children:!has-siblings:closed {
|
||||
background: rgb(47, 64, 78);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children:has-siblings {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children:!has-siblings {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView:branch:hover {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView:branch:selected {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
""")
|
||||
w = JsonTreeWidget()
|
||||
w.show()
|
||||
w.loadData('data.json')
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年4月8日
|
||||
@author: Irony
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file:
|
||||
@description:
|
||||
"""
|
||||
import json
|
||||
import webbrowser
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QWidget,\
|
||||
QLabel, QSpacerItem, QSizePolicy, QHBoxLayout
|
||||
import chardet
|
||||
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = "Copyright (c) 2018 Irony"
|
||||
__Version__ = "Version 1.0"
|
||||
|
||||
|
||||
class ItemWidget(QWidget):
|
||||
"""自定义的item"""
|
||||
|
||||
def __init__(self, text, badge, *args, **kwargs):
|
||||
super(ItemWidget, self).__init__(*args, **kwargs)
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(QLabel(text, self, styleSheet='color: white;'))
|
||||
layout.addSpacerItem(QSpacerItem(
|
||||
60, 1, QSizePolicy.Maximum, QSizePolicy.Minimum))
|
||||
if badge and len(badge) == 2: # 后面带颜色的标签
|
||||
layout.addWidget(QLabel(
|
||||
badge[0], self, alignment=Qt.AlignCenter,
|
||||
styleSheet="""min-width: 80px;
|
||||
max-width: 80px;
|
||||
min-height: 38px;
|
||||
max-height: 38px;
|
||||
color: white;
|
||||
border:none;
|
||||
border-radius: 4px;
|
||||
background: %s""" % badge[1]
|
||||
))
|
||||
|
||||
|
||||
class JsonTreeWidget(QTreeWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(JsonTreeWidget, self).__init__(*args, **kwargs)
|
||||
self.setEditTriggers(self.NoEditTriggers)
|
||||
self.header().setVisible(False)
|
||||
# 帮点单击事件
|
||||
self.itemClicked.connect(self.onItemClicked)
|
||||
|
||||
def onItemClicked(self, item):
|
||||
"""item单击事件"""
|
||||
if item.url: # 调用浏览器打开网址
|
||||
webbrowser.open_new_tab(item.url)
|
||||
|
||||
def parseData(self, datas, parent=None):
|
||||
"""解析json数据"""
|
||||
for data in datas:
|
||||
url = data.get('url', '')
|
||||
items = data.get('items', [])
|
||||
# 生成item
|
||||
_item = QTreeWidgetItem(parent)
|
||||
_item.setIcon(0, QIcon(data.get('icon', '')))
|
||||
_widget = ItemWidget(
|
||||
data.get('name', ''),
|
||||
data.get('badge', []),
|
||||
self
|
||||
)
|
||||
_item.url = url # 可以直接设置变量值
|
||||
self.setItemWidget(_item, 0, _widget)
|
||||
if url:
|
||||
continue # 跳过
|
||||
# 解析儿子
|
||||
if items:
|
||||
self.parseData(items, _item)
|
||||
|
||||
def loadData(self, path):
|
||||
"""加载json数据"""
|
||||
datas = open(path, 'rb').read()
|
||||
datas = datas.decode(chardet.detect(datas).get('encoding', 'utf-8'))
|
||||
self.parseData(json.loads(datas), self)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet("""QTreeView {
|
||||
outline: 0px;
|
||||
background: rgb(47, 64, 78);
|
||||
}
|
||||
QTreeView::item {
|
||||
min-height: 92px;
|
||||
}
|
||||
QTreeView::item:hover {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView::item:selected {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::item:selected:active{
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView::item:selected:!active{
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::branch:has-siblings:!adjoins-item {
|
||||
background: green;
|
||||
}
|
||||
QTreeView::branch:closed:has-children:has-siblings {
|
||||
background: rgb(47, 64, 78);
|
||||
}
|
||||
|
||||
QTreeView::branch:has-children:!has-siblings:closed {
|
||||
background: rgb(47, 64, 78);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children:has-siblings {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
|
||||
QTreeView::branch:open:has-children:!has-siblings {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView:branch:hover {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
QTreeView:branch:selected {
|
||||
background: rgb(41, 56, 71);
|
||||
}
|
||||
""")
|
||||
w = JsonTreeWidget()
|
||||
w.show()
|
||||
w.loadData('data.json')
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,108 +1,108 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月23日
|
||||
@author: Irony
|
||||
@site: 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_())
|
||||
#!/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_())
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年7月26日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: QGraphicsView练习.QGraphicsItem.Item移动
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年7月26日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: QGraphicsView练习.QGraphicsItem.Item移动
|
||||
@description:
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
# Created on 2018年7月26日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: QGraphicsView练习.QGraphicsItem.ttt
|
||||
# description:
|
||||
|
|
|
@ -1,78 +1,78 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月24日
|
||||
@author: Irony
|
||||
@site: 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_())
|
||||
#!/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 +1,19 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtCore import QObject
|
||||
|
||||
# Created on 2018年3月26日
|
||||
# author: Irony
|
||||
# site: 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):
|
||||
#!/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 +1,158 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月24日
|
||||
@author: Irony
|
||||
@site: 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_())
|
||||
#!/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_())
|
||||
|
|
|
@ -8,7 +8,7 @@ from PyQt5.QtWidgets import QListView, QWidget, QHBoxLayout, QLineEdit,\
|
|||
|
||||
# Created on 2018年8月4日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: QListView.显示自定义Widget
|
||||
# description:
|
||||
|
|
|
@ -12,7 +12,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QListView,\
|
|||
|
||||
# Created on 2018年8月4日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: QListView.显示自定义Widget并排序
|
||||
# description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年9月14日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: DragListWidget
|
||||
@description:
|
||||
|
|
|
@ -1,48 +1,48 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtCore import QFile, QIODevice, QTextStream, QTextCodec
|
||||
from PyQt5.QtWidgets import QTextBrowser
|
||||
|
||||
import res_rc # @UnresolvedImport @UnusedImport
|
||||
|
||||
|
||||
# Created on 2018年5月1日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: QRC资源文件使用.textread
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class TextBrowser(QTextBrowser):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TextBrowser, self).__init__(*args, **kwargs)
|
||||
self.setText(self.readText(':/README.md'))
|
||||
|
||||
def readText(self, path):
|
||||
file = QFile(path)
|
||||
if not file.open(QIODevice.ReadOnly):
|
||||
return ''
|
||||
stream = QTextStream(file)
|
||||
# 下面这句设置编码根据文件的编码自行确定
|
||||
stream.setCodec(QTextCodec.codecForName('UTF-8'))
|
||||
data = stream.readAll()
|
||||
file.close()
|
||||
del stream
|
||||
return data
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.aboutToQuit.connect(res_rc.qCleanupResources) # 退出时要清理资源
|
||||
w = TextBrowser()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtCore import QFile, QIODevice, QTextStream, QTextCodec
|
||||
from PyQt5.QtWidgets import QTextBrowser
|
||||
|
||||
import res_rc # @UnresolvedImport @UnusedImport
|
||||
|
||||
|
||||
# Created on 2018年5月1日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: QRC资源文件使用.textread
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class TextBrowser(QTextBrowser):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TextBrowser, self).__init__(*args, **kwargs)
|
||||
self.setText(self.readText(':/README.md'))
|
||||
|
||||
def readText(self, path):
|
||||
file = QFile(path)
|
||||
if not file.open(QIODevice.ReadOnly):
|
||||
return ''
|
||||
stream = QTextStream(file)
|
||||
# 下面这句设置编码根据文件的编码自行确定
|
||||
stream.setCodec(QTextCodec.codecForName('UTF-8'))
|
||||
data = stream.readAll()
|
||||
file.close()
|
||||
del stream
|
||||
return data
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.aboutToQuit.connect(res_rc.qCleanupResources) # 退出时要清理资源
|
||||
w = TextBrowser()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# 各种各样的PyQt测试和例子
|
||||
|
||||
# [博客](https://pyqt5.com)
|
||||
|
||||
### [Python.4 or Python][PyQt5]
|
||||
|
||||
### I、 项目型
|
||||
|
|
|
@ -1,66 +1,66 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
from SettingUi import Ui_Setting # @UnresolvedImport
|
||||
|
||||
|
||||
# Created on 2018年3月28日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: 仿QQ设置面板.Window
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Window(QWidget, Ui_Setting):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
self.setupUi(self)
|
||||
self.resize(700, 435)
|
||||
self._blockSignals = False
|
||||
|
||||
# 绑定滚动条和左侧item事件
|
||||
self.scrollArea.verticalScrollBar().valueChanged.connect(
|
||||
self.onValueChanged)
|
||||
self.listWidget.itemClicked.connect(self.onItemClicked)
|
||||
|
||||
def onValueChanged(self, value):
|
||||
"""滚动条"""
|
||||
if self._blockSignals:
|
||||
# 防止item点击时改变滚动条会触发这里
|
||||
return
|
||||
for i in range(8): # 因为这里右侧有8个widget
|
||||
widget = getattr(self, 'widget_%d' % i, None)
|
||||
# widget不为空且在可视范围内
|
||||
if widget and not widget.visibleRegion().isEmpty():
|
||||
self.listWidget.setCurrentRow(i) # 设置item的选中
|
||||
return
|
||||
|
||||
def onItemClicked(self, item):
|
||||
"""左侧item"""
|
||||
row = self.listWidget.row(item) # 获取点击的item的索引
|
||||
# 由于右侧的widget是按照命名widget_0 widget_1这样比较规范的方法,可以通过getattr找到
|
||||
widget = getattr(self, 'widget_%d' % row, None)
|
||||
if not widget:
|
||||
return
|
||||
# 定位右侧位置并滚动
|
||||
self._blockSignals = True
|
||||
self.scrollArea.verticalScrollBar().setSliderPosition(widget.pos().y())
|
||||
self._blockSignals = False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet(open("style.qss", "rb").read().decode("utf-8"))
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
from SettingUi import Ui_Setting # @UnresolvedImport
|
||||
|
||||
|
||||
# Created on 2018年3月28日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: 仿QQ设置面板.Window
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Window(QWidget, Ui_Setting):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
self.setupUi(self)
|
||||
self.resize(700, 435)
|
||||
self._blockSignals = False
|
||||
|
||||
# 绑定滚动条和左侧item事件
|
||||
self.scrollArea.verticalScrollBar().valueChanged.connect(
|
||||
self.onValueChanged)
|
||||
self.listWidget.itemClicked.connect(self.onItemClicked)
|
||||
|
||||
def onValueChanged(self, value):
|
||||
"""滚动条"""
|
||||
if self._blockSignals:
|
||||
# 防止item点击时改变滚动条会触发这里
|
||||
return
|
||||
for i in range(8): # 因为这里右侧有8个widget
|
||||
widget = getattr(self, 'widget_%d' % i, None)
|
||||
# widget不为空且在可视范围内
|
||||
if widget and not widget.visibleRegion().isEmpty():
|
||||
self.listWidget.setCurrentRow(i) # 设置item的选中
|
||||
return
|
||||
|
||||
def onItemClicked(self, item):
|
||||
"""左侧item"""
|
||||
row = self.listWidget.row(item) # 获取点击的item的索引
|
||||
# 由于右侧的widget是按照命名widget_0 widget_1这样比较规范的方法,可以通过getattr找到
|
||||
widget = getattr(self, 'widget_%d' % row, None)
|
||||
if not widget:
|
||||
return
|
||||
# 定位右侧位置并滚动
|
||||
self._blockSignals = True
|
||||
self.scrollArea.verticalScrollBar().setSliderPosition(widget.pos().y())
|
||||
self._blockSignals = False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet(open("style.qss", "rb").read().decode("utf-8"))
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,112 +1,112 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月21日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: Splitter
|
||||
@description:
|
||||
"""
|
||||
import sys
|
||||
|
||||
from PyQt5.QtCore import Qt, QPointF, pyqtSignal
|
||||
from PyQt5.QtGui import QPainter, QPolygonF
|
||||
from PyQt5.QtWidgets import QTextEdit, QListWidget,\
|
||||
QTreeWidget, QSplitter, QApplication, QMainWindow, QSplitterHandle
|
||||
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = "Copyright (c) 2018 Irony"
|
||||
__Version__ = "Version 1.0"\
|
||||
|
||||
|
||||
|
||||
class SplitterHandle(QSplitterHandle):
|
||||
clicked = pyqtSignal()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SplitterHandle, self).__init__(*args, **kwargs)
|
||||
# 如果不设置这个,则鼠标只能在按下后移动才能响应mouseMoveEvent
|
||||
self.setMouseTracking(True)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
super(SplitterHandle, self).mousePressEvent(event)
|
||||
if event.pos().y() <= 24:
|
||||
# 发送点击信号
|
||||
self.clicked.emit()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""鼠标移动事件"""
|
||||
# 当y坐标小于24时,也就是顶部的矩形框高度
|
||||
if event.pos().y() <= 24:
|
||||
# 取消鼠标样式
|
||||
self.unsetCursor()
|
||||
event.accept()
|
||||
else:
|
||||
# 设置默认的鼠标样式并可以移动
|
||||
self.setCursor(Qt.SplitHCursor if self.orientation()
|
||||
== Qt.Horizontal else Qt.SplitVCursor)
|
||||
super(SplitterHandle, self).mouseMoveEvent(event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
# 绘制默认的样式
|
||||
super(SplitterHandle, self).paintEvent(event)
|
||||
# 绘制顶部扩展按钮
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing, True)
|
||||
painter.setPen(Qt.red)
|
||||
# 画矩形
|
||||
painter.drawRect(0, 0, self.width(), 24)
|
||||
# 画三角形
|
||||
painter.setBrush(Qt.red)
|
||||
painter.drawPolygon(QPolygonF([
|
||||
QPointF(0, (24 - 8) / 2),
|
||||
QPointF(self.width() - 2, 24 / 2),
|
||||
QPointF(0, (24 + 8) / 2)
|
||||
]))
|
||||
|
||||
|
||||
class Splitter(QSplitter):
|
||||
|
||||
def onClicked(self):
|
||||
print('clicked')
|
||||
|
||||
def createHandle(self):
|
||||
if self.count() == 1:
|
||||
# 这里表示第一个分割条
|
||||
handle = SplitterHandle(self.orientation(), self)
|
||||
handle.clicked.connect(self.onClicked)
|
||||
return handle
|
||||
return super(Splitter, self).createHandle()
|
||||
|
||||
|
||||
class SplitterWindow(QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super(SplitterWindow, self).__init__(parent)
|
||||
self.resize(400, 400)
|
||||
self.setWindowTitle('PyQt Qsplitter')
|
||||
textedit = QTextEdit('QTextEdit', self)
|
||||
listwidget = QListWidget(self)
|
||||
listwidget.addItem("This is a \nListWidget!")
|
||||
treewidget = QTreeWidget()
|
||||
treewidget.setHeaderLabels(['This', 'is', 'a', 'TreeWidgets!'])
|
||||
|
||||
splitter = Splitter(self)
|
||||
splitter.setHandleWidth(8)
|
||||
splitter.addWidget(textedit)
|
||||
splitter.addWidget(listwidget)
|
||||
splitter.addWidget(treewidget)
|
||||
# Qt.Vertical 垂直 Qt.Horizontal 水平
|
||||
splitter.setOrientation(Qt.Horizontal)
|
||||
self.setCentralWidget(splitter)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
main = SplitterWindow()
|
||||
main.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月21日
|
||||
@author: Irony
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: Splitter
|
||||
@description:
|
||||
"""
|
||||
import sys
|
||||
|
||||
from PyQt5.QtCore import Qt, QPointF, pyqtSignal
|
||||
from PyQt5.QtGui import QPainter, QPolygonF
|
||||
from PyQt5.QtWidgets import QTextEdit, QListWidget,\
|
||||
QTreeWidget, QSplitter, QApplication, QMainWindow, QSplitterHandle
|
||||
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = "Copyright (c) 2018 Irony"
|
||||
__Version__ = "Version 1.0"\
|
||||
|
||||
|
||||
|
||||
class SplitterHandle(QSplitterHandle):
|
||||
clicked = pyqtSignal()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SplitterHandle, self).__init__(*args, **kwargs)
|
||||
# 如果不设置这个,则鼠标只能在按下后移动才能响应mouseMoveEvent
|
||||
self.setMouseTracking(True)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
super(SplitterHandle, self).mousePressEvent(event)
|
||||
if event.pos().y() <= 24:
|
||||
# 发送点击信号
|
||||
self.clicked.emit()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""鼠标移动事件"""
|
||||
# 当y坐标小于24时,也就是顶部的矩形框高度
|
||||
if event.pos().y() <= 24:
|
||||
# 取消鼠标样式
|
||||
self.unsetCursor()
|
||||
event.accept()
|
||||
else:
|
||||
# 设置默认的鼠标样式并可以移动
|
||||
self.setCursor(Qt.SplitHCursor if self.orientation()
|
||||
== Qt.Horizontal else Qt.SplitVCursor)
|
||||
super(SplitterHandle, self).mouseMoveEvent(event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
# 绘制默认的样式
|
||||
super(SplitterHandle, self).paintEvent(event)
|
||||
# 绘制顶部扩展按钮
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing, True)
|
||||
painter.setPen(Qt.red)
|
||||
# 画矩形
|
||||
painter.drawRect(0, 0, self.width(), 24)
|
||||
# 画三角形
|
||||
painter.setBrush(Qt.red)
|
||||
painter.drawPolygon(QPolygonF([
|
||||
QPointF(0, (24 - 8) / 2),
|
||||
QPointF(self.width() - 2, 24 / 2),
|
||||
QPointF(0, (24 + 8) / 2)
|
||||
]))
|
||||
|
||||
|
||||
class Splitter(QSplitter):
|
||||
|
||||
def onClicked(self):
|
||||
print('clicked')
|
||||
|
||||
def createHandle(self):
|
||||
if self.count() == 1:
|
||||
# 这里表示第一个分割条
|
||||
handle = SplitterHandle(self.orientation(), self)
|
||||
handle.clicked.connect(self.onClicked)
|
||||
return handle
|
||||
return super(Splitter, self).createHandle()
|
||||
|
||||
|
||||
class SplitterWindow(QMainWindow):
|
||||
def __init__(self, parent=None):
|
||||
super(SplitterWindow, self).__init__(parent)
|
||||
self.resize(400, 400)
|
||||
self.setWindowTitle('PyQt Qsplitter')
|
||||
textedit = QTextEdit('QTextEdit', self)
|
||||
listwidget = QListWidget(self)
|
||||
listwidget.addItem("This is a \nListWidget!")
|
||||
treewidget = QTreeWidget()
|
||||
treewidget.setHeaderLabels(['This', 'is', 'a', 'TreeWidgets!'])
|
||||
|
||||
splitter = Splitter(self)
|
||||
splitter.setHandleWidth(8)
|
||||
splitter.addWidget(textedit)
|
||||
splitter.addWidget(listwidget)
|
||||
splitter.addWidget(treewidget)
|
||||
# Qt.Vertical 垂直 Qt.Horizontal 水平
|
||||
splitter.setOrientation(Qt.Horizontal)
|
||||
self.setCentralWidget(splitter)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv)
|
||||
main = SplitterWindow()
|
||||
main.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年8月22日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 动画特效.右键菜单动画
|
||||
@description:
|
||||
|
|
|
@ -6,7 +6,7 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton
|
|||
|
||||
# Created on 2018年6月14日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: 动画特效.淡入淡出
|
||||
# description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月30日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 单实例应用.Application
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月30日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: TestQSharedMemory
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月30日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: TestQSingleApplication
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月30日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: WindowNotify
|
||||
@description:
|
||||
|
|
|
@ -1,70 +1,70 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月9日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: inheritQThread
|
||||
@description: 继承QThread
|
||||
"""
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
|
||||
|
||||
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Worker(QThread):
|
||||
|
||||
valueChanged = pyqtSignal(int) # 值变化信号
|
||||
|
||||
def run(self):
|
||||
print('thread id', int(QThread.currentThreadId()))
|
||||
for i in range(1, 101):
|
||||
print('value', i)
|
||||
self.valueChanged.emit(i)
|
||||
QThread.sleep(1)
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self)
|
||||
self.progressBar = QProgressBar(self)
|
||||
self.progressBar.setRange(0, 100)
|
||||
layout.addWidget(self.progressBar)
|
||||
layout.addWidget(QPushButton('开启线程', self, clicked=self.onStart))
|
||||
|
||||
# 当前线程id
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
|
||||
# 子线程
|
||||
self._thread = Worker(self)
|
||||
self._thread.finished.connect(self._thread.deleteLater)
|
||||
self._thread.valueChanged.connect(self.progressBar.setValue)
|
||||
|
||||
def onStart(self):
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
self._thread.start() # 启动线程
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self._thread.isRunning():
|
||||
self._thread.quit()
|
||||
# 强制
|
||||
# self._thread.terminate()
|
||||
del self._thread
|
||||
super(Window, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月9日
|
||||
@author: Irony
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: inheritQThread
|
||||
@description: 继承QThread
|
||||
"""
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
|
||||
|
||||
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Worker(QThread):
|
||||
|
||||
valueChanged = pyqtSignal(int) # 值变化信号
|
||||
|
||||
def run(self):
|
||||
print('thread id', int(QThread.currentThreadId()))
|
||||
for i in range(1, 101):
|
||||
print('value', i)
|
||||
self.valueChanged.emit(i)
|
||||
QThread.sleep(1)
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self)
|
||||
self.progressBar = QProgressBar(self)
|
||||
self.progressBar.setRange(0, 100)
|
||||
layout.addWidget(self.progressBar)
|
||||
layout.addWidget(QPushButton('开启线程', self, clicked=self.onStart))
|
||||
|
||||
# 当前线程id
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
|
||||
# 子线程
|
||||
self._thread = Worker(self)
|
||||
self._thread.finished.connect(self._thread.deleteLater)
|
||||
self._thread.valueChanged.connect(self.progressBar.setValue)
|
||||
|
||||
def onStart(self):
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
self._thread.start() # 启动线程
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self._thread.isRunning():
|
||||
self._thread.quit()
|
||||
# 强制
|
||||
# self._thread.terminate()
|
||||
del self._thread
|
||||
super(Window, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,74 +1,74 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月9日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: moveToThread
|
||||
@description: moveToThread
|
||||
"""
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QThread, QTimer
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
|
||||
|
||||
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Worker(QObject):
|
||||
|
||||
valueChanged = pyqtSignal(int) # 值变化信号
|
||||
|
||||
def run(self):
|
||||
print('thread id', int(QThread.currentThreadId()))
|
||||
for i in range(1, 101):
|
||||
print('value', i)
|
||||
self.valueChanged.emit(i)
|
||||
QThread.sleep(1)
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self)
|
||||
self.progressBar = QProgressBar(self)
|
||||
self.progressBar.setRange(0, 100)
|
||||
layout.addWidget(self.progressBar)
|
||||
layout.addWidget(QPushButton('开启线程', self, clicked=self.onStart))
|
||||
|
||||
# 当前线程id
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
|
||||
# 启动线程更新进度条值
|
||||
self._thread = QThread(self)
|
||||
self._worker = Worker()
|
||||
self._worker.moveToThread(self._thread) # 移动到线程中执行
|
||||
self._thread.finished.connect(self._worker.deleteLater)
|
||||
self._worker.valueChanged.connect(self.progressBar.setValue)
|
||||
|
||||
def onStart(self):
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
self._thread.start() # 启动线程
|
||||
QTimer.singleShot(1, self._worker.run)
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self._thread.isRunning():
|
||||
self._thread.quit()
|
||||
# 强制
|
||||
# self._thread.terminate()
|
||||
del self._thread
|
||||
del self._worker
|
||||
super(Window, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月9日
|
||||
@author: Irony
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: moveToThread
|
||||
@description: moveToThread
|
||||
"""
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QThread, QTimer
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
|
||||
|
||||
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Worker(QObject):
|
||||
|
||||
valueChanged = pyqtSignal(int) # 值变化信号
|
||||
|
||||
def run(self):
|
||||
print('thread id', int(QThread.currentThreadId()))
|
||||
for i in range(1, 101):
|
||||
print('value', i)
|
||||
self.valueChanged.emit(i)
|
||||
QThread.sleep(1)
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self)
|
||||
self.progressBar = QProgressBar(self)
|
||||
self.progressBar.setRange(0, 100)
|
||||
layout.addWidget(self.progressBar)
|
||||
layout.addWidget(QPushButton('开启线程', self, clicked=self.onStart))
|
||||
|
||||
# 当前线程id
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
|
||||
# 启动线程更新进度条值
|
||||
self._thread = QThread(self)
|
||||
self._worker = Worker()
|
||||
self._worker.moveToThread(self._thread) # 移动到线程中执行
|
||||
self._thread.finished.connect(self._worker.deleteLater)
|
||||
self._worker.valueChanged.connect(self.progressBar.setValue)
|
||||
|
||||
def onStart(self):
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
self._thread.start() # 启动线程
|
||||
QTimer.singleShot(1, self._worker.run)
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self._thread.isRunning():
|
||||
self._thread.quit()
|
||||
# 强制
|
||||
# self._thread.terminate()
|
||||
del self._thread
|
||||
del self._worker
|
||||
super(Window, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
234
多线程使用/线程挂起恢复.py
234
多线程使用/线程挂起恢复.py
|
@ -1,117 +1,117 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import ctypes
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
|
||||
import win32con
|
||||
from win32process import SuspendThread, ResumeThread
|
||||
|
||||
|
||||
# Created on 2018年3月13日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: 多线程使用.a
|
||||
# description:
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Worker(QThread):
|
||||
|
||||
valueChanged = pyqtSignal(int) # 值变化信号
|
||||
handle = -1
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.handle = ctypes.windll.kernel32.OpenThread( # @UndefinedVariable
|
||||
win32con.PROCESS_ALL_ACCESS, False, int(QThread.currentThreadId()))
|
||||
except Exception as e:
|
||||
print('get thread handle failed', e)
|
||||
print('thread id', int(QThread.currentThreadId()))
|
||||
for i in range(1, 101):
|
||||
print('value', i)
|
||||
self.valueChanged.emit(i)
|
||||
QThread.sleep(1)
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self)
|
||||
self.progressBar = QProgressBar(self)
|
||||
self.progressBar.setRange(0, 100)
|
||||
layout.addWidget(self.progressBar)
|
||||
self.startButton = QPushButton('开启线程', self, clicked=self.onStart)
|
||||
layout.addWidget(self.startButton)
|
||||
self.suspendButton = QPushButton(
|
||||
'挂起线程', self, clicked=self.onSuspendThread, enabled=False)
|
||||
layout.addWidget(self.suspendButton)
|
||||
self.resumeButton = QPushButton(
|
||||
'恢复线程', self, clicked=self.onResumeThread, enabled=False)
|
||||
layout.addWidget(self.resumeButton)
|
||||
self.stopButton = QPushButton(
|
||||
'终止线程', self, clicked=self.onStopThread, enabled=False)
|
||||
layout.addWidget(self.stopButton)
|
||||
|
||||
# 当前线程id
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
|
||||
# 子线程
|
||||
self._thread = Worker(self)
|
||||
self._thread.finished.connect(self._thread.deleteLater)
|
||||
self._thread.valueChanged.connect(self.progressBar.setValue)
|
||||
|
||||
def onStart(self):
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
self._thread.start() # 启动线程
|
||||
self.startButton.setEnabled(False)
|
||||
self.suspendButton.setEnabled(True)
|
||||
self.stopButton.setEnabled(True)
|
||||
|
||||
def onSuspendThread(self):
|
||||
if self._thread.handle == -1:
|
||||
return print('handle is wrong')
|
||||
ret = SuspendThread(self._thread.handle)
|
||||
print('挂起线程', self._thread.handle, ret)
|
||||
self.suspendButton.setEnabled(False)
|
||||
self.resumeButton.setEnabled(True)
|
||||
|
||||
def onResumeThread(self):
|
||||
if self._thread.handle == -1:
|
||||
return print('handle is wrong')
|
||||
ret = ResumeThread(self._thread.handle)
|
||||
print('恢复线程', self._thread.handle, ret)
|
||||
self.suspendButton.setEnabled(True)
|
||||
self.resumeButton.setEnabled(False)
|
||||
|
||||
def onStopThread(self):
|
||||
self.startButton.setEnabled(False)
|
||||
self.suspendButton.setEnabled(False)
|
||||
self.resumeButton.setEnabled(False)
|
||||
ret = ctypes.windll.kernel32.TerminateThread( # @UndefinedVariable
|
||||
self._thread.handle, 0)
|
||||
print('终止线程', self._thread.handle, ret)
|
||||
self.stopButton.setEnabled(False)
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self._thread.isRunning():
|
||||
self._thread.quit()
|
||||
# 强制
|
||||
# self._thread.terminate()
|
||||
del self._thread
|
||||
super(Window, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import os
|
||||
print('pid', os.getpid())
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import ctypes
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton
|
||||
import win32con
|
||||
from win32process import SuspendThread, ResumeThread
|
||||
|
||||
|
||||
# Created on 2018年3月13日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: 多线程使用.a
|
||||
# description:
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class Worker(QThread):
|
||||
|
||||
valueChanged = pyqtSignal(int) # 值变化信号
|
||||
handle = -1
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.handle = ctypes.windll.kernel32.OpenThread( # @UndefinedVariable
|
||||
win32con.PROCESS_ALL_ACCESS, False, int(QThread.currentThreadId()))
|
||||
except Exception as e:
|
||||
print('get thread handle failed', e)
|
||||
print('thread id', int(QThread.currentThreadId()))
|
||||
for i in range(1, 101):
|
||||
print('value', i)
|
||||
self.valueChanged.emit(i)
|
||||
QThread.sleep(1)
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self)
|
||||
self.progressBar = QProgressBar(self)
|
||||
self.progressBar.setRange(0, 100)
|
||||
layout.addWidget(self.progressBar)
|
||||
self.startButton = QPushButton('开启线程', self, clicked=self.onStart)
|
||||
layout.addWidget(self.startButton)
|
||||
self.suspendButton = QPushButton(
|
||||
'挂起线程', self, clicked=self.onSuspendThread, enabled=False)
|
||||
layout.addWidget(self.suspendButton)
|
||||
self.resumeButton = QPushButton(
|
||||
'恢复线程', self, clicked=self.onResumeThread, enabled=False)
|
||||
layout.addWidget(self.resumeButton)
|
||||
self.stopButton = QPushButton(
|
||||
'终止线程', self, clicked=self.onStopThread, enabled=False)
|
||||
layout.addWidget(self.stopButton)
|
||||
|
||||
# 当前线程id
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
|
||||
# 子线程
|
||||
self._thread = Worker(self)
|
||||
self._thread.finished.connect(self._thread.deleteLater)
|
||||
self._thread.valueChanged.connect(self.progressBar.setValue)
|
||||
|
||||
def onStart(self):
|
||||
print('main id', int(QThread.currentThreadId()))
|
||||
self._thread.start() # 启动线程
|
||||
self.startButton.setEnabled(False)
|
||||
self.suspendButton.setEnabled(True)
|
||||
self.stopButton.setEnabled(True)
|
||||
|
||||
def onSuspendThread(self):
|
||||
if self._thread.handle == -1:
|
||||
return print('handle is wrong')
|
||||
ret = SuspendThread(self._thread.handle)
|
||||
print('挂起线程', self._thread.handle, ret)
|
||||
self.suspendButton.setEnabled(False)
|
||||
self.resumeButton.setEnabled(True)
|
||||
|
||||
def onResumeThread(self):
|
||||
if self._thread.handle == -1:
|
||||
return print('handle is wrong')
|
||||
ret = ResumeThread(self._thread.handle)
|
||||
print('恢复线程', self._thread.handle, ret)
|
||||
self.suspendButton.setEnabled(True)
|
||||
self.resumeButton.setEnabled(False)
|
||||
|
||||
def onStopThread(self):
|
||||
self.startButton.setEnabled(False)
|
||||
self.suspendButton.setEnabled(False)
|
||||
self.resumeButton.setEnabled(False)
|
||||
ret = ctypes.windll.kernel32.TerminateThread( # @UndefinedVariable
|
||||
self._thread.handle, 0)
|
||||
print('终止线程', self._thread.handle, ret)
|
||||
self.stopButton.setEnabled(False)
|
||||
|
||||
def closeEvent(self, event):
|
||||
if self._thread.isRunning():
|
||||
self._thread.quit()
|
||||
# 强制
|
||||
# self._thread.terminate()
|
||||
del self._thread
|
||||
super(Window, self).closeEvent(event)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import os
|
||||
print('pid', os.getpid())
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月30日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: FontAwesome
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月30日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: TestFontAwesome
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月30日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: TestFontRoboto
|
||||
@description:
|
||||
|
|
|
@ -10,7 +10,7 @@ from PyQt5.QtWidgets import QWidget, QListWidget, QStackedWidget, QHBoxLayout,\
|
|||
|
||||
# Created on 2018年5月29日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: LeftTabWidget
|
||||
# description:
|
||||
|
|
|
@ -8,7 +8,7 @@ import win32gui
|
|||
|
||||
# Created on 2018年6月8日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: 简单探测窗口和放大截图
|
||||
# description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年5月15日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 数据库查询显示表格.main
|
||||
@description:
|
||||
|
|
|
@ -1,342 +1,342 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, QPoint
|
||||
from PyQt5.QtGui import QFont, QEnterEvent, QPainter, QColor, QPen
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel,\
|
||||
QSpacerItem, QSizePolicy, QPushButton
|
||||
|
||||
|
||||
# Created on 2018年4月30日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: FramelessWindow
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class TitleBar(QWidget):
|
||||
|
||||
# 窗口最小化信号
|
||||
windowMinimumed = pyqtSignal()
|
||||
# 窗口最大化信号
|
||||
windowMaximumed = pyqtSignal()
|
||||
# 窗口还原信号
|
||||
windowNormaled = pyqtSignal()
|
||||
# 窗口关闭信号
|
||||
windowClosed = pyqtSignal()
|
||||
# 窗口移动
|
||||
windowMoved = pyqtSignal(QPoint)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TitleBar, self).__init__(*args, **kwargs)
|
||||
# 支持qss设置背景
|
||||
self.setAttribute(Qt.WA_StyledBackground, True)
|
||||
self.mPos = None
|
||||
self.iconSize = 20 # 图标的默认大小
|
||||
# 设置默认背景颜色,否则由于受到父窗口的影响导致透明
|
||||
self.setAutoFillBackground(True)
|
||||
palette = self.palette()
|
||||
palette.setColor(palette.Window, QColor(240, 240, 240))
|
||||
self.setPalette(palette)
|
||||
# 布局
|
||||
layout = QHBoxLayout(self, spacing=0)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
# 窗口图标
|
||||
self.iconLabel = QLabel(self)
|
||||
# self.iconLabel.setScaledContents(True)
|
||||
layout.addWidget(self.iconLabel)
|
||||
# 窗口标题
|
||||
self.titleLabel = QLabel(self)
|
||||
self.titleLabel.setMargin(2)
|
||||
layout.addWidget(self.titleLabel)
|
||||
# 中间伸缩条
|
||||
layout.addSpacerItem(QSpacerItem(
|
||||
40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
|
||||
# 利用Webdings字体来显示图标
|
||||
font = self.font() or QFont()
|
||||
font.setFamily('Webdings')
|
||||
# 最小化按钮
|
||||
self.buttonMinimum = QPushButton(
|
||||
'0', self, clicked=self.windowMinimumed.emit, font=font, objectName='buttonMinimum')
|
||||
layout.addWidget(self.buttonMinimum)
|
||||
# 最大化/还原按钮
|
||||
self.buttonMaximum = QPushButton(
|
||||
'1', self, clicked=self.showMaximized, font=font, objectName='buttonMaximum')
|
||||
layout.addWidget(self.buttonMaximum)
|
||||
# 关闭按钮
|
||||
self.buttonClose = QPushButton(
|
||||
'r', self, clicked=self.windowClosed.emit, font=font, objectName='buttonClose')
|
||||
layout.addWidget(self.buttonClose)
|
||||
# 初始高度
|
||||
self.setHeight()
|
||||
|
||||
def showMaximized(self):
|
||||
if self.buttonMaximum.text() == '1':
|
||||
# 最大化
|
||||
self.buttonMaximum.setText('2')
|
||||
self.windowMaximumed.emit()
|
||||
else: # 还原
|
||||
self.buttonMaximum.setText('1')
|
||||
self.windowNormaled.emit()
|
||||
|
||||
def setHeight(self, height=38):
|
||||
"""设置标题栏高度"""
|
||||
self.setMinimumHeight(height)
|
||||
self.setMaximumHeight(height)
|
||||
# 设置右边按钮的大小
|
||||
self.buttonMinimum.setMinimumSize(height, height)
|
||||
self.buttonMinimum.setMaximumSize(height, height)
|
||||
self.buttonMaximum.setMinimumSize(height, height)
|
||||
self.buttonMaximum.setMaximumSize(height, height)
|
||||
self.buttonClose.setMinimumSize(height, height)
|
||||
self.buttonClose.setMaximumSize(height, height)
|
||||
|
||||
def setTitle(self, title):
|
||||
"""设置标题"""
|
||||
self.titleLabel.setText(title)
|
||||
|
||||
def setIcon(self, icon):
|
||||
"""设置图标"""
|
||||
self.iconLabel.setPixmap(icon.pixmap(self.iconSize, self.iconSize))
|
||||
|
||||
def setIconSize(self, size):
|
||||
"""设置图标大小"""
|
||||
self.iconSize = size
|
||||
|
||||
def enterEvent(self, event):
|
||||
self.setCursor(Qt.ArrowCursor)
|
||||
super(TitleBar, self).enterEvent(event)
|
||||
|
||||
def mouseDoubleClickEvent(self, event):
|
||||
super(TitleBar, self).mouseDoubleClickEvent(event)
|
||||
self.showMaximized()
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""鼠标点击事件"""
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.mPos = event.pos()
|
||||
event.accept()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
'''鼠标弹起事件'''
|
||||
self.mPos = None
|
||||
event.accept()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if event.buttons() == Qt.LeftButton and self.mPos:
|
||||
self.windowMoved.emit(self.mapToGlobal(event.pos() - self.mPos))
|
||||
event.accept()
|
||||
|
||||
|
||||
# 枚举左上右下以及四个定点
|
||||
Left, Top, Right, Bottom, LeftTop, RightTop, LeftBottom, RightBottom = range(8)
|
||||
|
||||
|
||||
class FramelessWindow(QWidget):
|
||||
|
||||
# 四周边距
|
||||
Margins = 5
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FramelessWindow, self).__init__(*args, **kwargs)
|
||||
self._pressed = False
|
||||
self.Direction = None
|
||||
# 背景透明
|
||||
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
||||
# 无边框
|
||||
self.setWindowFlag(Qt.FramelessWindowHint)
|
||||
# 鼠标跟踪
|
||||
self.setMouseTracking(True)
|
||||
# 布局
|
||||
layout = QVBoxLayout(self, spacing=0)
|
||||
# 预留边界用于实现无边框窗口调整大小
|
||||
layout.setContentsMargins(
|
||||
self.Margins, self.Margins, self.Margins, self.Margins)
|
||||
# 标题栏
|
||||
self.titleBar = TitleBar(self)
|
||||
layout.addWidget(self.titleBar)
|
||||
# 信号槽
|
||||
self.titleBar.windowMinimumed.connect(self.showMinimized)
|
||||
self.titleBar.windowMaximumed.connect(self.showMaximized)
|
||||
self.titleBar.windowNormaled.connect(self.showNormal)
|
||||
self.titleBar.windowClosed.connect(self.close)
|
||||
self.titleBar.windowMoved.connect(self.move)
|
||||
self.windowTitleChanged.connect(self.titleBar.setTitle)
|
||||
self.windowIconChanged.connect(self.titleBar.setIcon)
|
||||
|
||||
def setTitleBarHeight(self, height=38):
|
||||
"""设置标题栏高度"""
|
||||
self.titleBar.setHeight(height)
|
||||
|
||||
def setIconSize(self, size):
|
||||
"""设置图标的大小"""
|
||||
self.titleBar.setIconSize(size)
|
||||
|
||||
def setWidget(self, widget):
|
||||
"""设置自己的控件"""
|
||||
if hasattr(self, '_widget'):
|
||||
return
|
||||
self._widget = widget
|
||||
# 设置默认背景颜色,否则由于受到父窗口的影响导致透明
|
||||
self._widget.setAutoFillBackground(True)
|
||||
palette = self._widget.palette()
|
||||
palette.setColor(palette.Window, QColor(240, 240, 240))
|
||||
self._widget.setPalette(palette)
|
||||
self._widget.installEventFilter(self)
|
||||
self.layout().addWidget(self._widget)
|
||||
|
||||
def move(self, pos):
|
||||
if self.windowState() == Qt.WindowMaximized or self.windowState() == Qt.WindowFullScreen:
|
||||
# 最大化或者全屏则不允许移动
|
||||
return
|
||||
super(FramelessWindow, self).move(pos)
|
||||
|
||||
def showMaximized(self):
|
||||
"""最大化,要去除上下左右边界,如果不去除则边框地方会有空隙"""
|
||||
super(FramelessWindow, self).showMaximized()
|
||||
self.layout().setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
def showNormal(self):
|
||||
"""还原,要保留上下左右边界,否则没有边框无法调整"""
|
||||
super(FramelessWindow, self).showNormal()
|
||||
self.layout().setContentsMargins(
|
||||
self.Margins, self.Margins, self.Margins, self.Margins)
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
"""事件过滤器,用于解决鼠标进入其它控件后还原为标准鼠标样式"""
|
||||
if isinstance(event, QEnterEvent):
|
||||
self.setCursor(Qt.ArrowCursor)
|
||||
return super(FramelessWindow, self).eventFilter(obj, event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""由于是全透明背景窗口,重绘事件中绘制透明度为1的难以发现的边框,用于调整窗口大小"""
|
||||
super(FramelessWindow, self).paintEvent(event)
|
||||
painter = QPainter(self)
|
||||
painter.setPen(QPen(QColor(255, 255, 255, 1), 2 * self.Margins))
|
||||
painter.drawRect(self.rect())
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""鼠标点击事件"""
|
||||
super(FramelessWindow, self).mousePressEvent(event)
|
||||
if event.button() == Qt.LeftButton:
|
||||
self._mpos = event.pos()
|
||||
self._pressed = True
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
'''鼠标弹起事件'''
|
||||
super(FramelessWindow, self).mouseReleaseEvent(event)
|
||||
self._pressed = False
|
||||
self.Direction = None
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""鼠标移动事件"""
|
||||
super(FramelessWindow, self).mouseMoveEvent(event)
|
||||
pos = event.pos()
|
||||
xPos, yPos = pos.x(), pos.y()
|
||||
wm, hm = self.width() - self.Margins, self.height() - self.Margins
|
||||
if self.isMaximized() or self.isFullScreen():
|
||||
self.Direction = None
|
||||
self.setCursor(Qt.ArrowCursor)
|
||||
return
|
||||
if event.buttons() == Qt.LeftButton and self._pressed:
|
||||
self._resizeWidget(pos)
|
||||
return
|
||||
if xPos <= self.Margins and yPos <= self.Margins:
|
||||
# 左上角
|
||||
self.Direction = LeftTop
|
||||
self.setCursor(Qt.SizeFDiagCursor)
|
||||
elif wm <= xPos <= self.width() and hm <= yPos <= self.height():
|
||||
# 右下角
|
||||
self.Direction = RightBottom
|
||||
self.setCursor(Qt.SizeFDiagCursor)
|
||||
elif wm <= xPos and yPos <= self.Margins:
|
||||
# 右上角
|
||||
self.Direction = RightTop
|
||||
self.setCursor(Qt.SizeBDiagCursor)
|
||||
elif xPos <= self.Margins and hm <= yPos:
|
||||
# 左下角
|
||||
self.Direction = LeftBottom
|
||||
self.setCursor(Qt.SizeBDiagCursor)
|
||||
elif 0 <= xPos <= self.Margins and self.Margins <= yPos <= hm:
|
||||
# 左边
|
||||
self.Direction = Left
|
||||
self.setCursor(Qt.SizeHorCursor)
|
||||
elif wm <= xPos <= self.width() and self.Margins <= yPos <= hm:
|
||||
# 右边
|
||||
self.Direction = Right
|
||||
self.setCursor(Qt.SizeHorCursor)
|
||||
elif self.Margins <= xPos <= wm and 0 <= yPos <= self.Margins:
|
||||
# 上面
|
||||
self.Direction = Top
|
||||
self.setCursor(Qt.SizeVerCursor)
|
||||
elif self.Margins <= xPos <= wm and hm <= yPos <= self.height():
|
||||
# 下面
|
||||
self.Direction = Bottom
|
||||
self.setCursor(Qt.SizeVerCursor)
|
||||
|
||||
def _resizeWidget(self, pos):
|
||||
"""调整窗口大小"""
|
||||
if self.Direction == None:
|
||||
return
|
||||
mpos = pos - self._mpos
|
||||
xPos, yPos = mpos.x(), mpos.y()
|
||||
geometry = self.geometry()
|
||||
x, y, w, h = geometry.x(), geometry.y(), geometry.width(), geometry.height()
|
||||
if self.Direction == LeftTop: # 左上角
|
||||
if w - xPos > self.minimumWidth():
|
||||
x += xPos
|
||||
w -= xPos
|
||||
if h - yPos > self.minimumHeight():
|
||||
y += yPos
|
||||
h -= yPos
|
||||
elif self.Direction == RightBottom: # 右下角
|
||||
if w + xPos > self.minimumWidth():
|
||||
w += xPos
|
||||
self._mpos = pos
|
||||
if h + yPos > self.minimumHeight():
|
||||
h += yPos
|
||||
self._mpos = pos
|
||||
elif self.Direction == RightTop: # 右上角
|
||||
if h - yPos > self.minimumHeight():
|
||||
y += yPos
|
||||
h -= yPos
|
||||
if w + xPos > self.minimumWidth():
|
||||
w += xPos
|
||||
self._mpos.setX(pos.x())
|
||||
elif self.Direction == LeftBottom: # 左下角
|
||||
if w - xPos > self.minimumWidth():
|
||||
x += xPos
|
||||
w -= xPos
|
||||
if h + yPos > self.minimumHeight():
|
||||
h += yPos
|
||||
self._mpos.setY(pos.y())
|
||||
elif self.Direction == Left: # 左边
|
||||
if w - xPos > self.minimumWidth():
|
||||
x += xPos
|
||||
w -= xPos
|
||||
else:
|
||||
return
|
||||
elif self.Direction == Right: # 右边
|
||||
if w + xPos > self.minimumWidth():
|
||||
w += xPos
|
||||
self._mpos = pos
|
||||
else:
|
||||
return
|
||||
elif self.Direction == Top: # 上面
|
||||
if h - yPos > self.minimumHeight():
|
||||
y += yPos
|
||||
h -= yPos
|
||||
else:
|
||||
return
|
||||
elif self.Direction == Bottom: # 下面
|
||||
if h + yPos > self.minimumHeight():
|
||||
h += yPos
|
||||
self._mpos = pos
|
||||
else:
|
||||
return
|
||||
self.setGeometry(x, y, w, h)
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, QPoint
|
||||
from PyQt5.QtGui import QFont, QEnterEvent, QPainter, QColor, QPen
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel,\
|
||||
QSpacerItem, QSizePolicy, QPushButton
|
||||
|
||||
|
||||
# Created on 2018年4月30日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: FramelessWindow
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class TitleBar(QWidget):
|
||||
|
||||
# 窗口最小化信号
|
||||
windowMinimumed = pyqtSignal()
|
||||
# 窗口最大化信号
|
||||
windowMaximumed = pyqtSignal()
|
||||
# 窗口还原信号
|
||||
windowNormaled = pyqtSignal()
|
||||
# 窗口关闭信号
|
||||
windowClosed = pyqtSignal()
|
||||
# 窗口移动
|
||||
windowMoved = pyqtSignal(QPoint)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(TitleBar, self).__init__(*args, **kwargs)
|
||||
# 支持qss设置背景
|
||||
self.setAttribute(Qt.WA_StyledBackground, True)
|
||||
self.mPos = None
|
||||
self.iconSize = 20 # 图标的默认大小
|
||||
# 设置默认背景颜色,否则由于受到父窗口的影响导致透明
|
||||
self.setAutoFillBackground(True)
|
||||
palette = self.palette()
|
||||
palette.setColor(palette.Window, QColor(240, 240, 240))
|
||||
self.setPalette(palette)
|
||||
# 布局
|
||||
layout = QHBoxLayout(self, spacing=0)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
# 窗口图标
|
||||
self.iconLabel = QLabel(self)
|
||||
# self.iconLabel.setScaledContents(True)
|
||||
layout.addWidget(self.iconLabel)
|
||||
# 窗口标题
|
||||
self.titleLabel = QLabel(self)
|
||||
self.titleLabel.setMargin(2)
|
||||
layout.addWidget(self.titleLabel)
|
||||
# 中间伸缩条
|
||||
layout.addSpacerItem(QSpacerItem(
|
||||
40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
|
||||
# 利用Webdings字体来显示图标
|
||||
font = self.font() or QFont()
|
||||
font.setFamily('Webdings')
|
||||
# 最小化按钮
|
||||
self.buttonMinimum = QPushButton(
|
||||
'0', self, clicked=self.windowMinimumed.emit, font=font, objectName='buttonMinimum')
|
||||
layout.addWidget(self.buttonMinimum)
|
||||
# 最大化/还原按钮
|
||||
self.buttonMaximum = QPushButton(
|
||||
'1', self, clicked=self.showMaximized, font=font, objectName='buttonMaximum')
|
||||
layout.addWidget(self.buttonMaximum)
|
||||
# 关闭按钮
|
||||
self.buttonClose = QPushButton(
|
||||
'r', self, clicked=self.windowClosed.emit, font=font, objectName='buttonClose')
|
||||
layout.addWidget(self.buttonClose)
|
||||
# 初始高度
|
||||
self.setHeight()
|
||||
|
||||
def showMaximized(self):
|
||||
if self.buttonMaximum.text() == '1':
|
||||
# 最大化
|
||||
self.buttonMaximum.setText('2')
|
||||
self.windowMaximumed.emit()
|
||||
else: # 还原
|
||||
self.buttonMaximum.setText('1')
|
||||
self.windowNormaled.emit()
|
||||
|
||||
def setHeight(self, height=38):
|
||||
"""设置标题栏高度"""
|
||||
self.setMinimumHeight(height)
|
||||
self.setMaximumHeight(height)
|
||||
# 设置右边按钮的大小
|
||||
self.buttonMinimum.setMinimumSize(height, height)
|
||||
self.buttonMinimum.setMaximumSize(height, height)
|
||||
self.buttonMaximum.setMinimumSize(height, height)
|
||||
self.buttonMaximum.setMaximumSize(height, height)
|
||||
self.buttonClose.setMinimumSize(height, height)
|
||||
self.buttonClose.setMaximumSize(height, height)
|
||||
|
||||
def setTitle(self, title):
|
||||
"""设置标题"""
|
||||
self.titleLabel.setText(title)
|
||||
|
||||
def setIcon(self, icon):
|
||||
"""设置图标"""
|
||||
self.iconLabel.setPixmap(icon.pixmap(self.iconSize, self.iconSize))
|
||||
|
||||
def setIconSize(self, size):
|
||||
"""设置图标大小"""
|
||||
self.iconSize = size
|
||||
|
||||
def enterEvent(self, event):
|
||||
self.setCursor(Qt.ArrowCursor)
|
||||
super(TitleBar, self).enterEvent(event)
|
||||
|
||||
def mouseDoubleClickEvent(self, event):
|
||||
super(TitleBar, self).mouseDoubleClickEvent(event)
|
||||
self.showMaximized()
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""鼠标点击事件"""
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.mPos = event.pos()
|
||||
event.accept()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
'''鼠标弹起事件'''
|
||||
self.mPos = None
|
||||
event.accept()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if event.buttons() == Qt.LeftButton and self.mPos:
|
||||
self.windowMoved.emit(self.mapToGlobal(event.pos() - self.mPos))
|
||||
event.accept()
|
||||
|
||||
|
||||
# 枚举左上右下以及四个定点
|
||||
Left, Top, Right, Bottom, LeftTop, RightTop, LeftBottom, RightBottom = range(8)
|
||||
|
||||
|
||||
class FramelessWindow(QWidget):
|
||||
|
||||
# 四周边距
|
||||
Margins = 5
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FramelessWindow, self).__init__(*args, **kwargs)
|
||||
self._pressed = False
|
||||
self.Direction = None
|
||||
# 背景透明
|
||||
self.setAttribute(Qt.WA_TranslucentBackground, True)
|
||||
# 无边框
|
||||
self.setWindowFlag(Qt.FramelessWindowHint)
|
||||
# 鼠标跟踪
|
||||
self.setMouseTracking(True)
|
||||
# 布局
|
||||
layout = QVBoxLayout(self, spacing=0)
|
||||
# 预留边界用于实现无边框窗口调整大小
|
||||
layout.setContentsMargins(
|
||||
self.Margins, self.Margins, self.Margins, self.Margins)
|
||||
# 标题栏
|
||||
self.titleBar = TitleBar(self)
|
||||
layout.addWidget(self.titleBar)
|
||||
# 信号槽
|
||||
self.titleBar.windowMinimumed.connect(self.showMinimized)
|
||||
self.titleBar.windowMaximumed.connect(self.showMaximized)
|
||||
self.titleBar.windowNormaled.connect(self.showNormal)
|
||||
self.titleBar.windowClosed.connect(self.close)
|
||||
self.titleBar.windowMoved.connect(self.move)
|
||||
self.windowTitleChanged.connect(self.titleBar.setTitle)
|
||||
self.windowIconChanged.connect(self.titleBar.setIcon)
|
||||
|
||||
def setTitleBarHeight(self, height=38):
|
||||
"""设置标题栏高度"""
|
||||
self.titleBar.setHeight(height)
|
||||
|
||||
def setIconSize(self, size):
|
||||
"""设置图标的大小"""
|
||||
self.titleBar.setIconSize(size)
|
||||
|
||||
def setWidget(self, widget):
|
||||
"""设置自己的控件"""
|
||||
if hasattr(self, '_widget'):
|
||||
return
|
||||
self._widget = widget
|
||||
# 设置默认背景颜色,否则由于受到父窗口的影响导致透明
|
||||
self._widget.setAutoFillBackground(True)
|
||||
palette = self._widget.palette()
|
||||
palette.setColor(palette.Window, QColor(240, 240, 240))
|
||||
self._widget.setPalette(palette)
|
||||
self._widget.installEventFilter(self)
|
||||
self.layout().addWidget(self._widget)
|
||||
|
||||
def move(self, pos):
|
||||
if self.windowState() == Qt.WindowMaximized or self.windowState() == Qt.WindowFullScreen:
|
||||
# 最大化或者全屏则不允许移动
|
||||
return
|
||||
super(FramelessWindow, self).move(pos)
|
||||
|
||||
def showMaximized(self):
|
||||
"""最大化,要去除上下左右边界,如果不去除则边框地方会有空隙"""
|
||||
super(FramelessWindow, self).showMaximized()
|
||||
self.layout().setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
def showNormal(self):
|
||||
"""还原,要保留上下左右边界,否则没有边框无法调整"""
|
||||
super(FramelessWindow, self).showNormal()
|
||||
self.layout().setContentsMargins(
|
||||
self.Margins, self.Margins, self.Margins, self.Margins)
|
||||
|
||||
def eventFilter(self, obj, event):
|
||||
"""事件过滤器,用于解决鼠标进入其它控件后还原为标准鼠标样式"""
|
||||
if isinstance(event, QEnterEvent):
|
||||
self.setCursor(Qt.ArrowCursor)
|
||||
return super(FramelessWindow, self).eventFilter(obj, event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
"""由于是全透明背景窗口,重绘事件中绘制透明度为1的难以发现的边框,用于调整窗口大小"""
|
||||
super(FramelessWindow, self).paintEvent(event)
|
||||
painter = QPainter(self)
|
||||
painter.setPen(QPen(QColor(255, 255, 255, 1), 2 * self.Margins))
|
||||
painter.drawRect(self.rect())
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
"""鼠标点击事件"""
|
||||
super(FramelessWindow, self).mousePressEvent(event)
|
||||
if event.button() == Qt.LeftButton:
|
||||
self._mpos = event.pos()
|
||||
self._pressed = True
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
'''鼠标弹起事件'''
|
||||
super(FramelessWindow, self).mouseReleaseEvent(event)
|
||||
self._pressed = False
|
||||
self.Direction = None
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""鼠标移动事件"""
|
||||
super(FramelessWindow, self).mouseMoveEvent(event)
|
||||
pos = event.pos()
|
||||
xPos, yPos = pos.x(), pos.y()
|
||||
wm, hm = self.width() - self.Margins, self.height() - self.Margins
|
||||
if self.isMaximized() or self.isFullScreen():
|
||||
self.Direction = None
|
||||
self.setCursor(Qt.ArrowCursor)
|
||||
return
|
||||
if event.buttons() == Qt.LeftButton and self._pressed:
|
||||
self._resizeWidget(pos)
|
||||
return
|
||||
if xPos <= self.Margins and yPos <= self.Margins:
|
||||
# 左上角
|
||||
self.Direction = LeftTop
|
||||
self.setCursor(Qt.SizeFDiagCursor)
|
||||
elif wm <= xPos <= self.width() and hm <= yPos <= self.height():
|
||||
# 右下角
|
||||
self.Direction = RightBottom
|
||||
self.setCursor(Qt.SizeFDiagCursor)
|
||||
elif wm <= xPos and yPos <= self.Margins:
|
||||
# 右上角
|
||||
self.Direction = RightTop
|
||||
self.setCursor(Qt.SizeBDiagCursor)
|
||||
elif xPos <= self.Margins and hm <= yPos:
|
||||
# 左下角
|
||||
self.Direction = LeftBottom
|
||||
self.setCursor(Qt.SizeBDiagCursor)
|
||||
elif 0 <= xPos <= self.Margins and self.Margins <= yPos <= hm:
|
||||
# 左边
|
||||
self.Direction = Left
|
||||
self.setCursor(Qt.SizeHorCursor)
|
||||
elif wm <= xPos <= self.width() and self.Margins <= yPos <= hm:
|
||||
# 右边
|
||||
self.Direction = Right
|
||||
self.setCursor(Qt.SizeHorCursor)
|
||||
elif self.Margins <= xPos <= wm and 0 <= yPos <= self.Margins:
|
||||
# 上面
|
||||
self.Direction = Top
|
||||
self.setCursor(Qt.SizeVerCursor)
|
||||
elif self.Margins <= xPos <= wm and hm <= yPos <= self.height():
|
||||
# 下面
|
||||
self.Direction = Bottom
|
||||
self.setCursor(Qt.SizeVerCursor)
|
||||
|
||||
def _resizeWidget(self, pos):
|
||||
"""调整窗口大小"""
|
||||
if self.Direction == None:
|
||||
return
|
||||
mpos = pos - self._mpos
|
||||
xPos, yPos = mpos.x(), mpos.y()
|
||||
geometry = self.geometry()
|
||||
x, y, w, h = geometry.x(), geometry.y(), geometry.width(), geometry.height()
|
||||
if self.Direction == LeftTop: # 左上角
|
||||
if w - xPos > self.minimumWidth():
|
||||
x += xPos
|
||||
w -= xPos
|
||||
if h - yPos > self.minimumHeight():
|
||||
y += yPos
|
||||
h -= yPos
|
||||
elif self.Direction == RightBottom: # 右下角
|
||||
if w + xPos > self.minimumWidth():
|
||||
w += xPos
|
||||
self._mpos = pos
|
||||
if h + yPos > self.minimumHeight():
|
||||
h += yPos
|
||||
self._mpos = pos
|
||||
elif self.Direction == RightTop: # 右上角
|
||||
if h - yPos > self.minimumHeight():
|
||||
y += yPos
|
||||
h -= yPos
|
||||
if w + xPos > self.minimumWidth():
|
||||
w += xPos
|
||||
self._mpos.setX(pos.x())
|
||||
elif self.Direction == LeftBottom: # 左下角
|
||||
if w - xPos > self.minimumWidth():
|
||||
x += xPos
|
||||
w -= xPos
|
||||
if h + yPos > self.minimumHeight():
|
||||
h += yPos
|
||||
self._mpos.setY(pos.y())
|
||||
elif self.Direction == Left: # 左边
|
||||
if w - xPos > self.minimumWidth():
|
||||
x += xPos
|
||||
w -= xPos
|
||||
else:
|
||||
return
|
||||
elif self.Direction == Right: # 右边
|
||||
if w + xPos > self.minimumWidth():
|
||||
w += xPos
|
||||
self._mpos = pos
|
||||
else:
|
||||
return
|
||||
elif self.Direction == Top: # 上面
|
||||
if h - yPos > self.minimumHeight():
|
||||
y += yPos
|
||||
h -= yPos
|
||||
else:
|
||||
return
|
||||
elif self.Direction == Bottom: # 下面
|
||||
if h + yPos > self.minimumHeight():
|
||||
h += yPos
|
||||
self._mpos = pos
|
||||
else:
|
||||
return
|
||||
self.setGeometry(x, y, w, h)
|
||||
|
|
|
@ -1,74 +1,74 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTextEdit
|
||||
|
||||
from FramelessWindow import FramelessWindow # @UnresolvedImport
|
||||
|
||||
|
||||
# Created on 2018年4月30日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: Test
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class MainWindow(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MainWindow, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self, spacing=0)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(QPushButton('按钮', self))
|
||||
layout.addWidget(QTextEdit(self))
|
||||
|
||||
|
||||
# 样式
|
||||
StyleSheet = """
|
||||
/*标题栏*/
|
||||
TitleBar {
|
||||
background-color: rgb(54, 157, 180);
|
||||
}
|
||||
|
||||
/*最小化最大化关闭按钮通用默认背景*/
|
||||
#buttonMinimum,#buttonMaximum,#buttonClose {
|
||||
border: none;
|
||||
background-color: rgb(54, 157, 180);
|
||||
}
|
||||
|
||||
/*悬停*/
|
||||
#buttonMinimum:hover,#buttonMaximum:hover {
|
||||
background-color: rgb(48, 141, 162);
|
||||
}
|
||||
#buttonClose:hover {
|
||||
color: white;
|
||||
background-color: rgb(232, 17, 35);
|
||||
}
|
||||
|
||||
/*鼠标按下不放*/
|
||||
#buttonMinimum:pressed,#buttonMaximum:pressed {
|
||||
background-color: rgb(44, 125, 144);
|
||||
}
|
||||
#buttonClose:pressed {
|
||||
color: white;
|
||||
background-color: rgb(161, 73, 92);
|
||||
}
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet(StyleSheet)
|
||||
w = FramelessWindow()
|
||||
w.setWindowTitle('测试标题栏')
|
||||
w.setWindowIcon(QIcon('Qt.ico'))
|
||||
w.setWidget(MainWindow(w)) # 把自己的窗口添加进来
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTextEdit
|
||||
|
||||
from FramelessWindow import FramelessWindow # @UnresolvedImport
|
||||
|
||||
|
||||
# Created on 2018年4月30日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: Test
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class MainWindow(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MainWindow, self).__init__(*args, **kwargs)
|
||||
layout = QVBoxLayout(self, spacing=0)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(QPushButton('按钮', self))
|
||||
layout.addWidget(QTextEdit(self))
|
||||
|
||||
|
||||
# 样式
|
||||
StyleSheet = """
|
||||
/*标题栏*/
|
||||
TitleBar {
|
||||
background-color: rgb(54, 157, 180);
|
||||
}
|
||||
|
||||
/*最小化最大化关闭按钮通用默认背景*/
|
||||
#buttonMinimum,#buttonMaximum,#buttonClose {
|
||||
border: none;
|
||||
background-color: rgb(54, 157, 180);
|
||||
}
|
||||
|
||||
/*悬停*/
|
||||
#buttonMinimum:hover,#buttonMaximum:hover {
|
||||
background-color: rgb(48, 141, 162);
|
||||
}
|
||||
#buttonClose:hover {
|
||||
color: white;
|
||||
background-color: rgb(232, 17, 35);
|
||||
}
|
||||
|
||||
/*鼠标按下不放*/
|
||||
#buttonMinimum:pressed,#buttonMaximum:pressed {
|
||||
background-color: rgb(44, 125, 144);
|
||||
}
|
||||
#buttonClose:pressed {
|
||||
color: white;
|
||||
background-color: rgb(161, 73, 92);
|
||||
}
|
||||
"""
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyleSheet(StyleSheet)
|
||||
w = FramelessWindow()
|
||||
w.setWindowTitle('测试标题栏')
|
||||
w.setWindowIcon(QIcon('Qt.ico'))
|
||||
w.setWidget(MainWindow(w)) # 把自己的窗口添加进来
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -13,7 +13,7 @@ import win32gui
|
|||
|
||||
# Created on 2018年8月2日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: win无边框调整大小
|
||||
# description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年4月6日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: DreamTree
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年6月22日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: MessageBox
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年9月9日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: Notification
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年5月15日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: PaintQSlider
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年5月15日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: QssQSlider
|
||||
@description: 通过QSS美化QSlider
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年9月4日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 界面美化.圆形进度条.CircleProgressBar
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年9月日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: MetroCircleProgress
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年9月5日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: MetroLineProgress
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"""
|
||||
Created on 2018年9月4日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 界面美化.各类进度条.PercentProgressBar
|
||||
@description:
|
||||
|
|
|
@ -1,162 +1,162 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created on 2018年4月1日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: ProgressBar
|
||||
# description:
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
import math
|
||||
|
||||
from PyQt5.QtCore import QTimer, Qt, QRectF, QSize
|
||||
from PyQt5.QtGui import QPainter, QPainterPath, QColor, QFont
|
||||
from PyQt5.QtWidgets import QProgressBar
|
||||
|
||||
|
||||
class ProgressBar(QProgressBar):
|
||||
|
||||
# 浪高百分比
|
||||
waterHeight = 1
|
||||
# 密度
|
||||
waterDensity = 1
|
||||
# 样式1为矩形, 0为圆形
|
||||
styleType = 1
|
||||
# 文字颜色
|
||||
textColor = Qt.white
|
||||
# 背景颜色
|
||||
backgroundColor = Qt.gray
|
||||
# 波浪颜色1
|
||||
waterColor1 = QColor(33, 178, 148)
|
||||
# 波浪颜色2
|
||||
waterColor2 = QColor(33, 178, 148, 100)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ProgressBar, self).__init__(*args, **kwargs)
|
||||
self._offset = 0
|
||||
# 每隔100ms刷新波浪(模拟波浪动态)
|
||||
self._updateTimer = QTimer(self, timeout=self.update)
|
||||
self._updateTimer.start(100)
|
||||
|
||||
def setRange(self, minValue, maxValue):
|
||||
if minValue == maxValue == 0:
|
||||
return # 不允许设置busy状态
|
||||
super(ProgressBar, self).setRange(minValue, maxValue)
|
||||
|
||||
def setMinimum(self, value):
|
||||
if value == self.maximum() == 0:
|
||||
return # 不允许设置busy状态
|
||||
super(ProgressBar, self).setMinimum(value)
|
||||
|
||||
def setMaximum(self, value):
|
||||
if value == self.minimum() == 0:
|
||||
return # 不允许设置busy状态
|
||||
super(ProgressBar, self).setMaximum(value)
|
||||
|
||||
def setWaterHeight(self, height):
|
||||
"""设置浪高"""
|
||||
self.waterHeight = height
|
||||
self.update()
|
||||
|
||||
def setWaterDensity(self, density):
|
||||
"""设置密度"""
|
||||
self.waterDensity = density
|
||||
self.update()
|
||||
|
||||
def setStyleType(self, style):
|
||||
"""设置类型"""
|
||||
self.styleType = style
|
||||
self.update()
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(100, 100)
|
||||
|
||||
def paintEvent(self, event):
|
||||
if self.minimum() == self.maximum() == 0:
|
||||
return
|
||||
# 正弦曲线公式 y = A * sin(ωx + φ) + k
|
||||
# 当前值所占百分比
|
||||
percent = 1 - (self.value() - self.minimum()) / \
|
||||
(self.maximum() - self.minimum())
|
||||
# w表示周期,6为人为定义
|
||||
w = 6 * self.waterDensity * math.pi / self.width()
|
||||
# A振幅 高度百分比,1/26为人为定义
|
||||
A = self.height() * self.waterHeight * 1 / 26
|
||||
# k 高度百分比
|
||||
k = self.height() * percent
|
||||
|
||||
# 波浪1
|
||||
waterPath1 = QPainterPath()
|
||||
waterPath1.moveTo(0, self.height()) # 起点在左下角
|
||||
# 波浪2
|
||||
waterPath2 = QPainterPath()
|
||||
waterPath2.moveTo(0, self.height()) # 起点在左下角
|
||||
|
||||
# 偏移
|
||||
self._offset += 0.6
|
||||
if self._offset > self.width() / 2:
|
||||
self._offset = 0
|
||||
|
||||
for i in range(self.width() + 1):
|
||||
# 从x轴开始计算y轴点
|
||||
y = A * math.sin(w * i + self._offset) + k
|
||||
waterPath1.lineTo(i, y)
|
||||
|
||||
# 相对第一条需要进行错位
|
||||
y = A * math.sin(w * i + self._offset + self.width() / 2 * A) + k
|
||||
waterPath2.lineTo(i, y)
|
||||
|
||||
# 封闭两条波浪,形成一个 U形 上面加波浪的封闭区间
|
||||
waterPath1.lineTo(self.width(), self.height())
|
||||
waterPath1.lineTo(0, self.height())
|
||||
waterPath2.lineTo(self.width(), self.height())
|
||||
waterPath2.lineTo(0, self.height())
|
||||
|
||||
# 整体形状(矩形或者圆形)
|
||||
bgPath = QPainterPath()
|
||||
if self.styleType:
|
||||
bgPath.addRect(QRectF(self.rect()))
|
||||
else:
|
||||
radius = min(self.width(), self.height())
|
||||
bgPath.addRoundedRect(QRectF(self.rect()), radius, radius)
|
||||
|
||||
# 开始画路径
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing, True)
|
||||
# 设置没有画笔
|
||||
painter.setPen(Qt.NoPen)
|
||||
|
||||
# 先整体绘制背景,然后再在背景上方绘制两条波浪
|
||||
painter.save()
|
||||
painter.setBrush(self.backgroundColor)
|
||||
painter.drawPath(bgPath)
|
||||
painter.restore()
|
||||
|
||||
# 波浪1
|
||||
painter.save()
|
||||
painter.setBrush(self.waterColor1)
|
||||
painter.drawPath(waterPath1)
|
||||
painter.restore()
|
||||
|
||||
# 波浪2
|
||||
painter.save()
|
||||
painter.setBrush(self.waterColor2)
|
||||
painter.drawPath(waterPath2)
|
||||
painter.restore()
|
||||
|
||||
# 绘制文字
|
||||
if not self.isTextVisible():
|
||||
return
|
||||
painter.setPen(self.textColor)
|
||||
font = self.font() or QFont()
|
||||
font.setPixelSize(int(min(self.width(), self.height()) / 2))
|
||||
painter.setFont(font)
|
||||
painter.drawText(self.rect(), Qt.AlignCenter, '%d%%' %
|
||||
(self.value() / self.maximum() * 100))
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created on 2018年4月1日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: ProgressBar
|
||||
# description:
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
import math
|
||||
|
||||
from PyQt5.QtCore import QTimer, Qt, QRectF, QSize
|
||||
from PyQt5.QtGui import QPainter, QPainterPath, QColor, QFont
|
||||
from PyQt5.QtWidgets import QProgressBar
|
||||
|
||||
|
||||
class ProgressBar(QProgressBar):
|
||||
|
||||
# 浪高百分比
|
||||
waterHeight = 1
|
||||
# 密度
|
||||
waterDensity = 1
|
||||
# 样式1为矩形, 0为圆形
|
||||
styleType = 1
|
||||
# 文字颜色
|
||||
textColor = Qt.white
|
||||
# 背景颜色
|
||||
backgroundColor = Qt.gray
|
||||
# 波浪颜色1
|
||||
waterColor1 = QColor(33, 178, 148)
|
||||
# 波浪颜色2
|
||||
waterColor2 = QColor(33, 178, 148, 100)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ProgressBar, self).__init__(*args, **kwargs)
|
||||
self._offset = 0
|
||||
# 每隔100ms刷新波浪(模拟波浪动态)
|
||||
self._updateTimer = QTimer(self, timeout=self.update)
|
||||
self._updateTimer.start(100)
|
||||
|
||||
def setRange(self, minValue, maxValue):
|
||||
if minValue == maxValue == 0:
|
||||
return # 不允许设置busy状态
|
||||
super(ProgressBar, self).setRange(minValue, maxValue)
|
||||
|
||||
def setMinimum(self, value):
|
||||
if value == self.maximum() == 0:
|
||||
return # 不允许设置busy状态
|
||||
super(ProgressBar, self).setMinimum(value)
|
||||
|
||||
def setMaximum(self, value):
|
||||
if value == self.minimum() == 0:
|
||||
return # 不允许设置busy状态
|
||||
super(ProgressBar, self).setMaximum(value)
|
||||
|
||||
def setWaterHeight(self, height):
|
||||
"""设置浪高"""
|
||||
self.waterHeight = height
|
||||
self.update()
|
||||
|
||||
def setWaterDensity(self, density):
|
||||
"""设置密度"""
|
||||
self.waterDensity = density
|
||||
self.update()
|
||||
|
||||
def setStyleType(self, style):
|
||||
"""设置类型"""
|
||||
self.styleType = style
|
||||
self.update()
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(100, 100)
|
||||
|
||||
def paintEvent(self, event):
|
||||
if self.minimum() == self.maximum() == 0:
|
||||
return
|
||||
# 正弦曲线公式 y = A * sin(ωx + φ) + k
|
||||
# 当前值所占百分比
|
||||
percent = 1 - (self.value() - self.minimum()) / \
|
||||
(self.maximum() - self.minimum())
|
||||
# w表示周期,6为人为定义
|
||||
w = 6 * self.waterDensity * math.pi / self.width()
|
||||
# A振幅 高度百分比,1/26为人为定义
|
||||
A = self.height() * self.waterHeight * 1 / 26
|
||||
# k 高度百分比
|
||||
k = self.height() * percent
|
||||
|
||||
# 波浪1
|
||||
waterPath1 = QPainterPath()
|
||||
waterPath1.moveTo(0, self.height()) # 起点在左下角
|
||||
# 波浪2
|
||||
waterPath2 = QPainterPath()
|
||||
waterPath2.moveTo(0, self.height()) # 起点在左下角
|
||||
|
||||
# 偏移
|
||||
self._offset += 0.6
|
||||
if self._offset > self.width() / 2:
|
||||
self._offset = 0
|
||||
|
||||
for i in range(self.width() + 1):
|
||||
# 从x轴开始计算y轴点
|
||||
y = A * math.sin(w * i + self._offset) + k
|
||||
waterPath1.lineTo(i, y)
|
||||
|
||||
# 相对第一条需要进行错位
|
||||
y = A * math.sin(w * i + self._offset + self.width() / 2 * A) + k
|
||||
waterPath2.lineTo(i, y)
|
||||
|
||||
# 封闭两条波浪,形成一个 U形 上面加波浪的封闭区间
|
||||
waterPath1.lineTo(self.width(), self.height())
|
||||
waterPath1.lineTo(0, self.height())
|
||||
waterPath2.lineTo(self.width(), self.height())
|
||||
waterPath2.lineTo(0, self.height())
|
||||
|
||||
# 整体形状(矩形或者圆形)
|
||||
bgPath = QPainterPath()
|
||||
if self.styleType:
|
||||
bgPath.addRect(QRectF(self.rect()))
|
||||
else:
|
||||
radius = min(self.width(), self.height())
|
||||
bgPath.addRoundedRect(QRectF(self.rect()), radius, radius)
|
||||
|
||||
# 开始画路径
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing, True)
|
||||
# 设置没有画笔
|
||||
painter.setPen(Qt.NoPen)
|
||||
|
||||
# 先整体绘制背景,然后再在背景上方绘制两条波浪
|
||||
painter.save()
|
||||
painter.setBrush(self.backgroundColor)
|
||||
painter.drawPath(bgPath)
|
||||
painter.restore()
|
||||
|
||||
# 波浪1
|
||||
painter.save()
|
||||
painter.setBrush(self.waterColor1)
|
||||
painter.drawPath(waterPath1)
|
||||
painter.restore()
|
||||
|
||||
# 波浪2
|
||||
painter.save()
|
||||
painter.setBrush(self.waterColor2)
|
||||
painter.drawPath(waterPath2)
|
||||
painter.restore()
|
||||
|
||||
# 绘制文字
|
||||
if not self.isTextVisible():
|
||||
return
|
||||
painter.setPen(self.textColor)
|
||||
font = self.font() or QFont()
|
||||
font.setPixelSize(int(min(self.width(), self.height()) / 2))
|
||||
painter.setFont(font)
|
||||
painter.drawText(self.rect(), Qt.AlignCenter, '%d%%' %
|
||||
(self.value() / self.maximum() * 100))
|
||||
|
|
|
@ -1,125 +1,125 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created on 2018年4月1日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: TestWidget
|
||||
# description:
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
from random import randint
|
||||
|
||||
from PyQt5.Qt import QSpinBox
|
||||
from PyQt5.QtCore import QTimer
|
||||
from PyQt5.QtGui import QPixmap, QIcon
|
||||
from PyQt5.QtWidgets import QWidget, QFormLayout, QRadioButton, QPushButton,\
|
||||
QColorDialog
|
||||
|
||||
from ProgressBar import ProgressBar # @UnresolvedImport
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
self.resize(800, 600)
|
||||
|
||||
self.bar = ProgressBar(self)
|
||||
self.bar.setMinimumSize(400, 400)
|
||||
self.bar.setMaximumSize(400, 400)
|
||||
|
||||
layout = QFormLayout(self)
|
||||
|
||||
layout.addWidget(QRadioButton(
|
||||
'矩形', self, checked=True, clicked=lambda: self.bar.setStyleType(1)))
|
||||
layout.addWidget(
|
||||
QRadioButton('圆形', clicked=lambda: self.bar.setStyleType(0)))
|
||||
layout.addWidget(
|
||||
QPushButton('设置背景颜色', self, clicked=self.chooseBackgroundColor))
|
||||
layout.addWidget(
|
||||
QPushButton('设置文字颜色', self, clicked=self.chooseTextColor))
|
||||
layout.addWidget(
|
||||
QPushButton('设置波浪1颜色', self, clicked=self.chooseWaterColor1))
|
||||
layout.addWidget(
|
||||
QPushButton('设置波浪2颜色', self, clicked=self.chooseWaterColor2))
|
||||
layout.addWidget(
|
||||
QPushButton('设置随机0-100固定值', self, clicked=self.setRandomValue))
|
||||
|
||||
layout.addRow('振幅(浪高)',
|
||||
QSpinBox(self, value=1, valueChanged=self.bar.setWaterHeight))
|
||||
|
||||
layout.addRow('周期(密度)',
|
||||
QSpinBox(self, value=1, valueChanged=self.bar.setWaterDensity))
|
||||
|
||||
layout.addWidget(self.bar)
|
||||
|
||||
# 动态设置进度条的值
|
||||
self._valueTimer = QTimer(self, timeout=self.updateValue)
|
||||
self._valueTimer.start(100)
|
||||
|
||||
def chooseBackgroundColor(self):
|
||||
"""设置背景颜色"""
|
||||
col = QColorDialog.getColor(self.bar.backgroundColor, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.backgroundColor = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def chooseTextColor(self):
|
||||
"""设置文字颜色"""
|
||||
col = QColorDialog.getColor(self.bar.textColor, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.textColor = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def chooseWaterColor1(self):
|
||||
"""设置波浪1颜色"""
|
||||
col = QColorDialog.getColor(self.bar.waterColor1, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.waterColor1 = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def chooseWaterColor2(self):
|
||||
"""设置波浪2颜色"""
|
||||
col = QColorDialog.getColor(self.bar.waterColor2, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.waterColor2 = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def setRandomValue(self):
|
||||
"""设置随机0-100值,并停止自增"""
|
||||
self._valueTimer.stop()
|
||||
self.bar.setValue(randint(0, 100))
|
||||
|
||||
def updateValue(self):
|
||||
value = self.bar.value() + 1
|
||||
if value > self.bar.maximum():
|
||||
value = 0
|
||||
self.bar.setValue(value)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Created on 2018年4月1日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: TestWidget
|
||||
# description:
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
from random import randint
|
||||
|
||||
from PyQt5.Qt import QSpinBox
|
||||
from PyQt5.QtCore import QTimer
|
||||
from PyQt5.QtGui import QPixmap, QIcon
|
||||
from PyQt5.QtWidgets import QWidget, QFormLayout, QRadioButton, QPushButton,\
|
||||
QColorDialog
|
||||
|
||||
from ProgressBar import ProgressBar # @UnresolvedImport
|
||||
|
||||
|
||||
class Window(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Window, self).__init__(*args, **kwargs)
|
||||
self.resize(800, 600)
|
||||
|
||||
self.bar = ProgressBar(self)
|
||||
self.bar.setMinimumSize(400, 400)
|
||||
self.bar.setMaximumSize(400, 400)
|
||||
|
||||
layout = QFormLayout(self)
|
||||
|
||||
layout.addWidget(QRadioButton(
|
||||
'矩形', self, checked=True, clicked=lambda: self.bar.setStyleType(1)))
|
||||
layout.addWidget(
|
||||
QRadioButton('圆形', clicked=lambda: self.bar.setStyleType(0)))
|
||||
layout.addWidget(
|
||||
QPushButton('设置背景颜色', self, clicked=self.chooseBackgroundColor))
|
||||
layout.addWidget(
|
||||
QPushButton('设置文字颜色', self, clicked=self.chooseTextColor))
|
||||
layout.addWidget(
|
||||
QPushButton('设置波浪1颜色', self, clicked=self.chooseWaterColor1))
|
||||
layout.addWidget(
|
||||
QPushButton('设置波浪2颜色', self, clicked=self.chooseWaterColor2))
|
||||
layout.addWidget(
|
||||
QPushButton('设置随机0-100固定值', self, clicked=self.setRandomValue))
|
||||
|
||||
layout.addRow('振幅(浪高)',
|
||||
QSpinBox(self, value=1, valueChanged=self.bar.setWaterHeight))
|
||||
|
||||
layout.addRow('周期(密度)',
|
||||
QSpinBox(self, value=1, valueChanged=self.bar.setWaterDensity))
|
||||
|
||||
layout.addWidget(self.bar)
|
||||
|
||||
# 动态设置进度条的值
|
||||
self._valueTimer = QTimer(self, timeout=self.updateValue)
|
||||
self._valueTimer.start(100)
|
||||
|
||||
def chooseBackgroundColor(self):
|
||||
"""设置背景颜色"""
|
||||
col = QColorDialog.getColor(self.bar.backgroundColor, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.backgroundColor = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def chooseTextColor(self):
|
||||
"""设置文字颜色"""
|
||||
col = QColorDialog.getColor(self.bar.textColor, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.textColor = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def chooseWaterColor1(self):
|
||||
"""设置波浪1颜色"""
|
||||
col = QColorDialog.getColor(self.bar.waterColor1, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.waterColor1 = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def chooseWaterColor2(self):
|
||||
"""设置波浪2颜色"""
|
||||
col = QColorDialog.getColor(self.bar.waterColor2, self)
|
||||
if not col.isValid():
|
||||
return
|
||||
self.bar.waterColor2 = col
|
||||
pix = QPixmap(16, 16)
|
||||
pix.fill(col)
|
||||
self.sender().setIcon(QIcon(pix))
|
||||
|
||||
def setRandomValue(self):
|
||||
"""设置随机0-100值,并停止自增"""
|
||||
self._valueTimer.stop()
|
||||
self.bar.setValue(randint(0, 100))
|
||||
|
||||
def updateValue(self):
|
||||
value = self.bar.value() + 1
|
||||
if value > self.bar.maximum():
|
||||
value = 0
|
||||
self.bar.setValue(value)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
17
界面美化/边框动画阴影/AnimationShadowEffect.py
Normal file
17
界面美化/边框动画阴影/AnimationShadowEffect.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年9月25日
|
||||
@author: Irony
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: AnimationShadowEffect
|
||||
@description: 边框动画阴影动画
|
||||
"""
|
||||
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年3月31日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: AutoRestart
|
||||
@description:
|
||||
|
|
|
@ -1,95 +1,95 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月1日
|
||||
@author: Irony
|
||||
@site: https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: WeltHideWindow
|
||||
@description:
|
||||
"""
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton
|
||||
|
||||
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class WeltHideWindow(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(WeltHideWindow, self).__init__(*args, **kwargs)
|
||||
self.setWindowFlag(Qt.FramelessWindowHint, True)
|
||||
self.resize(800, 600)
|
||||
self._width = QApplication.desktop().availableGeometry(self).width()
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(QPushButton("关闭窗口", self, clicked=self.close))
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
'''鼠标按下事件,需要记录下坐标self._pos 和 是否可移动self._canMove'''
|
||||
super(WeltHideWindow, self).mousePressEvent(event)
|
||||
if event.button() == Qt.LeftButton:
|
||||
self._pos = event.globalPos() - self.pos()
|
||||
# 当窗口最大化或者全屏时不可移动
|
||||
self._canMove = not self.isMaximized() or not self.isFullScreen()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
'''鼠标移动事件,动态调整窗口位置'''
|
||||
super(WeltHideWindow, self).mouseMoveEvent(event)
|
||||
if event.buttons() == Qt.LeftButton and self._canMove:
|
||||
self.move(event.globalPos() - self._pos)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
'''鼠标弹起事件,这个时候需要判断窗口的左边是否符合贴到左边,顶部,右边一半'''
|
||||
super(WeltHideWindow, self).mouseReleaseEvent(event)
|
||||
self._canMove = False
|
||||
pos = self.pos()
|
||||
x = pos.x()
|
||||
y = pos.y()
|
||||
if x < 0:
|
||||
# 隐藏到左边
|
||||
return self.move(1 - self.width(), y)
|
||||
if y < 0:
|
||||
# 隐藏到顶部
|
||||
return self.move(x, 1 - self.height())
|
||||
if x > self._width - self.width() / 2: # 窗口进入右边一半距离
|
||||
# 隐藏到右边
|
||||
return self.move(self._width - 1, y)
|
||||
|
||||
def enterEvent(self, event):
|
||||
'''鼠标进入窗口事件,用于弹出显示窗口'''
|
||||
super(WeltHideWindow, self).enterEvent(event)
|
||||
pos = self.pos()
|
||||
x = pos.x()
|
||||
y = pos.y()
|
||||
if x < 0:
|
||||
return self.move(0, y)
|
||||
if y < 0:
|
||||
return self.move(x, 0)
|
||||
if x > self._width - self.width() / 2:
|
||||
return self.move(self._width - self.width(), y)
|
||||
|
||||
def leaveEvent(self, event):
|
||||
'''鼠标离开事件,如果原先窗口已经隐藏,并暂时显示,此时离开后需要再次隐藏'''
|
||||
super(WeltHideWindow, self).leaveEvent(event)
|
||||
pos = self.pos()
|
||||
x = pos.x()
|
||||
y = pos.y()
|
||||
if x == 0:
|
||||
return self.move(1 - self.width(), y)
|
||||
if y == 0:
|
||||
return self.move(x, 1 - self.height())
|
||||
if x == self._width - self.width():
|
||||
return self.move(self._width - 1, y)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = WeltHideWindow()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Created on 2018年3月1日
|
||||
@author: Irony
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: WeltHideWindow
|
||||
@description:
|
||||
"""
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton
|
||||
|
||||
|
||||
__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com'
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class WeltHideWindow(QWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(WeltHideWindow, self).__init__(*args, **kwargs)
|
||||
self.setWindowFlag(Qt.FramelessWindowHint, True)
|
||||
self.resize(800, 600)
|
||||
self._width = QApplication.desktop().availableGeometry(self).width()
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(QPushButton("关闭窗口", self, clicked=self.close))
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
'''鼠标按下事件,需要记录下坐标self._pos 和 是否可移动self._canMove'''
|
||||
super(WeltHideWindow, self).mousePressEvent(event)
|
||||
if event.button() == Qt.LeftButton:
|
||||
self._pos = event.globalPos() - self.pos()
|
||||
# 当窗口最大化或者全屏时不可移动
|
||||
self._canMove = not self.isMaximized() or not self.isFullScreen()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
'''鼠标移动事件,动态调整窗口位置'''
|
||||
super(WeltHideWindow, self).mouseMoveEvent(event)
|
||||
if event.buttons() == Qt.LeftButton and self._canMove:
|
||||
self.move(event.globalPos() - self._pos)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
'''鼠标弹起事件,这个时候需要判断窗口的左边是否符合贴到左边,顶部,右边一半'''
|
||||
super(WeltHideWindow, self).mouseReleaseEvent(event)
|
||||
self._canMove = False
|
||||
pos = self.pos()
|
||||
x = pos.x()
|
||||
y = pos.y()
|
||||
if x < 0:
|
||||
# 隐藏到左边
|
||||
return self.move(1 - self.width(), y)
|
||||
if y < 0:
|
||||
# 隐藏到顶部
|
||||
return self.move(x, 1 - self.height())
|
||||
if x > self._width - self.width() / 2: # 窗口进入右边一半距离
|
||||
# 隐藏到右边
|
||||
return self.move(self._width - 1, y)
|
||||
|
||||
def enterEvent(self, event):
|
||||
'''鼠标进入窗口事件,用于弹出显示窗口'''
|
||||
super(WeltHideWindow, self).enterEvent(event)
|
||||
pos = self.pos()
|
||||
x = pos.x()
|
||||
y = pos.y()
|
||||
if x < 0:
|
||||
return self.move(0, y)
|
||||
if y < 0:
|
||||
return self.move(x, 0)
|
||||
if x > self._width - self.width() / 2:
|
||||
return self.move(self._width - self.width(), y)
|
||||
|
||||
def leaveEvent(self, event):
|
||||
'''鼠标离开事件,如果原先窗口已经隐藏,并暂时显示,此时离开后需要再次隐藏'''
|
||||
super(WeltHideWindow, self).leaveEvent(event)
|
||||
pos = self.pos()
|
||||
x = pos.x()
|
||||
y = pos.y()
|
||||
if x == 0:
|
||||
return self.move(1 - self.width(), y)
|
||||
if y == 0:
|
||||
return self.move(x, 1 - self.height())
|
||||
if x == self._width - self.width():
|
||||
return self.move(self._width - 1, y)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = WeltHideWindow()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,162 +1,162 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import QTimer
|
||||
from PyQt5.QtGui import QPixmap, QImage
|
||||
from PyQt5.QtNetwork import QTcpSocket
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
|
||||
# Created on 2018年4月18日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: ControlCar
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class ControlCar(QWidget):
|
||||
|
||||
HOST = '127.0.0.1'
|
||||
PORT = 8888
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ControlCar, self).__init__(*args, **kwargs)
|
||||
self._connCar = None
|
||||
# 加载UI文件
|
||||
uic.loadUi('carui.ui', self)
|
||||
self.resize(800, 600)
|
||||
# 绑定连接按钮信号
|
||||
self.buttonConnect.clicked.connect(self.doConnect)
|
||||
# 绑定拉动信号
|
||||
self.sliderForward.valueChanged.connect(self.doForward)
|
||||
self.sliderBackward.valueChanged.connect(self.doBackward)
|
||||
self.sliderLeft.valueChanged.connect(self.doLeft)
|
||||
self.sliderRight.valueChanged.connect(self.doRight)
|
||||
# 设置初始拉动条不能用
|
||||
self.sliderForward.setEnabled(False)
|
||||
self.sliderBackward.setEnabled(False)
|
||||
self.sliderLeft.setEnabled(False)
|
||||
self.sliderRight.setEnabled(False)
|
||||
|
||||
# 定时器定时向图片服务器发送请求
|
||||
self._timer = QTimer(self, timeout=self.doGetImage)
|
||||
|
||||
def _clearConn(self):
|
||||
"""清理连接"""
|
||||
if self._connCar:
|
||||
self._connCar.close()
|
||||
self._connCar.deleteLater()
|
||||
del self._connCar
|
||||
self._connCar = None
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""窗口关闭事件"""
|
||||
self._timer.stop()
|
||||
self._clearConn()
|
||||
super(ControlCar, self).closeEvent(event)
|
||||
|
||||
def doConnect(self):
|
||||
"""连接服务器"""
|
||||
self.buttonConnect.setEnabled(False)
|
||||
self._timer.stop()
|
||||
self._clearConn()
|
||||
self.browserResult.append('正在连接服务器')
|
||||
# 连接控制小车的服务器
|
||||
self._connCar = QTcpSocket(self)
|
||||
self._connCar.connected.connect(self.onConnected) # 绑定连接成功信号
|
||||
self._connCar.disconnected.connect(self.onDisconnected) # 绑定连接丢失信号
|
||||
self._connCar.readyRead.connect(self.onReadyRead) # 准备读取信号
|
||||
self._connCar.error.connect(self.onError) # 连接错误信号
|
||||
self._connCar.connectToHost(self.HOST, self.PORT)
|
||||
|
||||
def onConnected(self):
|
||||
"""连接成功"""
|
||||
self.buttonConnect.setEnabled(False) # 按钮不可用
|
||||
# 设置初始拉动条可用
|
||||
self.sliderForward.setEnabled(True)
|
||||
self.sliderBackward.setEnabled(True)
|
||||
self.sliderLeft.setEnabled(True)
|
||||
self.sliderRight.setEnabled(True)
|
||||
self.browserResult.append('连接成功') # 记录日志
|
||||
# 开启获取摄像头图片定时器
|
||||
self._timer.start(200)
|
||||
|
||||
def onDisconnected(self):
|
||||
"""丢失连接"""
|
||||
self._timer.stop()
|
||||
self.buttonConnect.setEnabled(True) # 按钮可用
|
||||
# 设置初始拉动条不可用
|
||||
self.sliderForward.setEnabled(False)
|
||||
self.sliderBackward.setEnabled(False)
|
||||
self.sliderLeft.setEnabled(False)
|
||||
self.sliderRight.setEnabled(False)
|
||||
# 把数据设置为最小值
|
||||
self.sliderForward.setValue(self.sliderForward.minimum())
|
||||
self.sliderBackward.setValue(self.sliderBackward.minimum())
|
||||
self.sliderLeft.setValue(self.sliderLeft.minimum())
|
||||
self.sliderRight.setValue(self.sliderRight.minimum())
|
||||
self.browserResult.append('丢失连接') # 记录日志
|
||||
|
||||
def onReadyRead(self):
|
||||
"""接收到数据"""
|
||||
while self._connCar.bytesAvailable() > 0:
|
||||
try:
|
||||
data = self._connCar.readAll().data()
|
||||
if data and data.find(b'JFIF') > -1:
|
||||
self.qlabel.setPixmap( # 图片
|
||||
QPixmap.fromImage(QImage.fromData(data)))
|
||||
else:
|
||||
self.browserResult.append('接收到数据: ' + data.decode())
|
||||
except Exception as e:
|
||||
self.browserResult.append('解析数据错误: ' + str(e))
|
||||
|
||||
def onError(self, _):
|
||||
"""连接报错"""
|
||||
self._timer.stop()
|
||||
self.buttonConnect.setEnabled(True) # 按钮可用
|
||||
self.browserResult.append('连接服务器错误: ' + self._connCar.errorString())
|
||||
|
||||
def doForward(self, value):
|
||||
"""向前"""
|
||||
# 发送的内容为 F:1 类似的
|
||||
self.sendData('F:', str(value))
|
||||
|
||||
def doBackward(self, value):
|
||||
"""向后"""
|
||||
# 发送的内容为 B:1 类似的
|
||||
self.sendData('B:', str(value))
|
||||
|
||||
def doLeft(self, value):
|
||||
"""向左"""
|
||||
# 发送的内容为 L:1 类似的
|
||||
self.sendData('L:', str(value))
|
||||
|
||||
def doRight(self, value):
|
||||
"""向右"""
|
||||
# 发送的内容为 R:1 类似的
|
||||
self.sendData('R:', str(value))
|
||||
|
||||
def doGetImage(self):
|
||||
# 请求图片
|
||||
self.sendData('getimage', '')
|
||||
|
||||
def sendData(self, ver, data):
|
||||
"""发送数据"""
|
||||
if not self._connCar or not self._connCar.isWritable():
|
||||
return self.browserResult.append('服务器未连接或不可写入数据')
|
||||
self._connCar.write(ver.encode() + str(data).encode() + b'\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = ControlCar()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt5 import uic
|
||||
from PyQt5.QtCore import QTimer
|
||||
from PyQt5.QtGui import QPixmap, QImage
|
||||
from PyQt5.QtNetwork import QTcpSocket
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
|
||||
# Created on 2018年4月18日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: ControlCar
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
class ControlCar(QWidget):
|
||||
|
||||
HOST = '127.0.0.1'
|
||||
PORT = 8888
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ControlCar, self).__init__(*args, **kwargs)
|
||||
self._connCar = None
|
||||
# 加载UI文件
|
||||
uic.loadUi('carui.ui', self)
|
||||
self.resize(800, 600)
|
||||
# 绑定连接按钮信号
|
||||
self.buttonConnect.clicked.connect(self.doConnect)
|
||||
# 绑定拉动信号
|
||||
self.sliderForward.valueChanged.connect(self.doForward)
|
||||
self.sliderBackward.valueChanged.connect(self.doBackward)
|
||||
self.sliderLeft.valueChanged.connect(self.doLeft)
|
||||
self.sliderRight.valueChanged.connect(self.doRight)
|
||||
# 设置初始拉动条不能用
|
||||
self.sliderForward.setEnabled(False)
|
||||
self.sliderBackward.setEnabled(False)
|
||||
self.sliderLeft.setEnabled(False)
|
||||
self.sliderRight.setEnabled(False)
|
||||
|
||||
# 定时器定时向图片服务器发送请求
|
||||
self._timer = QTimer(self, timeout=self.doGetImage)
|
||||
|
||||
def _clearConn(self):
|
||||
"""清理连接"""
|
||||
if self._connCar:
|
||||
self._connCar.close()
|
||||
self._connCar.deleteLater()
|
||||
del self._connCar
|
||||
self._connCar = None
|
||||
|
||||
def closeEvent(self, event):
|
||||
"""窗口关闭事件"""
|
||||
self._timer.stop()
|
||||
self._clearConn()
|
||||
super(ControlCar, self).closeEvent(event)
|
||||
|
||||
def doConnect(self):
|
||||
"""连接服务器"""
|
||||
self.buttonConnect.setEnabled(False)
|
||||
self._timer.stop()
|
||||
self._clearConn()
|
||||
self.browserResult.append('正在连接服务器')
|
||||
# 连接控制小车的服务器
|
||||
self._connCar = QTcpSocket(self)
|
||||
self._connCar.connected.connect(self.onConnected) # 绑定连接成功信号
|
||||
self._connCar.disconnected.connect(self.onDisconnected) # 绑定连接丢失信号
|
||||
self._connCar.readyRead.connect(self.onReadyRead) # 准备读取信号
|
||||
self._connCar.error.connect(self.onError) # 连接错误信号
|
||||
self._connCar.connectToHost(self.HOST, self.PORT)
|
||||
|
||||
def onConnected(self):
|
||||
"""连接成功"""
|
||||
self.buttonConnect.setEnabled(False) # 按钮不可用
|
||||
# 设置初始拉动条可用
|
||||
self.sliderForward.setEnabled(True)
|
||||
self.sliderBackward.setEnabled(True)
|
||||
self.sliderLeft.setEnabled(True)
|
||||
self.sliderRight.setEnabled(True)
|
||||
self.browserResult.append('连接成功') # 记录日志
|
||||
# 开启获取摄像头图片定时器
|
||||
self._timer.start(200)
|
||||
|
||||
def onDisconnected(self):
|
||||
"""丢失连接"""
|
||||
self._timer.stop()
|
||||
self.buttonConnect.setEnabled(True) # 按钮可用
|
||||
# 设置初始拉动条不可用
|
||||
self.sliderForward.setEnabled(False)
|
||||
self.sliderBackward.setEnabled(False)
|
||||
self.sliderLeft.setEnabled(False)
|
||||
self.sliderRight.setEnabled(False)
|
||||
# 把数据设置为最小值
|
||||
self.sliderForward.setValue(self.sliderForward.minimum())
|
||||
self.sliderBackward.setValue(self.sliderBackward.minimum())
|
||||
self.sliderLeft.setValue(self.sliderLeft.minimum())
|
||||
self.sliderRight.setValue(self.sliderRight.minimum())
|
||||
self.browserResult.append('丢失连接') # 记录日志
|
||||
|
||||
def onReadyRead(self):
|
||||
"""接收到数据"""
|
||||
while self._connCar.bytesAvailable() > 0:
|
||||
try:
|
||||
data = self._connCar.readAll().data()
|
||||
if data and data.find(b'JFIF') > -1:
|
||||
self.qlabel.setPixmap( # 图片
|
||||
QPixmap.fromImage(QImage.fromData(data)))
|
||||
else:
|
||||
self.browserResult.append('接收到数据: ' + data.decode())
|
||||
except Exception as e:
|
||||
self.browserResult.append('解析数据错误: ' + str(e))
|
||||
|
||||
def onError(self, _):
|
||||
"""连接报错"""
|
||||
self._timer.stop()
|
||||
self.buttonConnect.setEnabled(True) # 按钮可用
|
||||
self.browserResult.append('连接服务器错误: ' + self._connCar.errorString())
|
||||
|
||||
def doForward(self, value):
|
||||
"""向前"""
|
||||
# 发送的内容为 F:1 类似的
|
||||
self.sendData('F:', str(value))
|
||||
|
||||
def doBackward(self, value):
|
||||
"""向后"""
|
||||
# 发送的内容为 B:1 类似的
|
||||
self.sendData('B:', str(value))
|
||||
|
||||
def doLeft(self, value):
|
||||
"""向左"""
|
||||
# 发送的内容为 L:1 类似的
|
||||
self.sendData('L:', str(value))
|
||||
|
||||
def doRight(self, value):
|
||||
"""向右"""
|
||||
# 发送的内容为 R:1 类似的
|
||||
self.sendData('R:', str(value))
|
||||
|
||||
def doGetImage(self):
|
||||
# 请求图片
|
||||
self.sendData('getimage', '')
|
||||
|
||||
def sendData(self, ver, data):
|
||||
"""发送数据"""
|
||||
if not self._connCar or not self._connCar.isWritable():
|
||||
return self.browserResult.append('服务器未连接或不可写入数据')
|
||||
self._connCar.write(ver.encode() + str(data).encode() + b'\n')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = ControlCar()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,161 +1,161 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import atexit
|
||||
import logging
|
||||
|
||||
import cv2
|
||||
from tornado import gen
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.iostream import StreamClosedError
|
||||
from tornado.options import options, define
|
||||
from tornado.tcpserver import TCPServer
|
||||
|
||||
|
||||
try:
|
||||
import RPi.GPIO as GPIO # @UnusedImport @UnresolvedImport
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# Created on 2018年4月18日
|
||||
# author: Irony
|
||||
# site: https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: server
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
define("port", default=8888, help="TCP port to listen on")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# SIZE = (640, 480) # 分辨率
|
||||
# FPS = 24
|
||||
SIZE = (100, 80) # 分辨率
|
||||
FPS = 5
|
||||
PARAM = [int(cv2.IMWRITE_JPEG_QUALITY), FPS]
|
||||
|
||||
|
||||
class EchoServer(TCPServer):
|
||||
|
||||
IMAGE = None
|
||||
|
||||
def __init__(self, cap, *args, **kwargs):
|
||||
super(EchoServer, self).__init__(*args, **kwargs)
|
||||
self.cap = cap
|
||||
self.init()
|
||||
|
||||
def init(self):
|
||||
"""初始化管脚"""
|
||||
try:
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(17, GPIO.OUT)
|
||||
GPIO.setup(27, GPIO.OUT)
|
||||
GPIO.setup(22, GPIO.OUT)
|
||||
GPIO.setup(18, GPIO.OUT, initial=False)
|
||||
self.duo = GPIO.PWM(18, 300)
|
||||
self.p1 = GPIO.PWM(17, 10000)
|
||||
self.p2 = GPIO.PWM(27, 10000)
|
||||
en = GPIO.output(22, False) # @UnusedVariable
|
||||
self.p1.start(0)
|
||||
self.p2.start(0)
|
||||
self.duo.start(0)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def forward(self, a):
|
||||
try:
|
||||
k = a / 100
|
||||
print("k=%lf" % k)
|
||||
self.p1.ChangeDutyCycle(k)
|
||||
self.p2.ChangeDutyCycle(0)
|
||||
except:
|
||||
pass
|
||||
|
||||
def back(self, a):
|
||||
try:
|
||||
k = a / 100
|
||||
print("k1=%lf" % k)
|
||||
self.p1.ChangeDutyCycle(0)
|
||||
self.p2.ChangeDutyCycle(k)
|
||||
except:
|
||||
pass
|
||||
|
||||
def lr(self, a):
|
||||
try:
|
||||
self.duo.ChangeDutyCycle(a) # 左满舵a=32,右满舵a=52,中值a=42,则a值取32至52
|
||||
except:
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
try:
|
||||
self.p1.ChangeDutyCycle(0)
|
||||
self.p2.ChangeDutyCycle(0)
|
||||
self.duo.ChangeDutyCycle(42)
|
||||
except:
|
||||
pass
|
||||
|
||||
@gen.coroutine
|
||||
def handle_stream(self, stream, address):
|
||||
while True:
|
||||
try:
|
||||
data = yield stream.read_until(b"\n")
|
||||
# logger.info("Received bytes: %s", data)
|
||||
if not data.endswith(b"\n"):
|
||||
data = data + b"\n"
|
||||
if data == b'getimage\n' and self.cap and self.cap.isOpened():
|
||||
_, frame = self.cap.read() # 读取一帧图片
|
||||
if str(type(frame)).find('ndarray') > -1:
|
||||
frame = cv2.resize(frame, SIZE)
|
||||
ret, data = cv2.imencode('.jpg', frame, PARAM)
|
||||
if ret:
|
||||
yield stream.write(data.tostring()) # 发送图片
|
||||
else:
|
||||
try:
|
||||
ver, value = data.decode().split(':')
|
||||
if ver == 'L':
|
||||
self.lr(int(value))
|
||||
elif ver == 'R':
|
||||
self.lr(int(value))
|
||||
elif ver == 'F':
|
||||
self.forward(int(value))
|
||||
elif ver == 'B':
|
||||
self.back(int(value))
|
||||
yield stream.write(data)
|
||||
except:
|
||||
yield stream.write(b'\n')
|
||||
except StreamClosedError:
|
||||
logger.warning("Lost client at host %s", address[0])
|
||||
break
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def start(cap):
|
||||
"""启动服务器"""
|
||||
options.parse_command_line()
|
||||
server = EchoServer(cap)
|
||||
server.listen(options.port)
|
||||
logger.info("Listening on TCP port %d", options.port)
|
||||
IOLoop.current().start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cap = None
|
||||
try:
|
||||
cap = cv2.VideoCapture(0) # 开启摄像头
|
||||
atexit.register(lambda: cap.release())
|
||||
atexit.register(lambda: GPIO.cleanup())
|
||||
start(cap)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
if cap:
|
||||
cap.release()
|
||||
try:
|
||||
GPIO.cleanup()
|
||||
except:
|
||||
pass
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import atexit
|
||||
import logging
|
||||
|
||||
import cv2
|
||||
from tornado import gen
|
||||
from tornado.ioloop import IOLoop
|
||||
from tornado.iostream import StreamClosedError
|
||||
from tornado.options import options, define
|
||||
from tornado.tcpserver import TCPServer
|
||||
|
||||
|
||||
try:
|
||||
import RPi.GPIO as GPIO # @UnusedImport @UnresolvedImport
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# Created on 2018年4月18日
|
||||
# author: Irony
|
||||
# site: https://pyqt5.com, https://github.com/892768447
|
||||
# email: 892768447@qq.com
|
||||
# file: server
|
||||
# description:
|
||||
__Author__ = """By: Irony
|
||||
QQ: 892768447
|
||||
Email: 892768447@qq.com"""
|
||||
__Copyright__ = 'Copyright (c) 2018 Irony'
|
||||
__Version__ = 1.0
|
||||
|
||||
|
||||
define("port", default=8888, help="TCP port to listen on")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# SIZE = (640, 480) # 分辨率
|
||||
# FPS = 24
|
||||
SIZE = (100, 80) # 分辨率
|
||||
FPS = 5
|
||||
PARAM = [int(cv2.IMWRITE_JPEG_QUALITY), FPS]
|
||||
|
||||
|
||||
class EchoServer(TCPServer):
|
||||
|
||||
IMAGE = None
|
||||
|
||||
def __init__(self, cap, *args, **kwargs):
|
||||
super(EchoServer, self).__init__(*args, **kwargs)
|
||||
self.cap = cap
|
||||
self.init()
|
||||
|
||||
def init(self):
|
||||
"""初始化管脚"""
|
||||
try:
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(17, GPIO.OUT)
|
||||
GPIO.setup(27, GPIO.OUT)
|
||||
GPIO.setup(22, GPIO.OUT)
|
||||
GPIO.setup(18, GPIO.OUT, initial=False)
|
||||
self.duo = GPIO.PWM(18, 300)
|
||||
self.p1 = GPIO.PWM(17, 10000)
|
||||
self.p2 = GPIO.PWM(27, 10000)
|
||||
en = GPIO.output(22, False) # @UnusedVariable
|
||||
self.p1.start(0)
|
||||
self.p2.start(0)
|
||||
self.duo.start(0)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def forward(self, a):
|
||||
try:
|
||||
k = a / 100
|
||||
print("k=%lf" % k)
|
||||
self.p1.ChangeDutyCycle(k)
|
||||
self.p2.ChangeDutyCycle(0)
|
||||
except:
|
||||
pass
|
||||
|
||||
def back(self, a):
|
||||
try:
|
||||
k = a / 100
|
||||
print("k1=%lf" % k)
|
||||
self.p1.ChangeDutyCycle(0)
|
||||
self.p2.ChangeDutyCycle(k)
|
||||
except:
|
||||
pass
|
||||
|
||||
def lr(self, a):
|
||||
try:
|
||||
self.duo.ChangeDutyCycle(a) # 左满舵a=32,右满舵a=52,中值a=42,则a值取32至52
|
||||
except:
|
||||
pass
|
||||
|
||||
def stop(self):
|
||||
try:
|
||||
self.p1.ChangeDutyCycle(0)
|
||||
self.p2.ChangeDutyCycle(0)
|
||||
self.duo.ChangeDutyCycle(42)
|
||||
except:
|
||||
pass
|
||||
|
||||
@gen.coroutine
|
||||
def handle_stream(self, stream, address):
|
||||
while True:
|
||||
try:
|
||||
data = yield stream.read_until(b"\n")
|
||||
# logger.info("Received bytes: %s", data)
|
||||
if not data.endswith(b"\n"):
|
||||
data = data + b"\n"
|
||||
if data == b'getimage\n' and self.cap and self.cap.isOpened():
|
||||
_, frame = self.cap.read() # 读取一帧图片
|
||||
if str(type(frame)).find('ndarray') > -1:
|
||||
frame = cv2.resize(frame, SIZE)
|
||||
ret, data = cv2.imencode('.jpg', frame, PARAM)
|
||||
if ret:
|
||||
yield stream.write(data.tostring()) # 发送图片
|
||||
else:
|
||||
try:
|
||||
ver, value = data.decode().split(':')
|
||||
if ver == 'L':
|
||||
self.lr(int(value))
|
||||
elif ver == 'R':
|
||||
self.lr(int(value))
|
||||
elif ver == 'F':
|
||||
self.forward(int(value))
|
||||
elif ver == 'B':
|
||||
self.back(int(value))
|
||||
yield stream.write(data)
|
||||
except:
|
||||
yield stream.write(b'\n')
|
||||
except StreamClosedError:
|
||||
logger.warning("Lost client at host %s", address[0])
|
||||
break
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
def start(cap):
|
||||
"""启动服务器"""
|
||||
options.parse_command_line()
|
||||
server = EchoServer(cap)
|
||||
server.listen(options.port)
|
||||
logger.info("Listening on TCP port %d", options.port)
|
||||
IOLoop.current().start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
cap = None
|
||||
try:
|
||||
cap = cv2.VideoCapture(0) # 开启摄像头
|
||||
atexit.register(lambda: cap.release())
|
||||
atexit.register(lambda: GPIO.cleanup())
|
||||
start(cap)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
if cap:
|
||||
cap.release()
|
||||
try:
|
||||
GPIO.cleanup()
|
||||
except:
|
||||
pass
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年5月7日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 自动更新.mylibs.testlibs
|
||||
@description:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
'''
|
||||
Created on 2017年5月7日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 自动更新.test
|
||||
@description:
|
||||
|
|
|
@ -1,65 +1,65 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月12日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@email: 892768447@qq.com
|
||||
@file: 自定义属性测试
|
||||
@description:
|
||||
'''
|
||||
from random import randint
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal
|
||||
from PyQt5.QtWidgets import QPushButton
|
||||
|
||||
|
||||
__version__ = "0.0.1"
|
||||
|
||||
|
||||
class Window(QPushButton):
|
||||
|
||||
bgChanged = pyqtSignal(str, str)
|
||||
|
||||
def __init__(self):
|
||||
super(Window, self).__init__("QSS")
|
||||
self._textColor = ""
|
||||
self._backgroundColor = ""
|
||||
self.clicked.connect(self.onClick)
|
||||
self.bgChanged.connect(lambda old, new: print(
|
||||
"old bg color", old, "new bg color", new))
|
||||
|
||||
def onClick(self):
|
||||
print("textColor", self._textColor)
|
||||
self.setStyleSheet("qproperty-backgroundColor: %s;" % randint(1, 1000))
|
||||
|
||||
# 方式一、个人觉得比较简洁
|
||||
@pyqtProperty(str, notify=bgChanged)
|
||||
def backgroundColor(self):
|
||||
return self._backgroundColor
|
||||
|
||||
@backgroundColor.setter
|
||||
def backgroundColor(self, color):
|
||||
self.bgChanged.emit(self._backgroundColor, color)
|
||||
self._backgroundColor = color
|
||||
|
||||
# 方式二
|
||||
def getTextColor(self):
|
||||
return self._textColor
|
||||
|
||||
def setTextColor(self, c):
|
||||
self._textColor = c
|
||||
|
||||
textColor = pyqtProperty(str, getTextColor, setTextColor)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.setStyleSheet(
|
||||
"qproperty-textColor: white;qproperty-backgroundColor: red;")
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月12日
|
||||
@author: Irony."[讽刺]
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: 自定义属性测试
|
||||
@description:
|
||||
'''
|
||||
from random import randint
|
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal
|
||||
from PyQt5.QtWidgets import QPushButton
|
||||
|
||||
|
||||
__version__ = "0.0.1"
|
||||
|
||||
|
||||
class Window(QPushButton):
|
||||
|
||||
bgChanged = pyqtSignal(str, str)
|
||||
|
||||
def __init__(self):
|
||||
super(Window, self).__init__("QSS")
|
||||
self._textColor = ""
|
||||
self._backgroundColor = ""
|
||||
self.clicked.connect(self.onClick)
|
||||
self.bgChanged.connect(lambda old, new: print(
|
||||
"old bg color", old, "new bg color", new))
|
||||
|
||||
def onClick(self):
|
||||
print("textColor", self._textColor)
|
||||
self.setStyleSheet("qproperty-backgroundColor: %s;" % randint(1, 1000))
|
||||
|
||||
# 方式一、个人觉得比较简洁
|
||||
@pyqtProperty(str, notify=bgChanged)
|
||||
def backgroundColor(self):
|
||||
return self._backgroundColor
|
||||
|
||||
@backgroundColor.setter
|
||||
def backgroundColor(self, color):
|
||||
self.bgChanged.emit(self._backgroundColor, color)
|
||||
self._backgroundColor = color
|
||||
|
||||
# 方式二
|
||||
def getTextColor(self):
|
||||
return self._textColor
|
||||
|
||||
def setTextColor(self, c):
|
||||
self._textColor = c
|
||||
|
||||
textColor = pyqtProperty(str, getTextColor, setTextColor)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
app = QApplication(sys.argv)
|
||||
w = Window()
|
||||
w.setStyleSheet(
|
||||
"qproperty-textColor: white;qproperty-backgroundColor: red;")
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,107 +1,107 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月6日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@email: 892768447@qq.com
|
||||
@file: TableView
|
||||
@description:
|
||||
'''
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt5.QtWidgets import QTableView, QApplication, QAction, QMessageBox
|
||||
|
||||
|
||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
||||
__Version__ = "Version 1.0"
|
||||
|
||||
|
||||
class TableView(QTableView):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(TableView, self).__init__(parent)
|
||||
self.resize(800, 600)
|
||||
self.setContextMenuPolicy(Qt.ActionsContextMenu) # 右键菜单
|
||||
self.setEditTriggers(self.NoEditTriggers) # 禁止编辑
|
||||
self.doubleClicked.connect(self.onDoubleClick)
|
||||
self.addAction(QAction("复制", self, triggered=self.copyData))
|
||||
self.myModel = QStandardItemModel() # model
|
||||
self.initHeader() # 初始化表头
|
||||
self.setModel(self.myModel)
|
||||
self.initData() # 初始化模拟数据
|
||||
|
||||
def onDoubleClick(self, index):
|
||||
print(index.row(), index.column(), index.data())
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
super(TableView, self).keyPressEvent(event)
|
||||
# Ctrl + C
|
||||
if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_C:
|
||||
self.copyData()
|
||||
|
||||
def copyData(self):
|
||||
count = len(self.selectedIndexes())
|
||||
if count == 0:
|
||||
return
|
||||
if count == 1: # 只复制了一个
|
||||
QApplication.clipboard().setText(
|
||||
self.selectedIndexes()[0].data()) # 复制到剪贴板中
|
||||
QMessageBox.information(self, "提示", "已复制一个数据")
|
||||
return
|
||||
rows = set()
|
||||
cols = set()
|
||||
for index in self.selectedIndexes(): # 得到所有选择的
|
||||
rows.add(index.row())
|
||||
cols.add(index.column())
|
||||
# print(index.row(),index.column(),index.data())
|
||||
if len(rows) == 1: # 一行
|
||||
QApplication.clipboard().setText("\t".join(
|
||||
[index.data() for index in self.selectedIndexes()])) # 复制
|
||||
QMessageBox.information(self, "提示", "已复制一行数据")
|
||||
return
|
||||
if len(cols) == 1: # 一列
|
||||
QApplication.clipboard().setText("\r\n".join(
|
||||
[index.data() for index in self.selectedIndexes()])) # 复制
|
||||
QMessageBox.information(self, "提示", "已复制一列数据")
|
||||
return
|
||||
mirow, marow = min(rows), max(rows) # 最(少/多)行
|
||||
micol, macol = min(cols), max(cols) # 最(少/多)列
|
||||
print(mirow, marow, micol, macol)
|
||||
arrays = [
|
||||
[
|
||||
"" for _ in range(macol - micol + 1)
|
||||
] for _ in range(marow - mirow + 1)
|
||||
] # 创建二维数组(并排除前面的空行和空列)
|
||||
print(arrays)
|
||||
# 填充数据
|
||||
for index in self.selectedIndexes(): # 遍历所有选择的
|
||||
arrays[index.row() - mirow][index.column() - micol] = index.data()
|
||||
print(arrays)
|
||||
data = "" # 最后的结果
|
||||
for row in arrays:
|
||||
data += "\t".join(row) + "\r\n"
|
||||
print(data)
|
||||
QApplication.clipboard().setText(data) # 复制到剪贴板中
|
||||
QMessageBox.information(self, "提示", "已复制")
|
||||
|
||||
def initHeader(self):
|
||||
for i in range(5):
|
||||
self.myModel.setHorizontalHeaderItem(
|
||||
i, QStandardItem("表头" + str(i + 1)))
|
||||
|
||||
def initData(self):
|
||||
for row in range(100):
|
||||
for col in range(5):
|
||||
self.myModel.setItem(
|
||||
row, col, QStandardItem("row: {row},col: {col}".format(row=row + 1, col=col + 1)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("TableView")
|
||||
w = TableView()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月6日
|
||||
@author: Irony."[讽刺]
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: TableView
|
||||
@description:
|
||||
'''
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt5.QtWidgets import QTableView, QApplication, QAction, QMessageBox
|
||||
|
||||
|
||||
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
|
||||
__Copyright__ = "Copyright (c) 2017 Irony.\"[讽刺]"
|
||||
__Version__ = "Version 1.0"
|
||||
|
||||
|
||||
class TableView(QTableView):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(TableView, self).__init__(parent)
|
||||
self.resize(800, 600)
|
||||
self.setContextMenuPolicy(Qt.ActionsContextMenu) # 右键菜单
|
||||
self.setEditTriggers(self.NoEditTriggers) # 禁止编辑
|
||||
self.doubleClicked.connect(self.onDoubleClick)
|
||||
self.addAction(QAction("复制", self, triggered=self.copyData))
|
||||
self.myModel = QStandardItemModel() # model
|
||||
self.initHeader() # 初始化表头
|
||||
self.setModel(self.myModel)
|
||||
self.initData() # 初始化模拟数据
|
||||
|
||||
def onDoubleClick(self, index):
|
||||
print(index.row(), index.column(), index.data())
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
super(TableView, self).keyPressEvent(event)
|
||||
# Ctrl + C
|
||||
if event.modifiers() == Qt.ControlModifier and event.key() == Qt.Key_C:
|
||||
self.copyData()
|
||||
|
||||
def copyData(self):
|
||||
count = len(self.selectedIndexes())
|
||||
if count == 0:
|
||||
return
|
||||
if count == 1: # 只复制了一个
|
||||
QApplication.clipboard().setText(
|
||||
self.selectedIndexes()[0].data()) # 复制到剪贴板中
|
||||
QMessageBox.information(self, "提示", "已复制一个数据")
|
||||
return
|
||||
rows = set()
|
||||
cols = set()
|
||||
for index in self.selectedIndexes(): # 得到所有选择的
|
||||
rows.add(index.row())
|
||||
cols.add(index.column())
|
||||
# print(index.row(),index.column(),index.data())
|
||||
if len(rows) == 1: # 一行
|
||||
QApplication.clipboard().setText("\t".join(
|
||||
[index.data() for index in self.selectedIndexes()])) # 复制
|
||||
QMessageBox.information(self, "提示", "已复制一行数据")
|
||||
return
|
||||
if len(cols) == 1: # 一列
|
||||
QApplication.clipboard().setText("\r\n".join(
|
||||
[index.data() for index in self.selectedIndexes()])) # 复制
|
||||
QMessageBox.information(self, "提示", "已复制一列数据")
|
||||
return
|
||||
mirow, marow = min(rows), max(rows) # 最(少/多)行
|
||||
micol, macol = min(cols), max(cols) # 最(少/多)列
|
||||
print(mirow, marow, micol, macol)
|
||||
arrays = [
|
||||
[
|
||||
"" for _ in range(macol - micol + 1)
|
||||
] for _ in range(marow - mirow + 1)
|
||||
] # 创建二维数组(并排除前面的空行和空列)
|
||||
print(arrays)
|
||||
# 填充数据
|
||||
for index in self.selectedIndexes(): # 遍历所有选择的
|
||||
arrays[index.row() - mirow][index.column() - micol] = index.data()
|
||||
print(arrays)
|
||||
data = "" # 最后的结果
|
||||
for row in arrays:
|
||||
data += "\t".join(row) + "\r\n"
|
||||
print(data)
|
||||
QApplication.clipboard().setText(data) # 复制到剪贴板中
|
||||
QMessageBox.information(self, "提示", "已复制")
|
||||
|
||||
def initHeader(self):
|
||||
for i in range(5):
|
||||
self.myModel.setHorizontalHeaderItem(
|
||||
i, QStandardItem("表头" + str(i + 1)))
|
||||
|
||||
def initData(self):
|
||||
for row in range(100):
|
||||
for col in range(5):
|
||||
self.myModel.setItem(
|
||||
row, col, QStandardItem("row: {row},col: {col}".format(row=row + 1, col=col + 1)))
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("TableView")
|
||||
w = TableView()
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
|
@ -1,127 +1,127 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月5日
|
||||
@author: Irony."[讽刺]
|
||||
@site: alyl.vip, orzorz.vip, irony.coding.me , irony.iask.in , mzone.iask.in
|
||||
@email: 892768447@qq.com
|
||||
@file: widgets.WidgetCode
|
||||
@description:
|
||||
'''
|
||||
from random import sample
|
||||
import string
|
||||
|
||||
from PyQt5.QtCore import Qt, qrand, QPointF, QPoint, QBasicTimer
|
||||
from PyQt5.QtGui import QPainter, QBrush, QPen, QPalette, QFontMetrics
|
||||
from PyQt5.QtWidgets import QLabel
|
||||
|
||||
|
||||
__version__ = "0.0.1"
|
||||
|
||||
DEF_NOISYPOINTCOUNT = 60 # 噪点数量
|
||||
COLORLIST = ("black", "gray", "red", "green", "blue", "magenta")
|
||||
TCOLORLIST = (Qt.black, Qt.gray, Qt.red, Qt.green, Qt.blue, Qt.magenta)
|
||||
QTCOLORLIST = (Qt.darkGray, Qt.darkRed, Qt.darkGreen, Qt.darkBlue, Qt.darkMagenta)
|
||||
HTML = "<html><body>{html}</body></html>"
|
||||
FONT = "<font color=\"{color}\">{word}</font>"
|
||||
WORDS = list(string.ascii_letters + string.digits)
|
||||
SINETABLE = (0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38)
|
||||
|
||||
class WidgetCode(QLabel):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(WidgetCode, self).__init__(*args, **kwargs)
|
||||
self._sensitive = False # 是否大小写敏感
|
||||
self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
|
||||
self.setBackgroundRole(QPalette.Midlight)
|
||||
self.setAutoFillBackground(True)
|
||||
# 字体
|
||||
newFont = self.font()
|
||||
newFont.setPointSize(16)
|
||||
newFont.setFamily("Kristen ITC")
|
||||
newFont.setBold(True)
|
||||
self.setFont(newFont)
|
||||
self.reset()
|
||||
# 定时器
|
||||
self.step = 0
|
||||
self.timer = QBasicTimer()
|
||||
self.timer.start(60, self)
|
||||
|
||||
def reset(self):
|
||||
self._code = "".join(sample(WORDS, 4)) # 随机4个字符
|
||||
self.setText(self._code)
|
||||
|
||||
def check(self, code):
|
||||
return self._code == str(code) if self._sensitive else self._code.lower() == str(code).lower()
|
||||
|
||||
def setSensitive(self, sensitive):
|
||||
self._sensitive = sensitive
|
||||
|
||||
# def setText(self, text):
|
||||
# text = text if (text and len(text) == 4) else "".join(sample(WORDS, 4)) # 随机4个字符
|
||||
# self._code = str(text)
|
||||
# html = "".join([FONT.format(color=COLORLIST[qrand() % 6], word=t) for t in text])
|
||||
# super(WidgetCode, self).setText(HTML.format(html=html))
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
super(WidgetCode, self).mouseReleaseEvent(event)
|
||||
self.reset()
|
||||
|
||||
def timerEvent(self, event):
|
||||
if event.timerId() == self.timer.timerId():
|
||||
self.step += 1
|
||||
return self.update()
|
||||
return super(WidgetCode, self).timerEvent(event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
# 背景白色
|
||||
painter.fillRect(event.rect(), QBrush(Qt.white))
|
||||
# 绘制边缘虚线框
|
||||
painter.setPen(Qt.DashLine)
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
painter.drawRect(self.rect())
|
||||
# 随机画条线
|
||||
for _ in range(3):
|
||||
painter.setPen(QPen(QTCOLORLIST[qrand() % 5], 1, Qt.SolidLine))
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
painter.drawLine(QPoint(0, qrand() % self.height()),
|
||||
QPoint(self.width(), qrand() % self.height()))
|
||||
painter.drawLine(QPoint(qrand() % self.width(), 0),
|
||||
QPoint(qrand() % self.width(), self.height()))
|
||||
# 绘制噪点
|
||||
painter.setPen(Qt.DotLine)
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
for _ in range(self.width()): # 绘制噪点
|
||||
painter.drawPoint(QPointF(qrand() % self.width(), qrand() % self.height()))
|
||||
# super(WidgetCode, self).paintEvent(event) # 绘制文字
|
||||
# 绘制跳动文字
|
||||
metrics = QFontMetrics(self.font())
|
||||
x = (self.width() - metrics.width(self.text())) / 2
|
||||
y = (self.height() + metrics.ascent() - metrics.descent()) / 2
|
||||
for i, ch in enumerate(self.text()):
|
||||
index = (self.step + i) % 16
|
||||
painter.setPen(TCOLORLIST[qrand() % 6])
|
||||
painter.drawText(x, y - ((SINETABLE[index] * metrics.height()) / 400), ch)
|
||||
x += metrics.width(ch)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
|
||||
from PyQt5.QtGui import QFontDatabase
|
||||
from PyQt5.QtWidgets import QLineEdit
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("Validate Code")
|
||||
QFontDatabase.addApplicationFont("itckrist.ttf")
|
||||
w = QWidget()
|
||||
layout = QHBoxLayout(w)
|
||||
|
||||
cwidget = WidgetCode(w, minimumHeight=35, minimumWidth=80)
|
||||
layout.addWidget(cwidget)
|
||||
lineEdit = QLineEdit(w, maxLength=4, placeholderText="请输入验证码并按回车验证",
|
||||
returnPressed=lambda:print(cwidget.check(lineEdit.text())))
|
||||
layout.addWidget(lineEdit)
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
Created on 2017年4月5日
|
||||
@author: Irony."[讽刺]
|
||||
@site: https://pyqt5.com, https://github.com/892768447
|
||||
@email: 892768447@qq.com
|
||||
@file: widgets.WidgetCode
|
||||
@description:
|
||||
'''
|
||||
from random import sample
|
||||
import string
|
||||
|
||||
from PyQt5.QtCore import Qt, qrand, QPointF, QPoint, QBasicTimer
|
||||
from PyQt5.QtGui import QPainter, QBrush, QPen, QPalette, QFontMetrics
|
||||
from PyQt5.QtWidgets import QLabel
|
||||
|
||||
|
||||
__version__ = "0.0.1"
|
||||
|
||||
DEF_NOISYPOINTCOUNT = 60 # 噪点数量
|
||||
COLORLIST = ("black", "gray", "red", "green", "blue", "magenta")
|
||||
TCOLORLIST = (Qt.black, Qt.gray, Qt.red, Qt.green, Qt.blue, Qt.magenta)
|
||||
QTCOLORLIST = (Qt.darkGray, Qt.darkRed, Qt.darkGreen, Qt.darkBlue, Qt.darkMagenta)
|
||||
HTML = "<html><body>{html}</body></html>"
|
||||
FONT = "<font color=\"{color}\">{word}</font>"
|
||||
WORDS = list(string.ascii_letters + string.digits)
|
||||
SINETABLE = (0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38)
|
||||
|
||||
class WidgetCode(QLabel):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(WidgetCode, self).__init__(*args, **kwargs)
|
||||
self._sensitive = False # 是否大小写敏感
|
||||
self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter)
|
||||
self.setBackgroundRole(QPalette.Midlight)
|
||||
self.setAutoFillBackground(True)
|
||||
# 字体
|
||||
newFont = self.font()
|
||||
newFont.setPointSize(16)
|
||||
newFont.setFamily("Kristen ITC")
|
||||
newFont.setBold(True)
|
||||
self.setFont(newFont)
|
||||
self.reset()
|
||||
# 定时器
|
||||
self.step = 0
|
||||
self.timer = QBasicTimer()
|
||||
self.timer.start(60, self)
|
||||
|
||||
def reset(self):
|
||||
self._code = "".join(sample(WORDS, 4)) # 随机4个字符
|
||||
self.setText(self._code)
|
||||
|
||||
def check(self, code):
|
||||
return self._code == str(code) if self._sensitive else self._code.lower() == str(code).lower()
|
||||
|
||||
def setSensitive(self, sensitive):
|
||||
self._sensitive = sensitive
|
||||
|
||||
# def setText(self, text):
|
||||
# text = text if (text and len(text) == 4) else "".join(sample(WORDS, 4)) # 随机4个字符
|
||||
# self._code = str(text)
|
||||
# html = "".join([FONT.format(color=COLORLIST[qrand() % 6], word=t) for t in text])
|
||||
# super(WidgetCode, self).setText(HTML.format(html=html))
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
super(WidgetCode, self).mouseReleaseEvent(event)
|
||||
self.reset()
|
||||
|
||||
def timerEvent(self, event):
|
||||
if event.timerId() == self.timer.timerId():
|
||||
self.step += 1
|
||||
return self.update()
|
||||
return super(WidgetCode, self).timerEvent(event)
|
||||
|
||||
def paintEvent(self, event):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHint(QPainter.Antialiasing)
|
||||
# 背景白色
|
||||
painter.fillRect(event.rect(), QBrush(Qt.white))
|
||||
# 绘制边缘虚线框
|
||||
painter.setPen(Qt.DashLine)
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
painter.drawRect(self.rect())
|
||||
# 随机画条线
|
||||
for _ in range(3):
|
||||
painter.setPen(QPen(QTCOLORLIST[qrand() % 5], 1, Qt.SolidLine))
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
painter.drawLine(QPoint(0, qrand() % self.height()),
|
||||
QPoint(self.width(), qrand() % self.height()))
|
||||
painter.drawLine(QPoint(qrand() % self.width(), 0),
|
||||
QPoint(qrand() % self.width(), self.height()))
|
||||
# 绘制噪点
|
||||
painter.setPen(Qt.DotLine)
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
for _ in range(self.width()): # 绘制噪点
|
||||
painter.drawPoint(QPointF(qrand() % self.width(), qrand() % self.height()))
|
||||
# super(WidgetCode, self).paintEvent(event) # 绘制文字
|
||||
# 绘制跳动文字
|
||||
metrics = QFontMetrics(self.font())
|
||||
x = (self.width() - metrics.width(self.text())) / 2
|
||||
y = (self.height() + metrics.ascent() - metrics.descent()) / 2
|
||||
for i, ch in enumerate(self.text()):
|
||||
index = (self.step + i) % 16
|
||||
painter.setPen(TCOLORLIST[qrand() % 6])
|
||||
painter.drawText(x, y - ((SINETABLE[index] * metrics.height()) / 400), ch)
|
||||
x += metrics.width(ch)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
|
||||
from PyQt5.QtGui import QFontDatabase
|
||||
from PyQt5.QtWidgets import QLineEdit
|
||||
app = QApplication(sys.argv)
|
||||
app.setApplicationName("Validate Code")
|
||||
QFontDatabase.addApplicationFont("itckrist.ttf")
|
||||
w = QWidget()
|
||||
layout = QHBoxLayout(w)
|
||||
|
||||
cwidget = WidgetCode(w, minimumHeight=35, minimumWidth=80)
|
||||
layout.addWidget(cwidget)
|
||||
lineEdit = QLineEdit(w, maxLength=4, placeholderText="请输入验证码并按回车验证",
|
||||
returnPressed=lambda:print(cwidget.check(lineEdit.text())))
|
||||
layout.addWidget(lineEdit)
|
||||
w.show()
|
||||
sys.exit(app.exec_())
|
||||
|
|
Loading…
Reference in a new issue