diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index af68413..aea50ad 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -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 diff --git a/ActiveX窗口/AxWidget.py b/ActiveX窗口/AxWidget.py index 511b250..c3ea0ff 100644 --- a/ActiveX窗口/AxWidget.py +++ b/ActiveX窗口/AxWidget.py @@ -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_()) diff --git a/C和C++扩展/py转pyd/pydmod.py b/C和C++扩展/py转pyd/pydmod.py index 58da4b1..f29b67a 100644 --- a/C和C++扩展/py转pyd/pydmod.py +++ b/C和C++扩展/py转pyd/pydmod.py @@ -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 diff --git a/Json生成QTreeWidget/Json生成树形结构.py b/Json生成QTreeWidget/Json生成树形结构.py index 3c23b51..6439f87 100644 --- a/Json生成QTreeWidget/Json生成树形结构.py +++ b/Json生成QTreeWidget/Json生成树形结构.py @@ -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_()) diff --git a/QGraphicsView练习/ImageView.py b/QGraphicsView练习/ImageView.py index ae437bf..60edb55 100644 --- a/QGraphicsView练习/ImageView.py +++ b/QGraphicsView练习/ImageView.py @@ -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_()) diff --git a/QGraphicsView练习/QGraphicsItem/Item拖拽改变大小.py b/QGraphicsView练习/QGraphicsItem/Item拖拽改变大小.py index 2507951..5fd8be0 100644 --- a/QGraphicsView练习/QGraphicsItem/Item拖拽改变大小.py +++ b/QGraphicsView练习/QGraphicsItem/Item拖拽改变大小.py @@ -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: diff --git a/QGraphicsView练习/QGraphicsItem/Item移动.py b/QGraphicsView练习/QGraphicsItem/Item移动.py index 07fbc84..7001f0f 100644 --- a/QGraphicsView练习/QGraphicsItem/Item移动.py +++ b/QGraphicsView练习/QGraphicsItem/Item移动.py @@ -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: diff --git a/QGraphicsView练习/QGraphicsItem/调整.py b/QGraphicsView练习/QGraphicsItem/调整.py index 9f99239..7c8d15a 100644 --- a/QGraphicsView练习/QGraphicsItem/调整.py +++ b/QGraphicsView练习/QGraphicsItem/调整.py @@ -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: diff --git a/QGraphicsView练习/简单图像处理/SimpleImagePs.py b/QGraphicsView练习/简单图像处理/SimpleImagePs.py index 9e45d4b..e4599c3 100644 --- a/QGraphicsView练习/简单图像处理/SimpleImagePs.py +++ b/QGraphicsView练习/简单图像处理/SimpleImagePs.py @@ -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_()) diff --git a/QGraphicsView练习/简单图像处理/SimpleImageThread.py b/QGraphicsView练习/简单图像处理/SimpleImageThread.py index 2848ae3..8992d3b 100644 --- a/QGraphicsView练习/简单图像处理/SimpleImageThread.py +++ b/QGraphicsView练习/简单图像处理/SimpleImageThread.py @@ -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 \ No newline at end of file diff --git a/QGraphicsView练习/简单图像处理/SimpleImageView.py b/QGraphicsView练习/简单图像处理/SimpleImageView.py index ed241ed..84875fc 100644 --- a/QGraphicsView练习/简单图像处理/SimpleImageView.py +++ b/QGraphicsView练习/简单图像处理/SimpleImageView.py @@ -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_()) diff --git a/QListView/显示自定义Widget.py b/QListView/显示自定义Widget.py index 053e352..e9c12f9 100644 --- a/QListView/显示自定义Widget.py +++ b/QListView/显示自定义Widget.py @@ -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: diff --git a/QListView/显示自定义Widget并排序.py b/QListView/显示自定义Widget并排序.py index 3440efe..3a37ee5 100644 --- a/QListView/显示自定义Widget并排序.py +++ b/QListView/显示自定义Widget并排序.py @@ -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: diff --git a/QListWidget自定义Item并拖拽/DragListWidget.py b/QListWidget自定义Item并拖拽/DragListWidget.py index dd8bb97..3104301 100644 --- a/QListWidget自定义Item并拖拽/DragListWidget.py +++ b/QListWidget自定义Item并拖拽/DragListWidget.py @@ -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: diff --git a/QRC资源文件使用/textread.py b/QRC资源文件使用/textread.py index dd33289..404b332 100644 --- a/QRC资源文件使用/textread.py +++ b/QRC资源文件使用/textread.py @@ -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_()) diff --git a/README.md b/README.md index 3a86b6f..a9a1186 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # 各种各样的PyQt测试和例子 +# [博客](https://pyqt5.com) + ### [Python.4 or Python][PyQt5] ### I、 项目型 diff --git a/仿QQ设置面板/Window.py b/仿QQ设置面板/Window.py index 998341e..a48efd1 100644 --- a/仿QQ设置面板/Window.py +++ b/仿QQ设置面板/Window.py @@ -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_()) diff --git a/分割窗口的分割条重写/Splitter.py b/分割窗口的分割条重写/Splitter.py index cca0421..0a70531 100644 --- a/分割窗口的分割条重写/Splitter.py +++ b/分割窗口的分割条重写/Splitter.py @@ -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_()) diff --git a/动画特效/右键菜单动画.py b/动画特效/右键菜单动画.py index ab82de3..dcec764 100644 --- a/动画特效/右键菜单动画.py +++ b/动画特效/右键菜单动画.py @@ -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: diff --git a/动画特效/淡入淡出.py b/动画特效/淡入淡出.py index 65a4821..4517edf 100644 --- a/动画特效/淡入淡出.py +++ b/动画特效/淡入淡出.py @@ -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: diff --git a/单实例应用/Application.py b/单实例应用/Application.py index 5db5a1e..ccc8d98 100644 --- a/单实例应用/Application.py +++ b/单实例应用/Application.py @@ -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: diff --git a/单实例应用/TestQSharedMemory.py b/单实例应用/TestQSharedMemory.py index ff0dc14..54c9037 100644 --- a/单实例应用/TestQSharedMemory.py +++ b/单实例应用/TestQSharedMemory.py @@ -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: diff --git a/单实例应用/TestQSingleApplication.py b/单实例应用/TestQSingleApplication.py index 992827b..18e2389 100644 --- a/单实例应用/TestQSingleApplication.py +++ b/单实例应用/TestQSingleApplication.py @@ -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: diff --git a/右下角弹出框/WindowNotify.py b/右下角弹出框/WindowNotify.py index eecff02..63e8444 100644 --- a/右下角弹出框/WindowNotify.py +++ b/右下角弹出框/WindowNotify.py @@ -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: diff --git a/多线程使用/inheritQThread.py b/多线程使用/inheritQThread.py index 5706ea3..a1c8804 100644 --- a/多线程使用/inheritQThread.py +++ b/多线程使用/inheritQThread.py @@ -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_()) diff --git a/多线程使用/moveToThread.py b/多线程使用/moveToThread.py index a8b2ec1..c1fd9e5 100644 --- a/多线程使用/moveToThread.py +++ b/多线程使用/moveToThread.py @@ -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_()) diff --git a/多线程使用/线程挂起恢复.py b/多线程使用/线程挂起恢复.py index 6deb8c7..73f63a2 100644 --- a/多线程使用/线程挂起恢复.py +++ b/多线程使用/线程挂起恢复.py @@ -1,117 +1,117 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import ctypes - -from PyQt5.QtCore import QThread, pyqtSignal -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton -import win32con -from win32process import SuspendThread, ResumeThread - - -# Created on 2018年3月13日 -# author: Irony -# site: https://github.com/892768447 -# email: 892768447@qq.com -# file: 多线程使用.a -# description: -__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com' -__Copyright__ = 'Copyright (c) 2018 Irony' -__Version__ = 1.0 - - -class Worker(QThread): - - valueChanged = pyqtSignal(int) # 值变化信号 - handle = -1 - - def run(self): - try: - self.handle = ctypes.windll.kernel32.OpenThread( # @UndefinedVariable - win32con.PROCESS_ALL_ACCESS, False, int(QThread.currentThreadId())) - except Exception as e: - print('get thread handle failed', e) - print('thread id', int(QThread.currentThreadId())) - for i in range(1, 101): - print('value', i) - self.valueChanged.emit(i) - QThread.sleep(1) - - -class Window(QWidget): - - def __init__(self, *args, **kwargs): - super(Window, self).__init__(*args, **kwargs) - layout = QVBoxLayout(self) - self.progressBar = QProgressBar(self) - self.progressBar.setRange(0, 100) - layout.addWidget(self.progressBar) - self.startButton = QPushButton('开启线程', self, clicked=self.onStart) - layout.addWidget(self.startButton) - self.suspendButton = QPushButton( - '挂起线程', self, clicked=self.onSuspendThread, enabled=False) - layout.addWidget(self.suspendButton) - self.resumeButton = QPushButton( - '恢复线程', self, clicked=self.onResumeThread, enabled=False) - layout.addWidget(self.resumeButton) - self.stopButton = QPushButton( - '终止线程', self, clicked=self.onStopThread, enabled=False) - layout.addWidget(self.stopButton) - - # 当前线程id - print('main id', int(QThread.currentThreadId())) - - # 子线程 - self._thread = Worker(self) - self._thread.finished.connect(self._thread.deleteLater) - self._thread.valueChanged.connect(self.progressBar.setValue) - - def onStart(self): - print('main id', int(QThread.currentThreadId())) - self._thread.start() # 启动线程 - self.startButton.setEnabled(False) - self.suspendButton.setEnabled(True) - self.stopButton.setEnabled(True) - - def onSuspendThread(self): - if self._thread.handle == -1: - return print('handle is wrong') - ret = SuspendThread(self._thread.handle) - print('挂起线程', self._thread.handle, ret) - self.suspendButton.setEnabled(False) - self.resumeButton.setEnabled(True) - - def onResumeThread(self): - if self._thread.handle == -1: - return print('handle is wrong') - ret = ResumeThread(self._thread.handle) - print('恢复线程', self._thread.handle, ret) - self.suspendButton.setEnabled(True) - self.resumeButton.setEnabled(False) - - def onStopThread(self): - self.startButton.setEnabled(False) - self.suspendButton.setEnabled(False) - self.resumeButton.setEnabled(False) - ret = ctypes.windll.kernel32.TerminateThread( # @UndefinedVariable - self._thread.handle, 0) - print('终止线程', self._thread.handle, ret) - self.stopButton.setEnabled(False) - - def closeEvent(self, event): - if self._thread.isRunning(): - self._thread.quit() - # 强制 - # self._thread.terminate() - del self._thread - super(Window, self).closeEvent(event) - - -if __name__ == '__main__': - import sys - import os - print('pid', os.getpid()) - from PyQt5.QtWidgets import QApplication - app = QApplication(sys.argv) - w = Window() - w.show() - sys.exit(app.exec_()) +#!/usr/bin/env python +# -*- coding: utf-8 -*- +import ctypes + +from PyQt5.QtCore import QThread, pyqtSignal +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QProgressBar, QPushButton +import win32con +from win32process import SuspendThread, ResumeThread + + +# Created on 2018年3月13日 +# author: Irony +# site: https://pyqt5.com, https://github.com/892768447 +# email: 892768447@qq.com +# file: 多线程使用.a +# description: +__Author__ = 'By: Irony\nQQ: 892768447\nEmail: 892768447@qq.com' +__Copyright__ = 'Copyright (c) 2018 Irony' +__Version__ = 1.0 + + +class Worker(QThread): + + valueChanged = pyqtSignal(int) # 值变化信号 + handle = -1 + + def run(self): + try: + self.handle = ctypes.windll.kernel32.OpenThread( # @UndefinedVariable + win32con.PROCESS_ALL_ACCESS, False, int(QThread.currentThreadId())) + except Exception as e: + print('get thread handle failed', e) + print('thread id', int(QThread.currentThreadId())) + for i in range(1, 101): + print('value', i) + self.valueChanged.emit(i) + QThread.sleep(1) + + +class Window(QWidget): + + def __init__(self, *args, **kwargs): + super(Window, self).__init__(*args, **kwargs) + layout = QVBoxLayout(self) + self.progressBar = QProgressBar(self) + self.progressBar.setRange(0, 100) + layout.addWidget(self.progressBar) + self.startButton = QPushButton('开启线程', self, clicked=self.onStart) + layout.addWidget(self.startButton) + self.suspendButton = QPushButton( + '挂起线程', self, clicked=self.onSuspendThread, enabled=False) + layout.addWidget(self.suspendButton) + self.resumeButton = QPushButton( + '恢复线程', self, clicked=self.onResumeThread, enabled=False) + layout.addWidget(self.resumeButton) + self.stopButton = QPushButton( + '终止线程', self, clicked=self.onStopThread, enabled=False) + layout.addWidget(self.stopButton) + + # 当前线程id + print('main id', int(QThread.currentThreadId())) + + # 子线程 + self._thread = Worker(self) + self._thread.finished.connect(self._thread.deleteLater) + self._thread.valueChanged.connect(self.progressBar.setValue) + + def onStart(self): + print('main id', int(QThread.currentThreadId())) + self._thread.start() # 启动线程 + self.startButton.setEnabled(False) + self.suspendButton.setEnabled(True) + self.stopButton.setEnabled(True) + + def onSuspendThread(self): + if self._thread.handle == -1: + return print('handle is wrong') + ret = SuspendThread(self._thread.handle) + print('挂起线程', self._thread.handle, ret) + self.suspendButton.setEnabled(False) + self.resumeButton.setEnabled(True) + + def onResumeThread(self): + if self._thread.handle == -1: + return print('handle is wrong') + ret = ResumeThread(self._thread.handle) + print('恢复线程', self._thread.handle, ret) + self.suspendButton.setEnabled(True) + self.resumeButton.setEnabled(False) + + def onStopThread(self): + self.startButton.setEnabled(False) + self.suspendButton.setEnabled(False) + self.resumeButton.setEnabled(False) + ret = ctypes.windll.kernel32.TerminateThread( # @UndefinedVariable + self._thread.handle, 0) + print('终止线程', self._thread.handle, ret) + self.stopButton.setEnabled(False) + + def closeEvent(self, event): + if self._thread.isRunning(): + self._thread.quit() + # 强制 + # self._thread.terminate() + del self._thread + super(Window, self).closeEvent(event) + + +if __name__ == '__main__': + import sys + import os + print('pid', os.getpid()) + from PyQt5.QtWidgets import QApplication + app = QApplication(sys.argv) + w = Window() + w.show() + sys.exit(app.exec_()) diff --git a/字体测试/FontAwesome.py b/字体测试/FontAwesome.py index e494beb..cff957c 100644 --- a/字体测试/FontAwesome.py +++ b/字体测试/FontAwesome.py @@ -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: diff --git a/字体测试/TestFontAwesome.py b/字体测试/TestFontAwesome.py index de6f446..28c72e3 100644 --- a/字体测试/TestFontAwesome.py +++ b/字体测试/TestFontAwesome.py @@ -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: diff --git a/字体测试/TestFontRoboto.py b/字体测试/TestFontRoboto.py index f9527a7..1f18480 100644 --- a/字体测试/TestFontRoboto.py +++ b/字体测试/TestFontRoboto.py @@ -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: diff --git a/左侧选项卡/LeftTabWidget.py b/左侧选项卡/LeftTabWidget.py index 34b0ace..22020f9 100644 --- a/左侧选项卡/LeftTabWidget.py +++ b/左侧选项卡/LeftTabWidget.py @@ -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: diff --git a/探测窗口和放大截图/简单探测窗口和放大截图.py b/探测窗口和放大截图/简单探测窗口和放大截图.py index 4419b6b..ebdd712 100644 --- a/探测窗口和放大截图/简单探测窗口和放大截图.py +++ b/探测窗口和放大截图/简单探测窗口和放大截图.py @@ -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: diff --git a/数据库查询显示表格/main.py b/数据库查询显示表格/main.py index cf7efeb..7382d78 100644 --- a/数据库查询显示表格/main.py +++ b/数据库查询显示表格/main.py @@ -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: diff --git a/无边框自定义标题栏窗口/FramelessWindow.py b/无边框自定义标题栏窗口/FramelessWindow.py index 109f847..4834673 100644 --- a/无边框自定义标题栏窗口/FramelessWindow.py +++ b/无边框自定义标题栏窗口/FramelessWindow.py @@ -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) diff --git a/无边框自定义标题栏窗口/Test.py b/无边框自定义标题栏窗口/Test.py index 2dcc228..e606ff8 100644 --- a/无边框自定义标题栏窗口/Test.py +++ b/无边框自定义标题栏窗口/Test.py @@ -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_()) diff --git a/无边框自定义标题栏窗口/win无边框调整大小.py b/无边框自定义标题栏窗口/win无边框调整大小.py index f52dde7..891e8fc 100644 --- a/无边框自定义标题栏窗口/win无边框调整大小.py +++ b/无边框自定义标题栏窗口/win无边框调整大小.py @@ -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: diff --git a/梦幻树/DreamTree.py b/梦幻树/DreamTree.py index a31fc36..9b663d0 100644 --- a/梦幻树/DreamTree.py +++ b/梦幻树/DreamTree.py @@ -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: diff --git a/消息对话框倒计时关闭/MessageBox.py b/消息对话框倒计时关闭/MessageBox.py index e819db7..f80d890 100644 --- a/消息对话框倒计时关闭/MessageBox.py +++ b/消息对话框倒计时关闭/MessageBox.py @@ -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: diff --git a/消息提示/Notification.py b/消息提示/Notification.py index cae77aa..93bcf4a 100644 --- a/消息提示/Notification.py +++ b/消息提示/Notification.py @@ -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: diff --git a/界面美化/QSlider美化/PaintQSlider.py b/界面美化/QSlider美化/PaintQSlider.py index e11bbed..f2c3805 100644 --- a/界面美化/QSlider美化/PaintQSlider.py +++ b/界面美化/QSlider美化/PaintQSlider.py @@ -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: diff --git a/界面美化/QSlider美化/QssQSlider.py b/界面美化/QSlider美化/QssQSlider.py index bfbbc58..0baa41a 100644 --- a/界面美化/QSlider美化/QssQSlider.py +++ b/界面美化/QSlider美化/QssQSlider.py @@ -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 diff --git a/界面美化/各类进度条/CircleProgressBar.py b/界面美化/各类进度条/CircleProgressBar.py index 28b6227..a3a4812 100644 --- a/界面美化/各类进度条/CircleProgressBar.py +++ b/界面美化/各类进度条/CircleProgressBar.py @@ -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: diff --git a/界面美化/各类进度条/MetroCircleProgress.py b/界面美化/各类进度条/MetroCircleProgress.py index 7ec7c3c..8cf43db 100644 --- a/界面美化/各类进度条/MetroCircleProgress.py +++ b/界面美化/各类进度条/MetroCircleProgress.py @@ -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: diff --git a/界面美化/各类进度条/MetroLineProgress.py b/界面美化/各类进度条/MetroLineProgress.py index 798a58c..83330d7 100644 --- a/界面美化/各类进度条/MetroLineProgress.py +++ b/界面美化/各类进度条/MetroLineProgress.py @@ -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: diff --git a/界面美化/各类进度条/PercentProgressBar.py b/界面美化/各类进度条/PercentProgressBar.py index 787380e..8938d99 100644 --- a/界面美化/各类进度条/PercentProgressBar.py +++ b/界面美化/各类进度条/PercentProgressBar.py @@ -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: diff --git a/界面美化/水波纹进度条/ProgressBar.py b/界面美化/水波纹进度条/ProgressBar.py index b50d3ee..7a71a74 100644 --- a/界面美化/水波纹进度条/ProgressBar.py +++ b/界面美化/水波纹进度条/ProgressBar.py @@ -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)) diff --git a/界面美化/水波纹进度条/TestWidget.py b/界面美化/水波纹进度条/TestWidget.py index a01c130..d75ac3c 100644 --- a/界面美化/水波纹进度条/TestWidget.py +++ b/界面美化/水波纹进度条/TestWidget.py @@ -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_()) diff --git a/界面美化/边框动画阴影/AnimationShadowEffect.py b/界面美化/边框动画阴影/AnimationShadowEffect.py new file mode 100644 index 0000000..d3e4c7b --- /dev/null +++ b/界面美化/边框动画阴影/AnimationShadowEffect.py @@ -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 \ No newline at end of file diff --git a/程序重启/AutoRestart.py b/程序重启/AutoRestart.py index ca4f7f6..6bb1d6f 100644 --- a/程序重启/AutoRestart.py +++ b/程序重启/AutoRestart.py @@ -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: diff --git a/简单的窗口贴边隐藏/WeltHideWindow.py b/简单的窗口贴边隐藏/WeltHideWindow.py index fc4b047..bac31d9 100644 --- a/简单的窗口贴边隐藏/WeltHideWindow.py +++ b/简单的窗口贴边隐藏/WeltHideWindow.py @@ -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_()) diff --git a/网络操作/TcpSocket/控制小车/ControlCar.py b/网络操作/TcpSocket/控制小车/ControlCar.py index 0a5757e..45eced4 100644 --- a/网络操作/TcpSocket/控制小车/ControlCar.py +++ b/网络操作/TcpSocket/控制小车/ControlCar.py @@ -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_()) diff --git a/网络操作/TcpSocket/控制小车/server.py b/网络操作/TcpSocket/控制小车/server.py index 1dfa1c5..d60c5c5 100644 --- a/网络操作/TcpSocket/控制小车/server.py +++ b/网络操作/TcpSocket/控制小车/server.py @@ -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 diff --git a/自动更新/mylibs/testlibs.py b/自动更新/mylibs/testlibs.py index f6ee6b2..2bc2ee4 100644 --- a/自动更新/mylibs/testlibs.py +++ b/自动更新/mylibs/testlibs.py @@ -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: diff --git a/自动更新/test.py b/自动更新/test.py index 29bf9c2..c00c1dc 100644 --- a/自动更新/test.py +++ b/自动更新/test.py @@ -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: diff --git a/自定义属性测试/自定义属性测试.py b/自定义属性测试/自定义属性测试.py index eea0f7b..1f842d2 100644 --- a/自定义属性测试/自定义属性测试.py +++ b/自定义属性测试/自定义属性测试.py @@ -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_()) diff --git a/表格复制/TableView.py b/表格复制/TableView.py index b16e693..c7c99a0 100644 --- a/表格复制/TableView.py +++ b/表格复制/TableView.py @@ -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_()) diff --git a/验证码控件/WidgetCode.py b/验证码控件/WidgetCode.py index 978b2a9..11760e9 100644 --- a/验证码控件/WidgetCode.py +++ b/验证码控件/WidgetCode.py @@ -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}" -FONT = "{word}" -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}" +FONT = "{word}" +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_())