Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf1139a467 |
@@ -129,4 +129,3 @@ tmp
|
||||
.pydevproject
|
||||
.README.md.html
|
||||
README.md.html
|
||||
shape_predictor_68_face_landmarks.dat
|
||||
@@ -1 +0,0 @@
|
||||
*.xml
|
||||
@@ -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>
|
||||
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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软件)
|
||||
|
||||

|
||||

|
||||
|
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
|
||||
@@ -1,141 +0,0 @@
|
||||
# Demo
|
||||
|
||||
## 1、重启窗口Widget
|
||||
[运行 RestartWindow.py](RestartWindow.py)
|
||||
|
||||
利用类变量对窗口的变量进行引用,防止被回收(导致窗口一闪而过),重启时先显示新窗口后关闭自己
|
||||
|
||||

|
||||
|
||||
## 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`,鼠标离开事件,用于窗口暂时显示后自动隐藏效果
|
||||
|
||||

|
||||
|
||||
## 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样式(未解决)
|
||||
|
||||

|
||||
|
||||
|
||||
## 4、简单跟随其它窗口
|
||||
[运行 FollowWindow.py](FollowWindow.py)
|
||||
|
||||
1. 利用win32gui模块获取目标窗口的句柄
|
||||
1. 通过句柄获取目标窗口的大小位置,并设置自己的位置
|
||||
1. 当句柄失效时关闭自己
|
||||
1. 主要是检测时间,在10毫秒以下很流畅
|
||||
|
||||

|
||||
|
||||
|
||||
## 5、简单探测窗口和放大截图
|
||||
[运行 ProbeWindow.py](ProbeWindow.py)
|
||||
|
||||
1. 利用`win32gui`模块获取鼠标所在位置的窗口大小(未去掉边框)和rgb颜色
|
||||
1. 利用一个全屏的全透明鼠标穿透的窗口(目的在于绘制矩形框和截图)
|
||||
|
||||

|
||||
|
||||
|
||||
## 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`事件拦截边框的系统边框的显示,并返回各个方向
|
||||
|
||||

|
||||
|
||||
## 7、右下角弹出框
|
||||
[运行 WindowNotify.py](WindowNotify.py)
|
||||
|
||||

|
||||
|
||||
## 8、程序重启
|
||||
[运行 AutoRestart.py](AutoRestart.py)
|
||||
|
||||

|
||||
|
||||
## 9、自定义属性
|
||||
[运行 CustomProperties.py](CustomProperties.py)
|
||||
|
||||

|
||||
|
||||
## 10、调用截图DLL
|
||||
[运行 ScreenShotDll.py](ScreenShotDll.py)
|
||||
|
||||

|
||||
|
||||
## 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` 动画组来同时运行两个动画
|
||||
|
||||

|
||||
|
||||
## 13、右侧消息通知栏
|
||||
[运行 Notification.py](Notification.py)
|
||||
|
||||

|
||||
|
||||
## 14、验证码
|
||||
[运行 VerificationCode.py](VerificationCode.py)
|
||||
|
||||
1. 更新为paintEvent方式,采用上下跳动
|
||||
2. 参考网上一些代码,都是采用paintEvent绘制,这里采用QLabel显示html结合字体来显示文字<br />
|
||||
然后在paintEvent中绘制噪点和线条
|
||||
|
||||

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

|
||||
|
Before Width: | Height: | Size: 375 KiB |
|
Before Width: | Height: | Size: 617 KiB |
@@ -1,3 +0,0 @@
|
||||
pywin32
|
||||
numpy
|
||||
dlib
|
||||
@@ -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>
|
||||
@@ -1,8 +0,0 @@
|
||||
# QCalendarWidget
|
||||
|
||||
## 1、QSS美化日历样式
|
||||
[运行 CalendarQssStyle.py](CalendarQssStyle.py)
|
||||
|
||||
对日历控件的部分控件进行QSS美化,顶部背景颜色和高度,上下月按钮、月份选择、年选择、菜单
|
||||
|
||||

|
||||
@@ -1,30 +0,0 @@
|
||||
# QChart
|
||||
|
||||
## 1、折线图
|
||||
[运行 LineChart.py](LineChart.py)
|
||||
|
||||

|
||||
|
||||
## 2、折线堆叠图
|
||||
[运行 LineStack.py](LineStack.py)
|
||||
|
||||
仿照 [line-stack](http://echarts.baidu.com/demo.html#line-stack)
|
||||
|
||||

|
||||
|
||||
## 3、柱状堆叠图
|
||||
[运行 BarStack.py](BarStack.py)
|
||||
|
||||
仿照 [bar-stack](http://echarts.baidu.com/demo.html#bar-stack)
|
||||
|
||||

|
||||
|
||||
## 4、LineChart自定义xy轴
|
||||
[运行 CustomXYaxis.py](CustomXYaxis.py)
|
||||
|
||||

|
||||
|
||||
## 5、ToolTip提示
|
||||
[运行 ToolTip.py](ToolTip.py) | [运行 ToolTip2.py](ToolTip2.py)
|
||||
|
||||
 
|
||||
@@ -1 +0,0 @@
|
||||
PyQtChart
|
||||
@@ -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
|
||||
|
||||

|
||||
@@ -1,12 +0,0 @@
|
||||
# QComboBox
|
||||
|
||||
## 1、下拉数据关联
|
||||
[运行 CityLinkage.py](CityLinkage.py)
|
||||
|
||||
一个省市区关联的三级联动,数据源在data.json中
|
||||
|
||||
1. 主要用了`QComboBox`的`setModel`设置一个`QSortFilterProxyModel`过滤模型
|
||||
2. 并根据唯一编码过滤,为了不影响内容显示,唯一编码的角色为`ToolTipRole`
|
||||
3. 用`QColumnView`可以实现类似效果
|
||||
|
||||

|
||||
@@ -1,9 +0,0 @@
|
||||
# QFileSystemModel
|
||||
|
||||
## 1、自定义图标
|
||||
[运行 CustomIcon.py](CustomIcon.py)
|
||||
|
||||
1. 继承 `QFileIconProvider` 类实现自己的图标提供器
|
||||
2. 重写 `def icon(self, type_info)` 方法根据文件类型返回对应的图标
|
||||
|
||||

|
||||
@@ -1,18 +0,0 @@
|
||||
# QListView
|
||||
|
||||
## 1、腾讯视频热播列表
|
||||
[运行 HotPlaylist.py](HotPlaylist.py)
|
||||
|
||||
简单思路说明:
|
||||
|
||||
- 利用`QScrollArea`滚动显示,自定义的`QFlowLayout`做布局来放置自定义的Widget
|
||||
- `QNetworkAccessManager`异步下载网页和图片
|
||||
- `QScrollArea`滚动到底部触发下一页加载
|
||||
|
||||
自定义控件说明:
|
||||
|
||||
- 主要是多个layout和控件的结合,其中图片`QLabel`为自定义,通过`setPixmap`设置图片,重写`paintEvent`绘制底部渐变矩形框和白色文字
|
||||
- 字体颜色用qss设置
|
||||
- 图标利用了`QSvgWidget`显示,可以是svg 动画(如圆形加载图)
|
||||
|
||||

|
||||
@@ -1 +0,0 @@
|
||||
lxml
|
||||
@@ -1,11 +0,0 @@
|
||||
# QGraphicsDropShadowEffect
|
||||
|
||||
## 1、边框阴影动画
|
||||
[运行 ShadowEffect.py](ShadowEffect.py)
|
||||
|
||||
1. 通过`setGraphicsEffect`设置控件的边框阴影
|
||||
2. 继承`QGraphicsDropShadowEffect`实现增加动态属性`radius`
|
||||
3. 通过`QPropertyAnimation`属性动画不断改变`radius`的值并调用`setBlurRadius`更新半径值
|
||||
4. 不能对父控件使用
|
||||
|
||||

|
||||
@@ -1,16 +0,0 @@
|
||||
# QGraphicsView
|
||||
|
||||
## 1、绘制世界地图
|
||||
[运行 WorldMap.py](WorldMap.py)
|
||||
|
||||
1. 解析json数据生成 `QPolygonF`
|
||||
2. 使用Ctrl+滑轮进行放大缩小
|
||||
|
||||

|
||||
|
||||
## 2、添加QWidget
|
||||
[运行 AddQWidget.py](AddQWidget.py)
|
||||
|
||||
通过 `QGraphicsScene.addWidget` 添加自定义QWidget
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 460 KiB |
|
Before Width: | Height: | Size: 6.9 KiB |
@@ -1,18 +0,0 @@
|
||||
# QListView
|
||||
|
||||
## 1、腾讯视频热播列表
|
||||
[运行 HotPlaylist.py](HotPlaylist.py)
|
||||
|
||||
简单思路说明:
|
||||
|
||||
- 利用`QScrollArea`滚动显示,`QGridLayout`做布局来放置自定义的Widget
|
||||
- `QNetworkAccessManager`异步下载网页和图片
|
||||
- `QScrollArea`滚动到底部触发下一页加载
|
||||
|
||||
自定义控件说明:
|
||||
|
||||
- 主要是多个layout和控件的结合,其中图片`QLabel`为自定义,通过`setPixmap`设置图片,重写`paintEvent`绘制底部渐变矩形框和白色文字
|
||||
- 字体颜色用qss设置
|
||||
- 图标利用了`QSvgWidget`显示,可以是svg 动画(如圆形加载图)
|
||||
|
||||

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

|
||||
|
||||
## 2、图片旋转
|
||||
[运行 ImageRotate.py](ImageRotate.py)
|
||||
|
||||
1. 水平翻转 `QImage.mirrored(True, False)`
|
||||
2. 垂直翻转 `QImage.mirrored(False, True)`
|
||||
3. 旋转90的整数倍使用`QTransform`比较友好
|
||||
4. 任意角度采用`QPainter.rotate`
|
||||
|
||||

|
||||
|
||||
## 3、仿网页图片错位显示
|
||||
[运行 ImageSlipped.py](ImageSlipped.py)
|
||||
|
||||
1. 设置`setMouseTracking(True)`开启鼠标跟踪
|
||||
2. 重写`mouseMoveEvent`鼠标移动事件获取偏移量
|
||||
3. 重写`paintEvent`事件绘制图片
|
||||
|
||||

|
||||
|
||||
## 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`
|
||||
|
||||

|
||||
|
||||
### 5、圆形图片
|
||||
[运行 CircleImage.py](CircleImage.py)
|
||||
|
||||
使用`QPainter`的`setClipPath`方法结合`QPainterPath`对图片进行裁剪从而实现圆形图片。
|
||||
|
||||

|
||||
@@ -1,87 +0,0 @@
|
||||
# QListView
|
||||
|
||||
## 1. Custom Widget Item
|
||||
[Run CustomWidgetItem.py](CustomWidgetItem.py)
|
||||
|
||||
use `setIndexWidget(QModelIndex, QWidget)` to set custom `QWidget`
|
||||
|
||||

|
||||
|
||||
## 2. Custom Widget Sort Item
|
||||
[Run CustomWidgetSortItem.py](CustomWidgetSortItem.py)
|
||||
|
||||
1. set QListView proxy model, use `QSortFilterProxyModel`
|
||||
2. rewrite `lessThan` method to sort
|
||||
|
||||

|
||||
|
||||
## 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)
|
||||
```
|
||||
|
||||

|
||||
@@ -1,87 +0,0 @@
|
||||
# QListView
|
||||
|
||||
## 1、显示自定义Widget
|
||||
[运行 CustomWidgetItem.py](CustomWidgetItem.py)
|
||||
|
||||
通过设置 `setIndexWidget(QModelIndex, QWidget)` 可以设置自定义 `QWidget`
|
||||
|
||||

|
||||
|
||||
## 2、显示自定义Widget并排序
|
||||
[运行 CustomWidgetSortItem.py](CustomWidgetSortItem.py)
|
||||
|
||||
1. 对QListView设置代理 `QSortFilterProxyModel`
|
||||
2. 重写model的 `lessThan` 方法进行排序
|
||||
|
||||

|
||||
|
||||
## 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)
|
||||
```
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 312 KiB |
@@ -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_())
|
||||
|
Before Width: | Height: | Size: 6.9 KiB |
@@ -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数组一样。
|
||||
|
||||

|
||||
|
||||
## 2、自定义可拖拽Item
|
||||
[运行 DragDrop.py](DragDrop.py)
|
||||
|
||||

|
||||
|
||||
## 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)`
|
||||
|
||||

|
||||
@@ -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()
|
||||
@@ -1,14 +0,0 @@
|
||||
# QMessageBox
|
||||
|
||||
## 1、消息对话框倒计时关闭
|
||||
[运行 CountDownClose.py](CountDownClose.py)
|
||||
|
||||
1. 通过继承`QMessageBox`实现倒计时关闭的对话框
|
||||
1. `QTimer`定时器关闭窗口
|
||||
|
||||

|
||||
|
||||
## 2、自定义图标等
|
||||
[运行 CustomColorIcon.py](CustomColorIcon.py)
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 15 KiB |
@@ -1,32 +0,0 @@
|
||||
# QProgressBar
|
||||
|
||||
## 1、常规样式美化
|
||||
[运行 SimpleStyle.py](SimpleStyle.py)
|
||||
|
||||
主要改变背景颜色、高度、边框、块颜色、边框、圆角
|
||||
|
||||

|
||||
|
||||
## 2、圆圈进度条
|
||||
[运行 RoundProgressBar.py](RoundProgressBar.py)
|
||||
|
||||

|
||||
|
||||
## 3、百分比进度条
|
||||
[运行 PercentProgressBar.py](PercentProgressBar.py)
|
||||
|
||||

|
||||
|
||||
## 4、Metro进度条
|
||||
[运行 MetroCircleProgress.py](MetroCircleProgress.py)
|
||||
|
||||

|
||||
|
||||
## 5、水波纹进度条
|
||||
[运行 WaterProgressBar.py](WaterProgressBar.py)
|
||||
|
||||
1. 利用正弦函数根据0-width的范围计算y坐标
|
||||
2. 利用 `QPainterPath` 矩形或者圆形作为背景
|
||||
3. 用 `QPainterPath` 把y坐标用 `lineTo` 连接起来形成一个U字形+上方波浪的闭合区间
|
||||
|
||||

|
||||
@@ -1 +0,0 @@
|
||||
# QPropertyAnimation
|
||||
@@ -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)
|
||||
@@ -1,10 +0,0 @@
|
||||
# QProxyStyle
|
||||
|
||||
## 1、QTabWidget Tab文字方向
|
||||
[运行 TabTextDirection.py](TabTextDirection.py)
|
||||
|
||||
1. 通过 `app.setStyle(TabBarStyle())` 设置代理样式
|
||||
2. `sizeFromContents` 转置size
|
||||
3. `drawControl` 绘制文字
|
||||
|
||||

|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
@@ -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_())
|
||||
@@ -1,22 +0,0 @@
|
||||
# QPushButton
|
||||
|
||||
## 1、普通样式
|
||||
[运行 NormalStyle.py](NormalStyle.py)
|
||||
|
||||
主要改变背景颜色、鼠标按下颜色、鼠标悬停颜色、圆角、圆形、文字颜色
|
||||
|
||||

|
||||
|
||||
## 2、按钮底部线条进度
|
||||
[运行 BottomLineProgress.py](BottomLineProgress.py)
|
||||
|
||||
在按钮下方画一条线,根据百分值绘制
|
||||
|
||||

|
||||
|
||||
## 3、按钮文字旋转进度
|
||||
[运行 FontRotate.py](FontRotate.py)
|
||||
|
||||
利用字体,使用FontAwesome字体来显示一个圆形进度条,然后利用旋转动画
|
||||
|
||||

|
||||