update site

This commit is contained in:
Irony 2018-09-25 23:20:03 +08:00
parent 7d0a51c98d
commit c2e0d0c7a5
57 changed files with 2565 additions and 2545 deletions

View file

@ -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

View file

@ -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_())

View file

@ -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

View file

@ -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_())

View file

@ -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_())

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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_())

View file

@ -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

View file

@ -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_())

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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_())

View file

@ -1,5 +1,7 @@
# 各种各样的PyQt测试和例子
# [博客](https://pyqt5.com)
### [Python.4 or Python][PyQt5]
### I、 项目型

View file

@ -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_())

View file

@ -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_())

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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_())

View file

@ -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_())

View file

@ -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_())

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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)

View file

@ -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_())

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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))

View file

@ -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_())

View 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

View file

@ -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:

View file

@ -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_())

View file

@ -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_())

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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_())

View file

@ -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_())

View file

@ -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_())