Compare commits

1 Commits
Author SHA1 Message Date
Irony bf1139a467 old 2019-01-20 23:27:01 +08:00
876 changed files with 3750 additions and 1835 deletions
-1
View File
@@ -129,4 +129,3 @@ tmp
.pydevproject
.README.md.html
README.md.html
shape_predictor_68_face_landmarks.dat
-1
View File
@@ -1 +0,0 @@
*.xml
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.4" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="projectConfiguration" value="Nosetests" />
<option name="PROJECT_TEST_RUNNER" value="Nosetests" />
</component>
</module>
-5
View File
@@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" defaultCharsetForPropertiesFiles="UTF-8" addBOMForNewFiles="with NO BOM">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
-60
View File
@@ -1,60 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectInspectionProfilesVisibleTreeState">
<entry key="Project Default">
<profile-state>
<expanded-state>
<State />
<State>
<id>Buildout</id>
</State>
<State>
<id>EditorConfig</id>
</State>
<State>
<id>General</id>
</State>
<State>
<id>HTML</id>
</State>
<State>
<id>Internationalization</id>
</State>
<State>
<id>JSON and JSON5</id>
</State>
<State>
<id>Markdown</id>
</State>
<State>
<id>Properties Files</id>
</State>
<State>
<id>Python</id>
</State>
<State>
<id>RELAX NG</id>
</State>
<State>
<id>ReST</id>
</State>
<State>
<id>RegExp</id>
</State>
<State>
<id>XML</id>
</State>
<State>
<id>YAML</id>
</State>
</expanded-state>
<selected-state>
<State>
<id>Buildout</id>
</State>
</selected-state>
</profile-state>
</entry>
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.4" project-jdk-type="Python SDK" />
</project>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/PyQt.iml" filepath="$PROJECT_DIR$/.idea/PyQt.iml" />
</modules>
</component>
</project>
Generated
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+96 -43
View File
@@ -1,44 +1,97 @@
eclipse.preferences.version=1
encoding//Demo/EmbedWindow.py=utf-8
encoding//Demo/FacePoints.py=utf-8
encoding//Demo/FollowWindow.py=utf-8
encoding//Demo/FramelessWindow.py=utf-8
encoding//Demo/Lib/Application.py=utf-8
encoding//Demo/Lib/FramelessWindow.py=utf-8
encoding//Demo/NativeEvent.py=utf-8
encoding//Demo/Notification.py=utf-8
encoding//Demo/ProbeWindow.py=utf-8
encoding//Demo/RestartWindow.py=utf-8
encoding//Demo/SharedMemory.py=utf-8
encoding//Demo/SingleApplication.py=utf-8
encoding//Demo/VerificationCode.py=utf-8
encoding//Demo/WeltHideWindow.py=utf-8
encoding//Demo/WindowNotify.py=utf-8
encoding//QChart/LineChart.py=utf-8
encoding//QFont/AwesomeFont.py=utf-8
encoding//QFont/Lib/FontAwesome.py=utf-8
encoding//QListView/CustomWidgetSortItem.py=utf-8
encoding//QListView/SortItemByRole.py=utf-8
encoding//QMessageBox/CustomColorIcon.py=utf-8
encoding//QProgressBar/Lib/WaterRippleProgressBar.py=utf-8
encoding//QProgressBar/MetroCircleProgress.py=utf-8
encoding//QProgressBar/PercentProgressBar.py=utf-8
encoding//QProgressBar/SimpleStyle.py=utf-8
encoding//QProgressBar/WaterProgressBar.py=utf-8
encoding//QProxyStyle/Lib/TabBarStyle.py=utf-8
encoding//QProxyStyle/TabTextDirection.py=utf-8
encoding//QPushButton/BottomLineProgress.py=utf-8
encoding//QPushButton/FontRotate.py=utf-8
encoding//QPushButton/NormalStyle.py=utf-8
encoding//QScrollBar/StyleScrollBar.py=utf-8
encoding//QSlider/PaintQSlider.py=utf-8
encoding//QSlider/QssQSlider.py=utf-8
encoding//QSplitter/RewriteHandle.py=utf-8
encoding//QThread/moveToThread.py=utf-8
encoding//QTreeWidget/ParsingJson.py=utf-8
encoding//QWebView/DreamTree.py=utf-8
encoding//QWidget/Lib/CustomPaintWidget.py=utf-8
encoding//QWidget/Lib/CustomWidget.py=utf-8
encoding//QWidget/WidgetStyle.py=utf-8
encoding//Test/\u5168\u5C40\u70ED\u952E/HotKey.py=utf-8
encoding//Test/\u81EA\u52A8\u66F4\u65B0/test.py=utf-8
encoding//ActiveX/\u663E\u793Aword_excel_pdf.py=utf-8
encoding//Tmps/FaderWidget.py=utf-8
encoding//\u4E0B\u62C9\u6846/\u4E0B\u62C9\u9009\u62E9\u8054\u52A8/\u4E0B\u62C9\u9009\u62E9\u8054\u52A8.py=utf-8
encoding//\u5176\u5B83/C\u548CC++\u6269\u5C55/py\u8F6Cpyd/pydmod.py=utf-8
encoding//\u5176\u5B83/QRC\u8D44\u6E90\u6587\u4EF6\u4F7F\u7528/qrctest1.py=utf-8
encoding//\u5176\u5B83/QRC\u8D44\u6E90\u6587\u4EF6\u4F7F\u7528/qrctest2.py=utf-8
encoding//\u5176\u5B83/QRC\u8D44\u6E90\u6587\u4EF6\u4F7F\u7528/res_rc.py=utf-8
encoding//\u5176\u5B83/QRC\u8D44\u6E90\u6587\u4EF6\u4F7F\u7528/textread.py=utf-8
encoding//\u5176\u5B83/\u4E32\u53E3\u8C03\u8BD5\u5C0F\u52A9\u624B/UiSerialPort.py=utf-8
encoding//\u5176\u5B83/\u4E32\u53E3\u8C03\u8BD5\u5C0F\u52A9\u624B/\u4E32\u53E3\u8C03\u8BD5\u5C0F\u52A9\u624B.py=utf-8
encoding//\u5176\u5B83/\u4EBA\u8138\u63CF\u70B9\u68C0\u6D4B/OpencvWidget.py=utf-8
encoding//\u5176\u5B83/\u5168\u5C40\u70ED\u952E/HotKey.py=utf-8
encoding//\u5176\u5B83/\u53F3\u4E0B\u89D2\u5F39\u51FA\u6846/WindowNotify.py=utf-8
encoding//\u5176\u5B83/\u5B57\u4F53\u6D4B\u8BD5/FontAwesome.py=utf-8
encoding//\u5176\u5B83/\u5B57\u4F53\u6D4B\u8BD5/TestFontAwesome.py=utf-8
encoding//\u5176\u5B83/\u5B57\u4F53\u6D4B\u8BD5/TestFontRoboto.py=utf-8
encoding//\u5176\u5B83/\u6D88\u606F\u63D0\u793A/BubbleTips.py=utf-8
encoding//\u5176\u5B83/\u6D88\u606F\u63D0\u793A/Notification.py=utf-8
encoding//\u5176\u5B83/\u7A0B\u5E8F\u91CD\u542F/AutoRestart.py=utf-8
encoding//\u5176\u5B83/\u81EA\u52A8\u66F4\u65B0/mylibs/testlibs.py=utf-8
encoding//\u5176\u5B83/\u81EA\u52A8\u66F4\u65B0/test.py=utf-8
encoding//\u5176\u5B83/\u81EA\u5B9A\u4E49import/IronyImporter.py=utf-8
encoding//\u5176\u5B83/\u81EA\u5B9A\u4E49import/build.py=utf-8
encoding//\u5176\u5B83/\u81EA\u5B9A\u4E49import/main.py=utf-8
encoding//\u5176\u5B83/\u81EA\u5B9A\u4E49import/src/test.py=utf-8
encoding//\u5176\u5B83/\u81EA\u5B9A\u4E49\u5C5E\u6027\u6D4B\u8BD5/\u81EA\u5B9A\u4E49\u5C5E\u6027\u6D4B\u8BD5.py=utf-8
encoding//\u5217\u8868/QListView/\u663E\u793A\u81EA\u5B9A\u4E49Widget.py=utf-8
encoding//\u5217\u8868/QListView/\u663E\u793A\u81EA\u5B9A\u4E49Widget\u5E76\u6392\u5E8F.py=utf-8
encoding//\u5217\u8868/QListWidget/\u5220\u9664\u81EA\u5B9A\u4E49Item.py=utf-8
encoding//\u5217\u8868/QListWidget/\u817E\u8BAF\u89C6\u9891\u70ED\u64AD\u5217\u8868/TencentMovieHotPlay.py=utf-8
encoding//\u5217\u8868/QListWidget/\u817E\u8BAF\u89C6\u9891\u70ED\u64AD\u5217\u8868/TencentMovieHotPlay_Flow.py=utf-8
encoding//\u5217\u8868/QListWidget/\u817E\u8BAF\u89C6\u9891\u70ED\u64AD\u5217\u8868/TencentMovieHotPlay_ListWidget.py=utf-8
encoding//\u5217\u8868/QListWidget/\u81EA\u5B9A\u4E49\u53EF\u62D6\u62FDItem.py=utf-8
encoding//\u52A8\u753B/\u53F3\u952E\u83DC\u5355\u52A8\u753B.py=utf-8
encoding//\u52A8\u753B/\u591A\u9875\u9762\u5207\u6362\u52A8\u753B/SlidingStackedWidget.py=utf-8
encoding//\u52A8\u753B/\u591A\u9875\u9762\u5207\u6362\u52A8\u753B/UiImageSlider.py=utf-8
encoding//\u52A8\u753B/\u591A\u9875\u9762\u5207\u6362\u52A8\u753B/\u56FE\u7247\u8F6E\u64AD\u52A8\u753B.py=utf-8
encoding//\u52A8\u753B/\u6309\u94AE\u653E\u5927\u7F29\u5C0F\u52A8\u753B.py=utf-8
encoding//\u52A8\u753B/\u70B9\u9635\u7279\u6548/\u70B9\u9635\u7279\u6548.py=utf-8
encoding//\u52A8\u753B/\u7A97\u53E3\u6DE1\u5165\u6DE1\u51FA.py=utf-8
encoding//\u56FE\u5F62\u89C6\u56FE/\u4E16\u754C\u5730\u56FE/WorldMap.py=utf-8
encoding//\u56FE\u5F62\u89C6\u56FE/\u663E\u793A\u56FE\u7247\u53CA\u7F29\u653E.py=utf-8
encoding//\u56FE\u5F62\u89C6\u56FE/\u6DFB\u52A0QWidget.py=utf-8
encoding//\u56FE\u5F62\u89C6\u56FE/\u7B80\u5355\u56FE\u50CF\u5904\u7406/SimpleImagePs.py=utf-8
encoding//\u56FE\u5F62\u89C6\u56FE/\u7B80\u5355\u56FE\u50CF\u5904\u7406/SimpleImageThread.py=utf-8
encoding//\u56FE\u5F62\u89C6\u56FE/\u7B80\u5355\u56FE\u50CF\u5904\u7406/SimpleImageView.py=utf-8
encoding//\u56FE\u7247/\u4EFF\u7F51\u9875\u56FE\u7247\u9519\u4F4D\u7279\u6548.py=utf-8
encoding//\u56FE\u7247/\u56FE\u7247\u52A0\u8F7D/res_rc.py=utf-8
encoding//\u56FE\u7247/\u56FE\u7247\u52A0\u8F7D/xpmres.py=utf-8
encoding//\u56FE\u7247/\u56FE\u7247\u52A0\u8F7D/\u56FE\u7247\u52A0\u8F7D.py=utf-8
encoding//\u56FE\u7247/\u56FE\u7247\u65CB\u8F6C.py=utf-8
encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/pyd\u7248\u672C/QtNinePatch/sip/configure.py=utf-8
encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/pyd\u7248\u672C/QtNinePatch/sip/testQtNinePatch.py=utf-8
encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C1/NinePatch.py=utf-8
encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C1/testNinePatch.py=utf-8
encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C2/QtNinePatch.py=utf-8
encoding//\u56FE\u7247/\u663E\u793A.9\u683C\u5F0F\u56FE\u7247/\u7EAFpython\u7248\u672C2/testQtNinePatch.py=utf-8
encoding//\u56FE\u8868/PyQtChart/ChartView/ChartView.py=utf-8
encoding//\u56FE\u8868/PyQtChart/ChartView/ChatWidget.py=utf-8
encoding//\u56FE\u8868/PyQtChart/charts/bar/BarStack.py=utf-8
encoding//\u56FE\u8868/PyQtChart/charts/line/LineStack.py=utf-8
encoding//\u56FE\u8868/PyQtChart/demo/LineChart.py=utf-8
encoding//\u56FE\u8868/PyQtChart/demo/LineChart\u81EA\u5B9A\u4E49xy\u8F74.py=utf-8
encoding//\u56FE\u8868/PyQtChart/demo/ToolTip.py=utf-8
encoding//\u56FE\u8868/PyQtChart/demo/ToolTip2.py=utf-8
encoding//\u591A\u7EBF\u7A0B/moveToThread.py=utf-8
encoding//\u591A\u7EBF\u7A0B/\u7EBF\u7A0B\u4F11\u7720\u5524\u9192.py=utf-8
encoding//\u591A\u7EBF\u7A0B/\u7EBF\u7A0B\u6302\u8D77\u6062\u590D.py=utf-8
encoding//\u591A\u7EBF\u7A0B/\u7EE7\u627FQThread.py=utf-8
encoding//\u591A\u9875\u9762/QScrollArea/\u4EFFQQ\u8BBE\u7F6E\u9762\u677F/SettingUi.py=utf-8
encoding//\u591A\u9875\u9762/QScrollArea/\u4EFFQQ\u8BBE\u7F6E\u9762\u677F/\u4EFFQQ\u8BBE\u7F6E\u9762\u677F.py=utf-8
encoding//\u591A\u9875\u9762/QStackedWidget/\u5DE6\u4FA7\u9009\u9879\u5361/\u5DE6\u4FA7\u9009\u9879\u5361.py=utf-8
encoding//\u6811\u7ED3\u6784/QTreeWidget/Json\u751F\u6210QTreeWidget/Json\u751F\u6210\u6811\u5F62\u7ED3\u6784.py=utf-8
encoding//\u6D4F\u89C8\u5668/QWebView/\u68A6\u5E7B\u6811/\u68A6\u5E7B\u6811.py=utf-8
encoding//\u6ED1\u52A8\u6761/\u6ED1\u52A8\u6761\u70B9\u51FB\u5B9A\u4F4D.py=utf-8
encoding//\u7A97\u53E3/\u5206\u5272\u7A97\u53E3\u7684\u5206\u5272\u6761\u91CD\u5199.py=utf-8
encoding//\u7A97\u53E3/\u65E0\u8FB9\u6846\u81EA\u5B9A\u4E49\u6807\u9898\u680F\u7A97\u53E3/FramelessWindow.py=utf-8
encoding//\u7A97\u53E3/\u65E0\u8FB9\u6846\u81EA\u5B9A\u4E49\u6807\u9898\u680F\u7A97\u53E3/win\u65E0\u8FB9\u6846\u8C03\u6574\u5927\u5C0F.py=utf-8
encoding//\u7A97\u53E3/\u65E0\u8FB9\u6846\u81EA\u5B9A\u4E49\u6807\u9898\u680F\u7A97\u53E3/\u65E0\u8FB9\u6846\u81EA\u5B9A\u4E49\u6807\u9898\u680F\u7A97\u53E3.py=utf-8
encoding//\u7A97\u53E3/\u6D88\u606F\u5BF9\u8BDD\u6846\u5012\u8BA1\u65F6\u5173\u95ED.py=utf-8
encoding//\u7A97\u53E3/\u7A97\u53E3\u91CD\u542F.py=utf-8
encoding//\u7F51\u7EDC/\u63A7\u5236\u5C0F\u8F66/\u63A7\u5236\u5C0F\u8F66.py=utf-8
encoding//\u7F8E\u5316/Effect/AnimationShadowEffect.py=utf-8
encoding//\u7F8E\u5316/Effect/\u56FE\u7247\u6309\u94AE\u8F93\u5165\u6846\u9634\u5F71.py=utf-8
encoding//\u7F8E\u5316/QLabel/\u5706\u5F62\u56FE\u7247.py=utf-8
encoding//\u7F8E\u5316/QProgressBar/Metro\u8FDB\u5EA6\u6761.py=utf-8
encoding//\u7F8E\u5316/QProgressBar/\u6C34\u6CE2\u7EB9\u8FDB\u5EA6\u6761/ProgressBar.py=utf-8
encoding//\u7F8E\u5316/QProgressBar/\u6C34\u6CE2\u7EB9\u8FDB\u5EA6\u6761/\u6C34\u6CE2\u7EB9\u8FDB\u5EA6\u6761.py=utf-8
encoding//\u7F8E\u5316/QSlider/PaintQSlider.py=utf-8
encoding//\u7F8E\u5316/QWidget/CustomPaintWidget.py=utf-8
encoding//\u7F8E\u5316/QWidget/CustomWidget.py=utf-8
encoding//\u7F8E\u5316/QWidget/QWidget\u6837\u5F0F\u6D4B\u8BD5.py=utf-8
encoding//\u83DC\u5355/\u83DC\u5355\u591A\u9009\u4E0D\u5173\u95ED.py=utf-8
encoding//\u8868\u683C/QTableView/\u8868\u683C\u5185\u5BB9\u590D\u5236.py=utf-8
encoding//\u8868\u683C/QTableWidget/\u6570\u636E\u5E93\u67E5\u8BE2\u663E\u793A\u8868\u683C/main.py=utf-8
encoding//\u8868\u683C/QTableWidget/\u6570\u636E\u5E93\u67E5\u8BE2\u663E\u793A\u8868\u683C/mainui.py=utf-8
+3 -4
View File
@@ -1,10 +1,9 @@
# QAxWidget
# ActiveX控件
## 1、显示Word、Excel、PDF文件
[运行 ViewOffice.py](ViewOffice.py)
## [1、显示Word、Excel、PDF文件](显示word_excel_pdf.py)
1. 利用 `Word.Application` 打开Word文件
1. 利用 `Excel.Application` 打开Excel文件
1. 利用 `Adobe PDF Reader` 打开PDF文件(前提先装PDF软件)
![ViewOffice](ScreenShot/ViewOffice.png)
![截图](ScreenShot/显示word_excel_pdf.png)

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

@@ -4,9 +4,9 @@
'''
Created on 2017年4月6日
@author: Irony."[讽刺]
@site: https://pyqt5.com , https://github.com/892768447
@site: https://pyqt5.com, https://github.com/892768447
@email: 892768447@qq.com
@file: ViewOffice
@file: TableView
@description:
'''
from PyQt5.QAxContainer import QAxWidget
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
View File
-141
View File
@@ -1,141 +0,0 @@
# Demo
## 1、重启窗口Widget
[运行 RestartWindow.py](RestartWindow.py)
利用类变量对窗口的变量进行引用,防止被回收(导致窗口一闪而过),重启时先显示新窗口后关闭自己
![RestartWindow](ScreenShot/RestartWindow.gif)
## 2、简单的窗口贴边隐藏
[运行 WeltHideWindow.py](WeltHideWindow.py)
1. 大概思路
1. 思路是当窗口进入左边,顶部,右边一半时,此时判断窗口的坐标
1. 如果窗口的x坐标小于0 则需要隐藏到左边
1. 如果窗口的y坐标小于0 则需要隐藏到顶部
1. 如果窗口的x坐标大于屏幕宽度-窗口宽度/2 则需要隐藏到右边
2. 事件说明
1. `mousePressEvent`,鼠标按下事件,主要记录按下的坐标
1. `mouseMoveEvent`,鼠标移动事件,用于移动窗口
1. `mouseReleaseEvent`,鼠标弹起事件,用于判断是否需要隐藏窗口
1. `enterEvent`,鼠标进入事件,用于窗口隐藏后,是否需要暂时显示预览
1. `leaveEvent`,鼠标离开事件,用于窗口暂时显示后自动隐藏效果
![WeltHideWindow](ScreenShot/WeltHideWindow.gif)
## 3、嵌入外部窗口
[运行 EmbedWindow.py](EmbedWindow.py)
1. 使用`SetParent`函数设置外部窗口的`parent`为Qt的窗口
1. Qt使用`QWidget.createWindowContainer(QWindow.fromWinId(窗口ID))`生成QWidget
1. 使用`GetWindowLong`得到原来窗口的样式属性`style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE)``exstyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)`
1. 这里还原窗口后不会显示,用spy++发现没有了WS_VISIBLE样式(未解决)
![EmbedWindow](ScreenShot/EmbedWindow.gif)
## 4、简单跟随其它窗口
[运行 FollowWindow.py](FollowWindow.py)
1. 利用win32gui模块获取目标窗口的句柄
1. 通过句柄获取目标窗口的大小位置,并设置自己的位置
1. 当句柄失效时关闭自己
1. 主要是检测时间,在10毫秒以下很流畅
![FollowWindow](ScreenShot/FollowWindow.gif)
## 5、简单探测窗口和放大截图
[运行 ProbeWindow.py](ProbeWindow.py)
1. 利用`win32gui`模块获取鼠标所在位置的窗口大小(未去掉边框)和rgb颜色
1. 利用一个全屏的全透明鼠标穿透的窗口(目的在于绘制矩形框和截图)
![ProbeWindow](ScreenShot/ProbeWindow.gif)
## 6、无边框自定义标题栏窗口
[运行 FramelessWindow.py](FramelessWindow.py) | [运行 NativeEvent.py](NativeEvent.py)
1. 重写鼠标事件
1. 使用一个`QWidget``FramelessWindow`)作为父窗口, 一个`TitleBar`作为标题栏, 一个`QWidget`作为底部容器
1. 父窗口`FramelessWindow`设置为背景透明,但是需要绘制一定宽度的透明度很高的矩形边框用来接受鼠标事件(变形鼠标样式进行调整窗口大小)
1. `TitleBar`的最小化最大化关闭等按钮事件关联到父窗口里
1. `TitleBar`中的鼠标按下移动事件得到坐标也传递到父窗口调用move方法进行窗口移动
2. windows api
1. 使用`win32gui`设置薄边框
1. 重写`nativeEvent`事件拦截边框的系统边框的显示,并返回各个方向
![FramelessWindow](ScreenShot/FramelessWindow.gif)
## 7、右下角弹出框
[运行 WindowNotify.py](WindowNotify.py)
![WindowNotify](ScreenShot/WindowNotify.gif)
## 8、程序重启
[运行 AutoRestart.py](AutoRestart.py)
![AutoRestart](ScreenShot/AutoRestart.png)
## 9、自定义属性
[运行 CustomProperties.py](CustomProperties.py)
![CustomProperties](ScreenShot/CustomProperties.png)
## 10、调用截图DLL
[运行 ScreenShotDll.py](ScreenShotDll.py)
![ScreenShotDll](ScreenShot/ScreenShotDll.gif)
## 11、单实例应用
[运行 SingleApplication.py](SingleApplication.py) | [运行 SharedMemory.py](SharedMemory.py)
1. QSharedMemory
2. QLocalSocket, QLocalServer
## 12、简单的右下角气泡提示
[运行 BubbleTips.py](BubbleTips.py)
1. 使用 `QWidget` 包含一个 `QLabel`, 其中 `QWidget` 通过 `paintEvent` 绘制气泡形状
2. 使用 `QPropertyAnimation` 属性动画来移动气泡和改变气泡的透明度
3. 使用 `QParallelAnimationGroup` 动画组来同时运行两个动画
![BubbleTips](ScreenShot/BubbleTips.gif)
## 13、右侧消息通知栏
[运行 Notification.py](Notification.py)
![Notification](ScreenShot/Notification.gif)
## 14、验证码
[运行 VerificationCode.py](VerificationCode.py)
1. 更新为paintEvent方式,采用上下跳动
2. 参考网上一些代码,都是采用paintEvent绘制,这里采用QLabel显示html结合字体来显示文字<br />
然后在paintEvent中绘制噪点和线条
![VerificationCode](ScreenShot/VerificationCode.gif)
## 15、人脸特征点
[运行 FacePoints.py](FacePoints.py)
PyQt 结合 Opencv 进行人脸检测;
由于直接在主线程中进行特征点获取,效率比较低
依赖文件
1. [opencv](https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv)
2. [numpy](https://www.lfd.uci.edu/~gohlke/pythonlibs/#numpy)
3. [dlib](http://dlib.net/)
1. [dlib-19.4.0.win32-py2.7.exe](Data/dlib-19.4.0.win32-py2.7.exe)
2. [dlib-19.4.0.win32-py3.4.exe](Data/dlib-19.4.0.win32-py3.4.exe)
3. [dlib-19.4.0.win32-py3.5.exe](Data/dlib-19.4.0.win32-py3.5.exe)
4. [shape-predictor-68-face-landmarks.dat.bz2](http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2)
![FacePoints](ScreenShot/FacePoints.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 375 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 617 KiB

-3
View File
@@ -1,3 +0,0 @@
pywin32
numpy
dlib
+3
View File
@@ -0,0 +1,3 @@
          微信                    支付宝
<br/>
<a href="weixin.png" alt="微信"><img src="weixin.png" height="350" width="350"></a>or<a href="zhifubao.png" alt="支付宝"><img src="zhifubao.png" height="350" width="350"></a>
View File
-8
View File
@@ -1,8 +0,0 @@
# QCalendarWidget
## 1、QSS美化日历样式
[运行 CalendarQssStyle.py](CalendarQssStyle.py)
对日历控件的部分控件进行QSS美化,顶部背景颜色和高度,上下月按钮、月份选择、年选择、菜单
![CalendarQssStyle](ScreenShot/CalendarQssStyle.gif)
-30
View File
@@ -1,30 +0,0 @@
# QChart
## 1、折线图
[运行 LineChart.py](LineChart.py)
![LineChart](ScreenShot/LineChart.png)
## 2、折线堆叠图
[运行 LineStack.py](LineStack.py)
仿照 [line-stack](http://echarts.baidu.com/demo.html#line-stack)
![LineStack](ScreenShot/LineStack.gif)
## 3、柱状堆叠图
[运行 BarStack.py](BarStack.py)
仿照 [bar-stack](http://echarts.baidu.com/demo.html#bar-stack)
![BarStack](ScreenShot/BarStack.gif)
## 4、LineChart自定义xy轴
[运行 CustomXYaxis.py](CustomXYaxis.py)
![CustomXYaxis](ScreenShot/CustomXYaxis.png)
## 5、ToolTip提示
[运行 ToolTip.py](ToolTip.py) | [运行 ToolTip2.py](ToolTip2.py)
![ToolTip](ScreenShot/ToolTip.gif) ![ToolTip2](ScreenShot/ToolTip2.gif)
-1
View File
@@ -1 +0,0 @@
PyQtChart
View File
View File
View File
View File
-12
View File
@@ -1,12 +0,0 @@
# QComboBox
## 1、Data Linkage
[Run CityLinkage.py](CityLinkage.py)
Three level linkage, data file is data.json
1. use `QComboBox`,`setModel` and `QSortFilterProxyModel` to filter
2. the filter role is `Qt::ToolTipRole`
3. can use `QColumnView` maybe like this example
![CityLinkage](ScreenShot/CityLinkage.gif)
-12
View File
@@ -1,12 +0,0 @@
# QComboBox
## 1、下拉数据关联
[运行 CityLinkage.py](CityLinkage.py)
一个省市区关联的三级联动,数据源在data.json中
1. 主要用了`QComboBox``setModel`设置一个`QSortFilterProxyModel`过滤模型
2. 并根据唯一编码过滤,为了不影响内容显示,唯一编码的角色为`ToolTipRole`
3.`QColumnView`可以实现类似效果
![CityLinkage](ScreenShot/CityLinkage.gif)
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
-9
View File
@@ -1,9 +0,0 @@
# QFileSystemModel
## 1、自定义图标
[运行 CustomIcon.py](CustomIcon.py)
1. 继承 `QFileIconProvider` 类实现自己的图标提供器
2. 重写 `def icon(self, type_info)` 方法根据文件类型返回对应的图标
![CustomIcon](ScreenShot/CustomIcon.png)
View File
-18
View File
@@ -1,18 +0,0 @@
# QListView
## 1、腾讯视频热播列表
[运行 HotPlaylist.py](HotPlaylist.py)
简单思路说明:
- 利用`QScrollArea`滚动显示,自定义的`QFlowLayout`做布局来放置自定义的Widget
- `QNetworkAccessManager`异步下载网页和图片
- `QScrollArea`滚动到底部触发下一页加载
自定义控件说明:
- 主要是多个layout和控件的结合,其中图片`QLabel`为自定义,通过`setPixmap`设置图片,重写`paintEvent`绘制底部渐变矩形框和白色文字
- 字体颜色用qss设置
- 图标利用了`QSvgWidget`显示,可以是svg 动画(如圆形加载图)
![HotPlaylist](ScreenShot/HotPlaylist.gif)
-1
View File
@@ -1 +0,0 @@
lxml
View File
View File
View File
View File
View File
View File
-11
View File
@@ -1,11 +0,0 @@
# QGraphicsDropShadowEffect
## 1、边框阴影动画
[运行 ShadowEffect.py](ShadowEffect.py)
1. 通过`setGraphicsEffect`设置控件的边框阴影
2. 继承`QGraphicsDropShadowEffect`实现增加动态属性`radius`
3. 通过`QPropertyAnimation`属性动画不断改变`radius`的值并调用`setBlurRadius`更新半径值
4. 不能对父控件使用
![ShadowEffect](ScreenShot/ShadowEffect.gif)
View File
-16
View File
@@ -1,16 +0,0 @@
# QGraphicsView
## 1、绘制世界地图
[运行 WorldMap.py](WorldMap.py)
1. 解析json数据生成 `QPolygonF`
2. 使用Ctrl+滑轮进行放大缩小
![WorldMap](ScreenShot/WorldMap.gif)
## 2、添加QWidget
[运行 AddQWidget.py](AddQWidget.py)
通过 `QGraphicsScene.addWidget` 添加自定义QWidget
![AddQWidget](ScreenShot/AddQWidget.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

View File
-18
View File
@@ -1,18 +0,0 @@
# QListView
## 1、腾讯视频热播列表
[运行 HotPlaylist.py](HotPlaylist.py)
简单思路说明:
- 利用`QScrollArea`滚动显示,`QGridLayout`做布局来放置自定义的Widget
- `QNetworkAccessManager`异步下载网页和图片
- `QScrollArea`滚动到底部触发下一页加载
自定义控件说明:
- 主要是多个layout和控件的结合,其中图片`QLabel`为自定义,通过`setPixmap`设置图片,重写`paintEvent`绘制底部渐变矩形框和白色文字
- 字体颜色用qss设置
- 图标利用了`QSvgWidget`显示,可以是svg 动画(如圆形加载图)
![HotPlaylist](ScreenShot/HotPlaylist.gif)
View File
View File
View File
View File
View File
View File
View File
-103
View File
@@ -1,103 +0,0 @@
# QLabel
## 1、图片加载显示
[运行 ShowImage.py](ShowImage.py)
通过3种方式加载图片文件和显示gif图片
1. 通过`QPixmap("xxx.jpg")`加载
2. 通过`pyrcc5`转换res.qrc为res_rc.py文件,可以直接import加载
1. 转换命令`pyrcc5 res.qrc -o res_rc.py`
2. `import res_rc`
3. 此时可以通过`QPixmap(":/images/head.jpg")`来加载
3. 通过rcc命令转成为二进制文件res.rcc
1. 转换命令`Tools/rcc.exe -binary res2.qrc -o res.rcc`
2. 这里把资源前缀修改下(/myfile),见res2.qrc文件
3. 通过`QResource.registerResource("res.rcc")`注册
4. 此时可以通过`QPixmap(":/myfile/images/head.jpg")`来加载
4. 通过xpm数组加载
1. 通过工具`Tools/Image2XPM.exe`来转换
2. 这里把转换的xpm数组直接放到py文件中当做一个变量
3. 见xpmres.py中的image_head
4. 此时可以通过`QPixmap(image_head)`来加载
5. 通过`QMovie`加载gif图片
![ShowImage](ScreenShot/ShowImage.gif)
## 2、图片旋转
[运行 ImageRotate.py](ImageRotate.py)
1. 水平翻转 `QImage.mirrored(True, False)`
2. 垂直翻转 `QImage.mirrored(False, True)`
3. 旋转90的整数倍使用`QTransform`比较友好
4. 任意角度采用`QPainter.rotate`
![ImageRotate](ScreenShot/ImageRotate.gif)
## 3、仿网页图片错位显示
[运行 ImageSlipped.py](ImageSlipped.py)
1. 设置`setMouseTracking(True)`开启鼠标跟踪
2. 重写`mouseMoveEvent`鼠标移动事件获取偏移量
3. 重写`paintEvent`事件绘制图片
![ImageSlipped](ScreenShot/ImageSlipped.gif)
## 4、显示.9格式图片(气泡)
[运行 NinePatch.py](NinePatch.py) | [运行 QtNinePatch.py](QtNinePatch.py) | [运行 QtNinePatch2.py](QtNinePatch2.py)
什么叫.9.PNG呢,这是安卓开发里面的一种特殊的图片
这种格式的图片在android 环境下具有自适应调节大小的能力。
(1)允许开发人员定义可扩展区域,当需要延伸图片以填充比图片本身更大区域时,可扩展区的内容被延展。
(2)允许开发人员定义内容显示区,用于显示文字或其他内容
目前手机QQ中很多漂亮的的聊天气泡就是.9格式的png图片
在Github开源库中搜索到两个C++版本的
1.一个是NinePatchQt https://github.com/Roninsc2/NinePatchQt
2.一个是QtNinePatch https://github.com/soramimi/QtNinePatch
### For PyQt
1、目前针对第一个库在2年前用Python参考源码重新写一个见 `Lib/NinePatch.py`
2、这次针对第二个库用Python编写的见`Lib/QtNinePatch2.py`。用C++编写的pyd版本见`Lib/QtNinePatch`目录
### 说明
1、建议优先使用pyd版本的(后续提供Python3.4 3.5 3.6 3.7 编译好的32为库文件),也可以自行编译,编译步骤见下文。
2、其次可以使用Python写的第二个版本`Lib/QtNinePatch2.py`(个人觉得方便调用)
3、最后再考虑第一个版本吧
4、以上为个人意见,两个C++版本的写法不一样,但是核心算法应该是类似的。
### 自行编译
1、首先要安装好Qt、PyQt5、编译安装对应的sip、对应的VC++编译工具
2、用Qt Creator 打开pro文件进行编译
3、进入源码中的sip文件夹
4、修改`configure.py`文件
```python
# 这里是你的VC版本和对应的Qt目录中的文件夹
config.platform = "win32-msvc2010"
qt_path = 'D:/soft/Qt/Qt5.5.1/5.5/msvc2010'
```
5、`python configure.py`
![NinePatchImage](ScreenShot/NinePatchImage.gif)
### 5、圆形图片
[运行 CircleImage.py](CircleImage.py)
使用`QPainter``setClipPath`方法结合`QPainterPath`对图片进行裁剪从而实现圆形图片。
![CircleImage](ScreenShot/CircleImage.png)
View File
View File
-87
View File
@@ -1,87 +0,0 @@
# QListView
## 1. Custom Widget Item
[Run CustomWidgetItem.py](CustomWidgetItem.py)
use `setIndexWidget(QModelIndex, QWidget)` to set custom `QWidget`
![CustomWidgetItem](ScreenShot/CustomWidgetItem.png)
## 2. Custom Widget Sort Item
[Run CustomWidgetSortItem.py](CustomWidgetSortItem.py)
1. set QListView proxy model, use `QSortFilterProxyModel`
2. rewrite `lessThan` method to sort
![CustomWidgetSortItem](ScreenShot/CustomWidgetSortItem.gif)
## 3, Custom Role And Sort
[Run SortItemByRole.py](SortItemByRole.py)
Demand:
1. 5 categories(Tang, Song, Yuan, Ming, Qing) and Unclassified
2. selected Tang, the result is Tang, Song, Yuan, Ming, Qing, Unclassified
3. selected Song, the result is Song, Tang, Yuan, Ming, Qing, Unclassified
4. selected Yuan, the result is Yuan, Tang, Song, Ming, Qing, Unclassified
5. Cancel sorting then Restore, like: Unclassified, Tang, Tang, Ming, Qing, Unclassified, Song, Yuan, Unclassified
Method:
1. define `IdRole = Qt.UserRole + 1` Used to restore default sort
2. define `ClassifyRole = Qt.UserRole + 2` Used for sorting by sorting number
3. define 5 classify id
```python
NameDict = {
'Tang': ['Tang', 0],
'Song': ['Song', 1],
'Yuan': ['Yuan', 2],
'Ming': ['Ming', 3],
'Qing': ['Qing', 4],
}
IndexDict = {
0: 'Tang',
1: 'Song',
2: 'Yuan',
3: 'Ming',
4: 'Qing',
}
```
4. item `setData(id, IdRole)` Used to restore default sort
5. item `setData(cid, ClassifyRole)` Used to record classification
6. inherit `QSortFilterProxyModel` and add `setSortIndex(self, index)` mthod, The purpose is to keep some classify always top
```python
def setSortIndex(self, index):
self._topIndex = index
```
7. inherit `QSortFilterProxyModel` and rewrite `lessThan` mthod, if classify id is equal to top id, then modify it -1
```python
if self.sortRole() == ClassifyRole and \
source_left.column() == self.sortColumn() and \
source_right.column() == self.sortColumn():
# get classify id
leftIndex = source_left.data(ClassifyRole)
rightIndex = source_right.data(ClassifyRole)
# AscendingOrder
if self.sortOrder() == Qt.AscendingOrder:
# keep always top
if leftIndex == self._topIndex:
leftIndex = -1
if rightIndex == self._topIndex:
rightIndex = -1
return leftIndex < rightIndex
```
8. restore default sort
```python
self.fmodel.setSortRole(IdRole)
self.fmodel.sort(0)
```
9. sort by classify id, must reset `setSortRole` to other
```python
self.fmodel.setSortIndex(1)
self.fmodel.setSortRole(IdRole)
self.fmodel.setSortRole(ClassifyRole)
self.fmodel.sort(0)
```
![SortItemByRole](ScreenShot/SortItemByRole.gif)
-87
View File
@@ -1,87 +0,0 @@
# QListView
## 1、显示自定义Widget
[运行 CustomWidgetItem.py](CustomWidgetItem.py)
通过设置 `setIndexWidget(QModelIndex, QWidget)` 可以设置自定义 `QWidget`
![CustomWidgetItem](ScreenShot/CustomWidgetItem.png)
## 2、显示自定义Widget并排序
[运行 CustomWidgetSortItem.py](CustomWidgetSortItem.py)
1. 对QListView设置代理 `QSortFilterProxyModel`
2. 重写model的 `lessThan` 方法进行排序
![CustomWidgetSortItem](ScreenShot/CustomWidgetSortItem.gif)
## 3、自定义角色排序
[运行 SortItemByRole.py](SortItemByRole.py)
需求:
1. 5种分类(唐、宋、元、明、清) 和 未分类
2. 选中唐则按照 唐、宋、元、明、清、未分类排序
3. 选中宋则按照 宋、唐、元、明、清、未分类排序
4. 选中元则按照 元、唐、宋、明、清、未分类排序
5. 取消排序则恢复到加载时候顺序,如:未分类、唐、唐、明、清、未分类、宋、元、未分类
思路:
1. 定义`IdRole = Qt.UserRole + 1` 用于恢复默认排序
2. 定义`ClassifyRole = Qt.UserRole + 2` 用于按照分类序号排序
3. 定义5种分类的id
```python
NameDict = {
'唐': ['Tang', 0],
'宋': ['Song', 1],
'元': ['Yuan', 2],
'明': ['Ming', 3],
'清': ['Qing', 4],
}
IndexDict = {
0: '唐',
1: '宋',
2: '元',
3: '明',
4: '清',
}
```
4. item设置 `setData(id, IdRole)` 用于恢复默认排序
5. item设置 `setData(cid, ClassifyRole)` 用于标识该item的分类
6. 继承 `QSortFilterProxyModel` 增加 `setSortIndex(self, index)` 方法, 目的在于记录要置顶(不参与排序)的分类ID
```python
def setSortIndex(self, index):
self._topIndex = index
```
7. 继承 `QSortFilterProxyModel` 重写 `lessThan` 方法, 判断分类ID是否等于要置顶的ID, 如果是则修改为-1, 这样就永远在最前面
```python
if self.sortRole() == ClassifyRole and \
source_left.column() == self.sortColumn() and \
source_right.column() == self.sortColumn():
# 获取左右两个的分类
leftIndex = source_left.data(ClassifyRole)
rightIndex = source_right.data(ClassifyRole)
# 升序
if self.sortOrder() == Qt.AscendingOrder:
# 保持在最前面
if leftIndex == self._topIndex:
leftIndex = -1
if rightIndex == self._topIndex:
rightIndex = -1
return leftIndex < rightIndex
```
8. 恢复默认排序
```python
self.fmodel.setSortRole(IdRole) # 必须设置排序角色为ID
self.fmodel.sort(0) # 排序第一列按照ID升序
```
9. 根据分类排序, 这里要注意要先通过 `setSortRole` 设置其它角色再设置目标角色
```python
self.fmodel.setSortIndex(1)
self.fmodel.setSortRole(IdRole)
self.fmodel.setSortRole(ClassifyRole)
self.fmodel.sort(0)
```
![SortItemByRole](ScreenShot/SortItemByRole.gif)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 KiB

-149
View File
@@ -1,149 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2018年12月27日
@author: Irony
@site: https://pyqt5.com , https://github.com/892768447
@email: 892768447@qq.com
@file: QListView.SortItemByRole
@description:
"""
from random import choice
from PyQt5.QtCore import QSortFilterProxyModel, Qt
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QListView, QPushButton
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = "Copyright (c) 2018 Irony"
__Version__ = "Version 1.0"
class SortFilterProxyModel(QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(SortFilterProxyModel, self).__init__(*args, **kwargs)
self._topIndex = 0
def setSortIndex(self, index):
self._topIndex = index
print('在最前面的序号为:', index)
def lessThan(self, source_left, source_right):
if not source_left.isValid() or not source_right.isValid():
return False
if self.sortRole() == ClassifyRole and \
source_left.column() == self.sortColumn() and \
source_right.column() == self.sortColumn():
# 获取左右两个的分类
leftIndex = source_left.data(ClassifyRole)
rightIndex = source_right.data(ClassifyRole)
# 升序
if self.sortOrder() == Qt.AscendingOrder:
# 保持在最前面
if leftIndex == self._topIndex:
leftIndex = -1
if rightIndex == self._topIndex:
rightIndex = -1
return leftIndex < rightIndex
return super(SortFilterProxyModel, self).lessThan(source_left, source_right)
NameDict = {
'': ['Tang', 0],
'': ['Song', 1],
'': ['Yuan', 2],
'': ['Ming', 3],
'': ['Qing', 4],
}
IndexDict = {
0: '',
1: '',
2: '',
3: '',
4: '',
}
IdRole = Qt.UserRole + 1 # 用于恢复排序
ClassifyRole = Qt.UserRole + 2 # 用于按照分类序号排序
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
self.resize(600, 400)
layout = QVBoxLayout(self)
self.listView = QListView(self)
self.listView.setEditTriggers(QListView.NoEditTriggers)
layout.addWidget(self.listView)
layout.addWidget(QPushButton('恢复默认顺序', self, clicked=self.restoreSort))
layout.addWidget(QPushButton('', self, clicked=self.sortByClassify))
layout.addWidget(QPushButton('', self, clicked=self.sortByClassify))
layout.addWidget(QPushButton('', self, clicked=self.sortByClassify))
layout.addWidget(QPushButton('', self, clicked=self.sortByClassify))
layout.addWidget(QPushButton('', self, clicked=self.sortByClassify))
self._initItems()
def restoreSort(self):
# 恢复默认排序
self.fmodel.setSortRole(IdRole) # 必须设置排序角色为ID
self.fmodel.sort(0) # 排序第一列按照ID升序
def sortByClassify(self):
self.fmodel.setSortIndex(NameDict.get(
self.sender().text(), ['', 100])[1])
# self.restoreSort()
self.fmodel.setSortRole(IdRole)
# 按照给定的分类排序(这里注意还要按照把给定分类的放在最前面)
self.fmodel.setSortRole(ClassifyRole)
self.fmodel.sort(0)
def _initItems(self):
# 初始化Items
self.dmodel = QStandardItemModel(self.listView)
self.fmodel = SortFilterProxyModel(self.listView)
self.fmodel.setSourceModel(self.dmodel)
self.listView.setModel(self.fmodel)
keys = list(NameDict.keys())
print(keys) # ['清', '元', '唐', '明', '宋']
classifies = [v[1] for v in NameDict.values()]
for i in range(5):
# 添加5个100, 用于模拟没有分类, 排序的时候就显示在最后面
classifies.append(100)
print(classifies) # [4, 2, 0, 3, 1, 100, 100, 100, 100, 100]
# 生成50个Item
for i in range(50):
# name = keys[i % 4] # 随机取一个朝代
item = QStandardItem()
# 设置ID角色
item.setData(i, IdRole)
# 设置分类角色
c = choice(classifies)
item.setData(c, ClassifyRole)
# 设置显示内容
item.setText('Name: {}\t\tId: {}\t\tClassify: {}'.format(
IndexDict.get(c, '其它'), i, c))
self.dmodel.appendRow(item)
if __name__ == '__main__':
import sys
import cgitb
sys.excepthook = cgitb.enable(1, None, 5, '')
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())
Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

View File
-39
View File
@@ -1,39 +0,0 @@
# QListView
## 1、删除自定义Item
[运行 DeleteCustomItem.py](DeleteCustomItem.py)
1. 删除item时先要通过`QListWidget.indexFromItem(item).row()`得到它的行数
2. 通过`takeItem`函数取出该Item并删除掉,`item = self.listWidget.takeItem(row)`
3. 移除item对应的自定义控件`self.listWidget.removeItemWidget(item)`
4. 如果是清空所有Item,可以通过循环删除,但是删除的时候行号一直是0即可,原因和删除list数组一样。
![CustomWidgetItem](ScreenShot/DeleteCustomItem.gif)
## 2、自定义可拖拽Item
[运行 DragDrop.py](DragDrop.py)
![CustomWidgetSortItem](ScreenShot/DragDrop.gif)
## 3、腾讯视频热播列表
[运行 HotPlaylist.py](HotPlaylist.py)
简单思路说明:
- 利用`QListWidget`设置一些特殊的参数达到可以横向自动显示
- `QNetworkAccessManager`异步下载网页和图片
- 滚动到底部触发下一页加载
自定义控件说明:
- 主要是多个layout和控件的结合,其中图片`QLabel`为自定义,通过`setPixmap`设置图片,重写`paintEvent`绘制底部渐变矩形框和白色文字
- 字体颜色用qss设置
- 图标利用了`QSvgWidget`显示,可以是svg 动画(如圆形加载图)
`QListWidget`的参数设置
1. `setFlow(QListWidget.LeftToRight)`
2. `setWrapping(True)`
3. `setResizeMode(QListWidget.Adjust)`
![HotPlaylist](ScreenShot/HotPlaylist.gif)
View File
View File
-76
View File
@@ -1,76 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Created on 2018年1月17日
@author: Irony."[讽刺]
@site: https://pyqt5.com , https://github.com/892768447
@email: 892768447@qq.com
@file: CustomBtnIcon
@description:
'''
__Author__ = "By: Irony.\"[讽刺]\nQQ: 892768447\nEmail: 892768447@qq.com"
__Copyright__ = "Copyright (c) 2018 Irony.\"[讽刺]"
__Version__ = "Version 1.0"
import sys
from PyQt5.QtWidgets import QApplication, QMessageBox
app = QApplication(sys.argv)
app.setStyleSheet('''QDialogButtonBox {
dialogbuttonbox-buttons-have-icons: 1;
dialog-ok-icon: url(Data/icons/Ok.png);
dialog-open-icon: url(Data/icons/Open.png);
dialog-save-icon: url(Data/icons/Save.png);
dialog-cancel-icon: url(Data/icons/Cancel.png);
}
#qt_msgbox_label {
color: red;
background: green;
}
#qt_msgboxex_icon_label {
background: red;
}
QMessageBox {
background: black;
messagebox-information-icon: url(Data/icons/Close.png);
}
QMessageBox QPushButton {
padding: 2px;
border-radius: 5px;
background: white;
}
QMessageBox QPushButton:hover {
background: darkCyan;
}
QMessageBox QPushButton[text="Reset"] {
background: red;
}
QMessageBox QPushButton[text="Apply"] {
background: cyan;
qproperty-icon: url(Data/icons/Apply.png);
}
''')
QMessageBox.information(None, "information", "消息",
QMessageBox.Apply |
QMessageBox.Cancel |
QMessageBox.Close |
QMessageBox.Discard |
QMessageBox.Help |
QMessageBox.No |
QMessageBox.Ok |
QMessageBox.Open |
QMessageBox.Reset |
QMessageBox.Save |
QMessageBox.Yes)
sys.exit()
View File
-14
View File
@@ -1,14 +0,0 @@
# QMessageBox
## 1、消息对话框倒计时关闭
[运行 CountDownClose.py](CountDownClose.py)
1. 通过继承`QMessageBox`实现倒计时关闭的对话框
1. `QTimer`定时器关闭窗口
![CountDownClose](ScreenShot/CountDownClose.gif)
## 2、自定义图标等
[运行 CustomColorIcon.py](CustomColorIcon.py)
![CustomColorIcon](ScreenShot/CustomColorIcon.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File
View File
View File
View File
View File
-32
View File
@@ -1,32 +0,0 @@
# QProgressBar
## 1、常规样式美化
[运行 SimpleStyle.py](SimpleStyle.py)
主要改变背景颜色、高度、边框、块颜色、边框、圆角
![SimpleStyle](ScreenShot/SimpleStyle.gif)
## 2、圆圈进度条
[运行 RoundProgressBar.py](RoundProgressBar.py)
![RoundProgressBar](ScreenShot/RoundProgressBar.gif)
## 3、百分比进度条
[运行 PercentProgressBar.py](PercentProgressBar.py)
![PercentProgressBar](ScreenShot/PercentProgressBar.gif)
## 4、Metro进度条
[运行 MetroCircleProgress.py](MetroCircleProgress.py)
![MetroCircleProgress](ScreenShot/MetroCircleProgress.gif)
## 5、水波纹进度条
[运行 WaterProgressBar.py](WaterProgressBar.py)
1. 利用正弦函数根据0-width的范围计算y坐标
2. 利用 `QPainterPath` 矩形或者圆形作为背景
3. 用 `QPainterPath` 把y坐标用 `lineTo` 连接起来形成一个U字形+上方波浪的闭合区间
![WaterProgressBar](ScreenShot/WaterProgressBar.gif)
-1
View File
@@ -1 +0,0 @@
# QPropertyAnimation
-36
View File
@@ -1,36 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2018年12月27日
@author: Irony
@site: https://pyqt5.com , https://github.com/892768447
@email: 892768447@qq.com
@file: TabBarStyle
@description:
"""
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QProxyStyle
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = "Copyright (c) 2018 Irony"
__Version__ = "Version 1.0"
class TabBarStyle(QProxyStyle):
def sizeFromContents(self, types, option, size, widget):
size = super(TabBarStyle, self).sizeFromContents(
types, option, size, widget)
if types == self.CT_TabBarTab:
size.transpose()
return size
def drawControl(self, element, option, painter, widget):
if element == self.CE_TabBarTabLabel:
painter.drawText(option.rect, Qt.AlignCenter, option.text)
return
super(TabBarStyle, self).drawControl(element, option, painter, widget)
View File
-10
View File
@@ -1,10 +0,0 @@
# QProxyStyle
## 1、QTabWidget Tab文字方向
[运行 TabTextDirection.py](TabTextDirection.py)
1. 通过 `app.setStyle(TabBarStyle())` 设置代理样式
2. `sizeFromContents` 转置size
3. `drawControl` 绘制文字
![TabTextDirection](ScreenShot/TabTextDirection.png)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

-51
View File
@@ -1,51 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on 2018年12月27日
@author: Irony
@site: https://pyqt5.com , https://github.com/892768447
@email: 892768447@qq.com
@file: TestTabWidget
@description:
"""
from PyQt5.QtWidgets import QTabWidget, QLabel, QWidget, QGridLayout
from Lib.TabBarStyle import TabBarStyle
__Author__ = """By: Irony
QQ: 892768447
Email: 892768447@qq.com"""
__Copyright__ = "Copyright (c) 2018 Irony"
__Version__ = "Version 1.0"
class TabWidget(QTabWidget):
def __init__(self, *args, **kwargs):
super(TabWidget, self).__init__(*args, **kwargs)
for i in range(10):
self.addTab(QLabel('Tab' + str(i)), str(i))
class Window(QWidget):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
layout = QGridLayout(self)
layout.addWidget(TabWidget(self, tabPosition=TabWidget.North), 0, 1)
layout.addWidget(TabWidget(self, tabPosition=TabWidget.South), 2, 1)
layout.addWidget(TabWidget(self, tabPosition=TabWidget.West), 1, 0)
layout.addWidget(TabWidget(self, tabPosition=TabWidget.East), 1, 2)
if __name__ == '__main__':
import sys
from PyQt5.QtWidgets import QApplication
app = QApplication(sys.argv)
app.setStyle(TabBarStyle())
w = Window()
w.show()
sys.exit(app.exec_())
View File
-22
View File
@@ -1,22 +0,0 @@
# QPushButton
## 1、普通样式
[运行 NormalStyle.py](NormalStyle.py)
主要改变背景颜色、鼠标按下颜色、鼠标悬停颜色、圆角、圆形、文字颜色
![NormalStyle](ScreenShot/NormalStyle.gif)
## 2、按钮底部线条进度
[运行 BottomLineProgress.py](BottomLineProgress.py)
在按钮下方画一条线,根据百分值绘制
![BottomLineProgress](ScreenShot/BottomLineProgress.gif)
## 3、按钮文字旋转进度
[运行 FontRotate.py](FontRotate.py)
利用字体,使用FontAwesome字体来显示一个圆形进度条,然后利用旋转动画
![FontRotate](ScreenShot/FontRotate.gif)
View File
View File

Some files were not shown because too many files have changed in this diff Show More