v1.0.0 完成。软件功能不多,应该没什么 bug
8
.gitignore
vendored
@@ -113,3 +113,11 @@ dmypy.json
|
|||||||
|
|
||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
*.mp4
|
||||||
|
src/moduels/HandRight/
|
||||||
|
src/build/
|
||||||
|
src/dist/
|
||||||
|
src/output/
|
||||||
84
README.md
@@ -1,37 +1,73 @@
|
|||||||
# QuickHand
|
#  Quick Hand
|
||||||
|
|
||||||
#### 介绍
|
## 📝 介绍
|
||||||
快速的仿手写文字的图片生成器。基于 https://github.com/Gsllchb/Handright/ 的 GUI。
|
快速的仿手写文字的图片生成器。基于 https://github.com/Gsllchb/Handright/ 的 GUI。
|
||||||
|
|
||||||
#### 软件架构
|
它是开源的,你可以免费使用它。下载请到 release 界面。
|
||||||
软件架构说明
|
|
||||||
|
目前在两个仓库更新:
|
||||||
|
|
||||||
|
- https://github.com/HaujetZhao/QuickHand
|
||||||
|
- https://gitee.com/haujet/QuickHand
|
||||||
|
|
||||||
|
关于软件参数的帮助,你可以参照:https://github.com/Gsllchb/Handright/blob/master/docs/tutorial.md
|
||||||
|
|
||||||
|
界面预览:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
#### 安装教程
|
|
||||||
|
|
||||||
1. xxxx
|
## 🔮 使用说明
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### 使用说明
|
原理:首先,在水平位置、竖直位置和字体大小三个自由度上,对每个字的整体做随机扰动。随后,在水平位置、竖直位置和旋转角度三个自由度上,对每个字的每个笔画做随机扰动。
|
||||||
|
|
||||||
1. xxxx
|
Windows 64 位系统的用户:下载软件发行版压缩包,解压,双击运行里面的 `QuickHand.exe` 就可以运行了。
|
||||||
2. xxxx
|
|
||||||
3. xxxx
|
|
||||||
|
|
||||||
#### 参与贡献
|
- 请将需要用到的字体文件(ttf 格式)放到软件根目录的 `fonts` 文件夹中
|
||||||
|
- 请将需要用到的背景图片放到软件根目录的 `backgrounds` 文件夹中
|
||||||
|
|
||||||
1. Fork 本仓库
|
排版关系参考:
|
||||||
2. 新建 Feat_xxx 分支
|
|
||||||
3. 提交代码
|

|
||||||
4. 新建 Pull Request
|
|
||||||
|
## 🔨 参与贡献
|
||||||
|
|
||||||
|
作者只有 Win10 64 位系统。如果你用的是其它系统电脑,比如 windows 32 位、MacOS、Linux,你可以参与志愿打包。
|
||||||
|
|
||||||
|
只要安装上 requirements.txt 中的 python 依赖包,确保源码能跑起来,再用 pyinstaller 使用以下的命令将 QuickHand.py 打包:
|
||||||
|
|
||||||
|
```
|
||||||
|
lss
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
再将:
|
||||||
|
|
||||||
|
- `backgrounds` 文件夹
|
||||||
|
- `fonts` 文件夹
|
||||||
|
- `assets` 文件夹
|
||||||
|
- `README_zh.html` 文件
|
||||||
|
- `database.db` 文件
|
||||||
|
- `icon.ico` 文件
|
||||||
|
- `sponsor.jpg` 文件
|
||||||
|
- `style.css` 文件
|
||||||
|
|
||||||
|
都复制到打包出的 QuickHand 文件夹根目录,再打包成压缩包,即可。
|
||||||
|
|
||||||
|
Linux 和 MacOS 用户可能还需要将打包出的 QuickHand 文件夹根目录内的可执行文件加上执行权限才行,并且不能用 zip 等打包格式,因为这会使得可执行权限丢失。建议使用 tar.gz 格式压缩。
|
||||||
|
|
||||||
|
MacOS 用户不能使用 `icon.ico` 图标,请手动将其转换为 `icon.icns` 格式图片,放到打包出的 QuickHand 文件夹根目录内。
|
||||||
|
|
||||||
|
## ☕ 打赏
|
||||||
|
|
||||||
|
万水千山总是情,一块几块都是情。本软件完全开源,用爱发电,如果你愿意,可以以打赏的方式支持我一下:
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
#### 码云特技
|
|
||||||
|
|
||||||
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
|
## 😀 交流
|
||||||
2. 码云官方博客 [blog.gitee.com](https://blog.gitee.com)
|
|
||||||
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解码云上的优秀开源项目
|
如果有软件方面的反馈可以提交 issues,或者加入 QQ 群:[1146626791](https://qm.qq.com/cgi-bin/qm/qr?k=DgiFh5cclAElnELH4mOxqWUBxReyEVpm&jump_from=webapi)
|
||||||
4. [GVP](https://gitee.com/gvp) 全称是码云最有价值开源项目,是码云综合评定出的优秀开源项目
|
|
||||||
5. 码云官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
|
|
||||||
6. 码云封面人物是一档用来展示码云会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
|
|
||||||
|
|||||||
BIN
assets/image-20200808220817456.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
assets/params_visualizing.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
assets/sponsor.jpg
Normal file
|
After Width: | Height: | Size: 166 KiB |
8
requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
pillow == 6.2.1
|
||||||
|
|
||||||
|
twine >= 1.8.0
|
||||||
|
setuptools >= 38.6.0
|
||||||
|
wheel
|
||||||
|
|
||||||
|
pytest
|
||||||
|
pyside2
|
||||||
147
src/QuickHand.py
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
# -*- coding: UTF-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import platform
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from PySide2.QtCore import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
from PySide2.QtSql import *
|
||||||
|
from PySide2.QtWidgets import *
|
||||||
|
|
||||||
|
from moduels.SystemTray import SystemTray # 引入托盘栏
|
||||||
|
from moduels.HandRightTab import HandRightTab
|
||||||
|
from moduels.ConfigTab import ConfigTab
|
||||||
|
from moduels.HelpTab import HelpTab
|
||||||
|
|
||||||
|
|
||||||
|
dbname = './database.db' # 存储预设的数据库名字
|
||||||
|
presetTableName = 'configPreset' # 存储预设的表单名字
|
||||||
|
preferenceTableName = 'preference'
|
||||||
|
styleFile = './style.css'
|
||||||
|
version = 'V1.0.0'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
############# 主窗口和托盘 ################
|
||||||
|
|
||||||
|
class MainWindow(QMainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.initGui()
|
||||||
|
self.loadStyleSheet()
|
||||||
|
# self.status = self.statusBar() # 状态栏
|
||||||
|
|
||||||
|
|
||||||
|
# self.setWindowState(Qt.WindowMaximized)
|
||||||
|
# sys.stdout = Stream(newText=self.onUpdateText)
|
||||||
|
|
||||||
|
def initGui(self):
|
||||||
|
# 定义中心控件为多 tab 页面
|
||||||
|
self.tabs = QTabWidget()
|
||||||
|
QApplication.quit()
|
||||||
|
self.setCentralWidget(self.tabs)
|
||||||
|
|
||||||
|
# 定义多个不同功能的 tab
|
||||||
|
self.handRightTab = HandRightTab(self, conn, presetTableName) # 主要功能的 tab
|
||||||
|
self.ConfigTab = ConfigTab(self, conn, preferenceTableName) # 配置
|
||||||
|
self.helpTab = HelpTab(version, platfm) # 帮助
|
||||||
|
|
||||||
|
self.tabs.addTab(self.handRightTab, self.tr('HandRight'))
|
||||||
|
self.tabs.addTab(self.ConfigTab, self.tr('设置'))
|
||||||
|
self.tabs.addTab(self.helpTab, self.tr('帮助'))
|
||||||
|
self.adjustSize()
|
||||||
|
|
||||||
|
# 设置图标
|
||||||
|
if platfm == 'Windows':
|
||||||
|
self.setWindowIcon(QIcon('icon.ico'))
|
||||||
|
else:
|
||||||
|
self.setWindowIcon(QIcon('icon.icns'))
|
||||||
|
self.setWindowTitle('Quick Hand')
|
||||||
|
|
||||||
|
# self.setWindowFlag(Qt.WindowStaysOnTopHint) # 始终在前台
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def loadStyleSheet(self):
|
||||||
|
pass
|
||||||
|
# global styleFile
|
||||||
|
# try:
|
||||||
|
# try:
|
||||||
|
# with open(styleFile, 'r', encoding='utf-8') as style:
|
||||||
|
# self.setStyleSheet(style.read())
|
||||||
|
# except:
|
||||||
|
# with open(styleFile, 'r', encoding='gbk') as style:
|
||||||
|
# self.setStyleSheet(style.read())
|
||||||
|
# except:
|
||||||
|
# QMessageBox.warning(self, self.tr('主题载入错误'), self.tr('未能成功载入主题,请确保软件根目录有 "style.css" 文件存在。'))
|
||||||
|
|
||||||
|
def keyPressEvent(self, event) -> None:
|
||||||
|
# 在按下 F5 的时候重载 style.css 主题
|
||||||
|
if (event.key() == Qt.Key_F5):
|
||||||
|
self.loadStyleSheet()
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""Shuts down application on close."""
|
||||||
|
# Return stdout to defaults.
|
||||||
|
if main.ConfigTab.hideToSystemTraySwitch.isChecked():
|
||||||
|
event.ignore()
|
||||||
|
self.hide()
|
||||||
|
else:
|
||||||
|
sys.stdout = sys.__stdout__
|
||||||
|
super().closeEvent(event)
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def createDB():
|
||||||
|
cursor = conn.cursor()
|
||||||
|
result = cursor.execute('''select * from sqlite_master where name = '%s' ''' % presetTableName)
|
||||||
|
if result.fetchone() == None:
|
||||||
|
cursor.execute('''create table %s (
|
||||||
|
id integer primary key autoincrement,
|
||||||
|
name text,
|
||||||
|
useBackgroundImage integer,
|
||||||
|
imageName text,
|
||||||
|
backgroundSizeBoxX integer,
|
||||||
|
backgroundSizeBoxY integer,
|
||||||
|
fontName text,
|
||||||
|
fontSize integer,
|
||||||
|
fontColor text,
|
||||||
|
lineSpacing integer,
|
||||||
|
leftMargin integer,
|
||||||
|
topMargin integer,
|
||||||
|
rightMargin integer,
|
||||||
|
bottomMargin integer,
|
||||||
|
wordSpacing integer,
|
||||||
|
lineSpacingSigma integer,
|
||||||
|
fontSizeSigma integer,
|
||||||
|
wordSpacingSigma integer,
|
||||||
|
endChars text,
|
||||||
|
perturbXSigma integer,
|
||||||
|
perturbYSigma integer,
|
||||||
|
perturbThetaSigma real)''' % presetTableName)
|
||||||
|
conn.commit()
|
||||||
|
result = cursor.execute('''select * from sqlite_master where name = '%s' ''' % preferenceTableName)
|
||||||
|
if result.fetchone() == None:
|
||||||
|
cursor.execute('''create table %s (
|
||||||
|
id integer primary key autoincrement,
|
||||||
|
item text,
|
||||||
|
value text
|
||||||
|
)''' % preferenceTableName)
|
||||||
|
conn.commit()
|
||||||
|
print(1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
os.environ['PATH'] += os.pathsep + os.getcwd()
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
conn = sqlite3.connect(dbname)
|
||||||
|
createDB()
|
||||||
|
platfm = platform.system()
|
||||||
|
main = MainWindow()
|
||||||
|
if platfm == 'Windows':
|
||||||
|
tray = SystemTray(QIcon('icon.ico'), main)
|
||||||
|
else:
|
||||||
|
tray = SystemTray(QIcon('icon.icns'), main)
|
||||||
|
sys.exit(app.exec_())
|
||||||
|
conn.close()
|
||||||
BIN
src/QuickHand_Win64_pyinstaller.7z
Normal file
BIN
src/backgrounds/letter.png
Normal file
|
After Width: | Height: | Size: 309 KiB |
BIN
src/database.db
Normal file
BIN
src/fonts/品如手写体.ttf
Normal file
BIN
src/fonts/手书体.ttf
Normal file
BIN
src/fonts/新叶念体.otf
Normal file
BIN
src/fonts/杨任东竹石体-Regular.ttf
Normal file
BIN
src/fonts/沐瑶软笔手写体.ttf
Normal file
BIN
src/fonts/沐瑶随心手写体.ttf
Normal file
BIN
src/fonts/清松手写体1.ttf
Normal file
BIN
src/fonts/清松手写体2.ttf
Normal file
BIN
src/fonts/胡晓波骚包体.otf
Normal file
BIN
src/fonts/贤二体.ttf
Normal file
BIN
src/fonts/阿朱泡泡体.ttf
Normal file
BIN
src/fonts/鸿雷板书简体-Regular.ttf
Normal file
BIN
src/icon.ico
Normal file
|
After Width: | Height: | Size: 17 KiB |
582
src/misc/README_zh.html
Normal file
BIN
src/misc/icon.afphoto
Normal file
BIN
src/misc/icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
src/misc/排版关系参考图.afphoto
Normal file
BIN
src/misc/视频封面 - 视频教程.afphoto
Normal file
BIN
src/misc/视频封面 - 视频教程.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
23
src/moduels/ColorLabel.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from PySide2.QtWidgets import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
class ColorLabel(QLabel):
|
||||||
|
|
||||||
|
palette = QPalette()
|
||||||
|
color = QColor()
|
||||||
|
color.setRgb(0,0,0)
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, text):
|
||||||
|
super().__init__()
|
||||||
|
self.setText(text)
|
||||||
|
self.setAutoFillBackground(True)
|
||||||
|
self.setColor()
|
||||||
|
|
||||||
|
def mousePressEvent(self, ev:QMouseEvent):
|
||||||
|
self.color = QColorDialog.getColor()
|
||||||
|
self.palette.setColor(QPalette.Window, self.color)
|
||||||
|
self.setColor()
|
||||||
|
|
||||||
|
def setColor(self):
|
||||||
|
self.palette.setColor(QPalette.Window, self.color)
|
||||||
|
self.setPalette(self.palette)
|
||||||
55
src/moduels/ConfigTab.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
from PySide2.QtCore import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
from PySide2.QtSql import *
|
||||||
|
from PySide2.QtWidgets import *
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigTab(QWidget):
|
||||||
|
def __init__(self, parent, conn, preferenceTableName):
|
||||||
|
super(ConfigTab, self).__init__(parent)
|
||||||
|
self.conn = conn
|
||||||
|
self.preferenceTableName = preferenceTableName
|
||||||
|
self.initGui()
|
||||||
|
self.connectSlots()
|
||||||
|
self.initValues()
|
||||||
|
|
||||||
|
def initGui(self):
|
||||||
|
|
||||||
|
self.hideToSystemTraySwitch = QCheckBox(self.tr('点击关闭按钮时隐藏到托盘'))
|
||||||
|
# self.chooseLanguageHint = QLabel(self.tr('语言:'))
|
||||||
|
|
||||||
|
self.preferenceGroupLayout = QHBoxLayout()
|
||||||
|
self.preferenceGroupLayout.addWidget(self.hideToSystemTraySwitch)
|
||||||
|
self.preferenceGroup = QGroupBox(self.tr('偏好设置'))
|
||||||
|
self.preferenceGroup.setLayout(self.preferenceGroupLayout)
|
||||||
|
|
||||||
|
self.masterLayout = QVBoxLayout()
|
||||||
|
self.masterLayout.addWidget(self.preferenceGroup)
|
||||||
|
self.masterLayout.addStretch(1)
|
||||||
|
|
||||||
|
self.setLayout(self.masterLayout)
|
||||||
|
|
||||||
|
def initValues(self):
|
||||||
|
self.checkDB()
|
||||||
|
|
||||||
|
def connectSlots(self):
|
||||||
|
self.hideToSystemTraySwitch.clicked.connect(self.hideToSystemTraySwitchClicked)
|
||||||
|
|
||||||
|
def checkDB(self):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
|
||||||
|
hideToSystemTrayResult = cursor.execute('''select value from %s where item = '%s'; ''' % (self.preferenceTableName, 'hideToTrayWhenHitCloseButton') ).fetchone()
|
||||||
|
if hideToSystemTrayResult == None: # 如果关闭窗口最小化到状态栏这个选项还没有在数据库创建,那就创建一个
|
||||||
|
cursor.execute('''insert into %s (item, value) values ('hideToTrayWhenHitCloseButton', 'False') ''' % self.preferenceTableName)
|
||||||
|
self.conn.commit()
|
||||||
|
else:
|
||||||
|
hideToSystemTrayValue = hideToSystemTrayResult[0]
|
||||||
|
if hideToSystemTrayValue == 'True':
|
||||||
|
self.hideToSystemTraySwitch.setChecked(True)
|
||||||
|
else:
|
||||||
|
self.hideToSystemTraySwitch.setChecked(False)
|
||||||
|
|
||||||
|
def hideToSystemTraySwitchClicked(self):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
cursor.execute('''update %s set value='%s' where item = '%s';''' % (self.preferenceTableName, str(self.hideToSystemTraySwitch.isChecked()), 'hideToTrayWhenHitCloseButton'))
|
||||||
|
self.conn.commit()
|
||||||
19
src/moduels/ConsolePrintBox.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
from PySide2.QtWidgets import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
|
||||||
|
|
||||||
|
class ConsolePrintBox(QTextEdit):
|
||||||
|
# 定义一个 QTextEdit 类,写入 print 方法。用于输出显示。
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(ConsolePrintBox, self).__init__(parent)
|
||||||
|
self.setReadOnly(True)
|
||||||
|
|
||||||
|
def print(self, text):
|
||||||
|
try:
|
||||||
|
cursor = self.textCursor()
|
||||||
|
cursor.movePosition(QTextCursor.End)
|
||||||
|
cursor.insertText(text)
|
||||||
|
self.setTextCursor(cursor)
|
||||||
|
self.ensureCursorVisible()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
31
src/moduels/ConsoleWindow.py
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
from PySide2.QtWidgets import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
from moduels.ConsolePrintBox import ConsolePrintBox
|
||||||
|
|
||||||
|
|
||||||
|
class ConsoleWindow(QMainWindow):
|
||||||
|
# 这个 console 是个子窗口,调用的时候要指定父窗口。例如:window = Console(main)
|
||||||
|
# 里面包含一个 OutputBox, 可以将信号导到它的 print 方法。
|
||||||
|
thread = None
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(ConsoleWindow, self).__init__(parent)
|
||||||
|
self.initGui()
|
||||||
|
|
||||||
|
def initGui(self):
|
||||||
|
self.setWindowTitle(self.tr('运行信息输出窗口'))
|
||||||
|
self.resize(1300, 700)
|
||||||
|
self.consolePrintBox = ConsolePrintBox() # 他就用于输出用户定义的打印信息
|
||||||
|
self.consolePrintBox.setParent(self)
|
||||||
|
self.setCentralWidget(self.consolePrintBox)
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def closeEvent(self, a0: QCloseEvent) -> None:
|
||||||
|
try:
|
||||||
|
self.thread.exit()
|
||||||
|
print('Thread exited')
|
||||||
|
self.thread.setTerminationEnabled(True)
|
||||||
|
self.thread.terminate()
|
||||||
|
print('Thread terminated')
|
||||||
|
except:
|
||||||
|
pass
|
||||||
32
src/moduels/GenerateImagesThread.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from PySide2.QtCore import *
|
||||||
|
from PIL import Image
|
||||||
|
from handright import Template, handwrite
|
||||||
|
|
||||||
|
class GenerateImagesThread(QThread):
|
||||||
|
text = None
|
||||||
|
template = None
|
||||||
|
outputPath = None
|
||||||
|
signal = Signal(str)
|
||||||
|
showImage = False
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super(GenerateImagesThread, self).__init__(parent)
|
||||||
|
|
||||||
|
def print(self, text):
|
||||||
|
self.signal.emit(text)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.signal.emit('开始生成图片\n\n')
|
||||||
|
try:
|
||||||
|
images = handwrite(self.text, self.template)
|
||||||
|
for i, im in enumerate(images):
|
||||||
|
assert isinstance(im, Image.Image)
|
||||||
|
self.signal.emit('第 %s 张图片生成\n\n' % str(int(i) + 1))
|
||||||
|
if self.showImage == True:
|
||||||
|
im.show()
|
||||||
|
outputDir = self.outputPath.replace('\\', '/')
|
||||||
|
im.save(outputDir + "/{}.webp".replace('//', '/').format(i))
|
||||||
|
self.signal.emit('所有图片生成完毕,输出文件夹为:%s\n\n' % outputDir)
|
||||||
|
except Exception as e:
|
||||||
|
self.signal.emit('出错了,报错信息如下:\n\n')
|
||||||
|
self.signal.emit(str(e) + '\n\n')
|
||||||
663
src/moduels/HandRightTab.py
Normal file
@@ -0,0 +1,663 @@
|
|||||||
|
import os
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from PySide2.QtCore import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
from PySide2.QtWidgets import *
|
||||||
|
|
||||||
|
from PIL import Image, ImageFont
|
||||||
|
from handright import Template, handwrite
|
||||||
|
|
||||||
|
from moduels.GenerateImagesThread import GenerateImagesThread
|
||||||
|
from moduels.ConsoleWindow import ConsoleWindow
|
||||||
|
from moduels.ColorLabel import ColorLabel
|
||||||
|
# 参考 https://github.com/Gsllchb/Handright/blob/master/docs/tutorial.md
|
||||||
|
|
||||||
|
class HandRightTab(QWidget):
|
||||||
|
def __init__(self, parent, conn, presetTableName):
|
||||||
|
super(HandRightTab, self).__init__(parent)
|
||||||
|
self.conn = conn
|
||||||
|
self.presetTableName = presetTableName
|
||||||
|
self.initGui()
|
||||||
|
self.refreshList()
|
||||||
|
self.connectSlots()
|
||||||
|
self.initValue()
|
||||||
|
|
||||||
|
def initGui(self):
|
||||||
|
|
||||||
|
self.inputBox = QPlainTextEdit()
|
||||||
|
|
||||||
|
self.outputPathHint = QLabel('输出路径')
|
||||||
|
self.outputPathBox = QLineEdit()
|
||||||
|
|
||||||
|
self.runBtn = QPushButton('运行')
|
||||||
|
|
||||||
|
self.backgroundBlankRadioBtn = QRadioButton('使用空白背景')
|
||||||
|
self.backgroundImageRadioBtn = QRadioButton('使用背景图片')
|
||||||
|
|
||||||
|
|
||||||
|
self.backgroundHint = QLabel('背景图片')
|
||||||
|
self.backgroundBox = QComboBox()
|
||||||
|
|
||||||
|
self.backgroundSizeHint = QLabel('背景图片大小')
|
||||||
|
self.backgroundSizeBoxX = QLineEdit()
|
||||||
|
self.backgroundSizeBoxMultipleHint = QLabel('×')
|
||||||
|
self.backgroundSizeBoxY = QLineEdit()
|
||||||
|
|
||||||
|
|
||||||
|
self.fontPathHint = QLabel('字体')
|
||||||
|
self.fontPathBox = QComboBox()
|
||||||
|
|
||||||
|
self.fontSizeHint = QLabel('字体大小')
|
||||||
|
self.fontSizeBox = QSpinBox()
|
||||||
|
|
||||||
|
self.fontColorHint = QLabel('字体颜色')
|
||||||
|
self.fontColorBox = ColorLabel('')
|
||||||
|
|
||||||
|
self.lineSpacingHint = QLabel('行间距')
|
||||||
|
self.lineSpacingBox = QSpinBox()
|
||||||
|
|
||||||
|
self.wordSpacingHint = QLabel('字符间距')
|
||||||
|
self.wordSpacingBox = QSpinBox()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.leftMarginHint = QLabel('页面左边距')
|
||||||
|
self.leftMarginBox = QSpinBox()
|
||||||
|
|
||||||
|
self.topMarginHint = QLabel('页面上边距')
|
||||||
|
self.topMarginBox = QSpinBox()
|
||||||
|
|
||||||
|
self.rightMarginHint = QLabel('页面右边距')
|
||||||
|
self.rightMarginBox = QSpinBox()
|
||||||
|
|
||||||
|
self.bottomMarginHint = QLabel('页面下边距')
|
||||||
|
self.bottomMarginBox = QSpinBox()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.lindSpacingSigmaHint = QLabel('行间距扰动')
|
||||||
|
self.lindSpacingSigmaBox = QSpinBox()
|
||||||
|
|
||||||
|
self.fontSizeSigmaHint = QLabel('字体大小扰动')
|
||||||
|
self.fontSizeSigmaBox = QSpinBox()
|
||||||
|
|
||||||
|
self.wordSpacingSigmaHint = QLabel('字间距扰动')
|
||||||
|
self.wordSpacingSigmaBox = QSpinBox()
|
||||||
|
|
||||||
|
self.perturbXSigmaHint = QLabel('笔画横向偏移扰动')
|
||||||
|
self.perturbXSigmaBox = QSpinBox()
|
||||||
|
|
||||||
|
self.perturbYSigmaHint = QLabel('笔画纵向偏移扰动')
|
||||||
|
self.perturbYSigmaBox = QSpinBox()
|
||||||
|
|
||||||
|
self.perturbThetaSigmaHint = QLabel('笔画旋转偏移扰动')
|
||||||
|
self.perturbThetaSigmaBox = QDoubleSpinBox()
|
||||||
|
|
||||||
|
self.endCharsHint = QLabel('防止行首字符')
|
||||||
|
self.endCharsBox = QLineEdit()
|
||||||
|
|
||||||
|
self.showImageBox = QCheckBox('每生成一张图片后自动打开')
|
||||||
|
|
||||||
|
self.presetHint = QLabel('预设列表')
|
||||||
|
self.presetList = QListWidget()
|
||||||
|
|
||||||
|
self.upPresetBtn = QPushButton('↑')
|
||||||
|
self.downPresetBtn = QPushButton('↓')
|
||||||
|
self.addPresetBtn = QPushButton('+')
|
||||||
|
self.delPresetBtn = QPushButton('-')
|
||||||
|
|
||||||
|
|
||||||
|
self.outputLayout = QHBoxLayout()
|
||||||
|
self.outputLayout.setContentsMargins(0,0,0,0)
|
||||||
|
self.outputLayout.addWidget(self.outputPathHint)
|
||||||
|
self.outputLayout.addWidget(self.outputPathBox)
|
||||||
|
self.outputBox = QWidget()
|
||||||
|
self.outputBox.setContentsMargins(0,0,0,0)
|
||||||
|
self.outputBox.setLayout(self.outputLayout)
|
||||||
|
self.inputAndRunLayout = QVBoxLayout()
|
||||||
|
self.inputAndRunLayout.addWidget(self.inputBox)
|
||||||
|
self.inputAndRunLayout.addWidget(self.outputBox)
|
||||||
|
self.inputAndRunLayout.addWidget(self.runBtn)
|
||||||
|
self.inputAndRunBox = QWidget()
|
||||||
|
self.inputAndRunBox.setLayout(self.inputAndRunLayout)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.backgroundTypeLayout = QHBoxLayout() # 关于背景类型的两个按钮放置的布局
|
||||||
|
self.backgroundTypeLayout.addWidget(self.backgroundBlankRadioBtn)
|
||||||
|
self.backgroundTypeLayout.addWidget(self.backgroundImageRadioBtn)
|
||||||
|
self.backgroundTypeBox = QWidget()
|
||||||
|
self.backgroundTypeBox.setContentsMargins(0,0,0,0)
|
||||||
|
self.backgroundTypeBox.setLayout(self.backgroundTypeLayout)
|
||||||
|
|
||||||
|
self.backgroundSizeLayout = QHBoxLayout() # 关于背景大小
|
||||||
|
self.backgroundSizeLayout.setContentsMargins(0,0,0,0)
|
||||||
|
self.backgroundSizeLayout.addWidget(self.backgroundSizeBoxX)
|
||||||
|
self.backgroundSizeLayout.addWidget(self.backgroundSizeBoxMultipleHint)
|
||||||
|
self.backgroundSizeLayout.addWidget(self.backgroundSizeBoxY)
|
||||||
|
self.backgroundSizeBox = QWidget()
|
||||||
|
self.backgroundSizeBox.setContentsMargins(0, 0, 0, 0)
|
||||||
|
self.backgroundSizeBox.setLayout(self.backgroundSizeLayout)
|
||||||
|
|
||||||
|
self.optionsLayout = QFormLayout()
|
||||||
|
self.optionsLayout.setWidget(0, QFormLayout.SpanningRole, self.backgroundTypeBox) # 背景类型
|
||||||
|
self.optionsLayout.addRow(self.backgroundHint, self.backgroundBox) # 背景图片
|
||||||
|
self.optionsLayout.setWidget(2, QFormLayout.LabelRole, self.backgroundSizeHint) # 背景大小
|
||||||
|
self.optionsLayout.setWidget(2, QFormLayout.FieldRole, self.backgroundSizeBox) # 背景大小
|
||||||
|
self.optionsLayout.addRow(QLabel(''), QLabel('')) # 空白行
|
||||||
|
self.optionsLayout.addRow(self.fontPathHint, self.fontPathBox) # 字体
|
||||||
|
self.optionsLayout.addRow(self.fontSizeHint, self.fontSizeBox) # 字体大小
|
||||||
|
self.optionsLayout.addRow(self.fontColorHint, self.fontColorBox) # 字体颜色
|
||||||
|
self.optionsLayout.addRow(self.lineSpacingHint, self.lineSpacingBox) # 行间距
|
||||||
|
self.optionsLayout.addRow(self.wordSpacingHint, self.wordSpacingBox) # 字符间距
|
||||||
|
self.optionsLayout.addRow(QLabel(''), QLabel('')) # 空白行
|
||||||
|
self.optionsLayout.addRow(self.leftMarginHint, self.leftMarginBox) # 左边距
|
||||||
|
self.optionsLayout.addRow(self.topMarginHint, self.topMarginBox) # 上边距
|
||||||
|
self.optionsLayout.addRow(self.rightMarginHint, self.rightMarginBox) # 右边距
|
||||||
|
self.optionsLayout.addRow(self.bottomMarginHint, self.bottomMarginBox) # 下边距
|
||||||
|
self.optionsLayout.addRow(QLabel(''), QLabel('')) # 空白行
|
||||||
|
self.optionsLayout.addRow(self.lindSpacingSigmaHint, self.lindSpacingSigmaBox) # 行间距扰动
|
||||||
|
self.optionsLayout.addRow(self.fontSizeSigmaHint, self.fontSizeSigmaBox) # 字体大小扰动
|
||||||
|
self.optionsLayout.addRow(self.wordSpacingSigmaHint, self.wordSpacingSigmaBox) # 字间距扰动
|
||||||
|
self.optionsLayout.addRow(self.perturbXSigmaHint, self.perturbXSigmaBox) # 笔画横向偏移扰动
|
||||||
|
self.optionsLayout.addRow(self.perturbYSigmaHint, self.perturbYSigmaBox) # 行间距扰动
|
||||||
|
self.optionsLayout.addRow(self.perturbThetaSigmaHint, self.perturbThetaSigmaBox) # 行间距扰动
|
||||||
|
self.optionsLayout.addRow(self.endCharsHint, self.endCharsBox) # 防止行首字符
|
||||||
|
self.optionsLayout.addRow(QLabel(''), QLabel('')) # 空白行
|
||||||
|
self.optionsLayout.setWidget(23, QFormLayout.SpanningRole, self.showImageBox)
|
||||||
|
|
||||||
|
|
||||||
|
self.optionsBox = QWidget()
|
||||||
|
self.optionsBox.setLayout(self.optionsLayout)
|
||||||
|
|
||||||
|
|
||||||
|
self.presetLayout = QGridLayout()
|
||||||
|
self.presetLayout.addWidget(self.presetHint, 0,0,1,2)
|
||||||
|
self.presetLayout.addWidget(self.presetList, 1,0,1,2)
|
||||||
|
self.presetLayout.addWidget(self.upPresetBtn, 2,0,1,1)
|
||||||
|
self.presetLayout.addWidget(self.downPresetBtn, 2,1,1,1)
|
||||||
|
self.presetLayout.addWidget(self.addPresetBtn, 3,0,1,1)
|
||||||
|
self.presetLayout.addWidget(self.delPresetBtn, 3,1,1,1)
|
||||||
|
self.presetBox = QWidget()
|
||||||
|
self.presetBox.setLayout(self.presetLayout)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.splitBetweenOptionAndPesetTable = QSplitter()
|
||||||
|
self.splitBetweenOptionAndPesetTable.addWidget(self.optionsBox)
|
||||||
|
self.splitBetweenOptionAndPesetTable.addWidget(self.presetBox)
|
||||||
|
|
||||||
|
self.splitBetweenInputAndOption = QSplitter()
|
||||||
|
self.splitBetweenInputAndOption.addWidget(self.inputAndRunBox)
|
||||||
|
self.splitBetweenInputAndOption.addWidget(self.splitBetweenOptionAndPesetTable)
|
||||||
|
|
||||||
|
self.masterLayout = QHBoxLayout()
|
||||||
|
self.masterLayout.addWidget(self.splitBetweenInputAndOption)
|
||||||
|
|
||||||
|
self.setLayout(self.masterLayout)
|
||||||
|
|
||||||
|
def initValue(self):
|
||||||
|
font = QFont()
|
||||||
|
font.setPointSize(12)
|
||||||
|
self.inputBox.setFont(font)
|
||||||
|
self.inputBox.setPlaceholderText('在这里输入要生成图片的文字')
|
||||||
|
|
||||||
|
self.outputPathBox.setText(os.getcwd().replace('\\', '/') + '/output')
|
||||||
|
|
||||||
|
self.backgroundBlankRadioBtn.click() # 启用或停用背景图片
|
||||||
|
# self.switchUseable()
|
||||||
|
|
||||||
|
self.backgroundBox.clear()
|
||||||
|
self.backgroundBox.addItems(os.listdir('./backgrounds')) # 添加背景图片列表
|
||||||
|
|
||||||
|
self.backgroundSizeBoxX.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter) # 初始化背景图片大小
|
||||||
|
self.backgroundSizeBoxX.setValidator(QIntValidator(self))
|
||||||
|
self.backgroundSizeBoxX.setText('2000')
|
||||||
|
|
||||||
|
self.backgroundSizeBoxY.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter) # 初始化背景图片大小
|
||||||
|
self.backgroundSizeBoxY.setValidator(QIntValidator(self))
|
||||||
|
self.backgroundSizeBoxY.setText('2000')
|
||||||
|
|
||||||
|
|
||||||
|
self.fontPathBox.clear()
|
||||||
|
self.fontPathBox.addItems(os.listdir('./fonts')) # 添加字体列表
|
||||||
|
|
||||||
|
self.fontSizeBox.setSingleStep(5)
|
||||||
|
self.fontSizeBox.setMinimum(1)
|
||||||
|
self.fontSizeBox.setMaximum(2000)
|
||||||
|
self.fontSizeBox.setValue(100) # 设定字体初始大小
|
||||||
|
self.fontSizeBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.lineSpacingBox.setSingleStep(10)
|
||||||
|
self.lineSpacingBox.setMinimum(1)
|
||||||
|
self.lineSpacingBox.setMaximum(2000)
|
||||||
|
self.lineSpacingBox.setValue(120) # 初始化行间距
|
||||||
|
self.lineSpacingBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.wordSpacingBox.setSingleStep(5)
|
||||||
|
self.wordSpacingBox.setMinimum(-1000)
|
||||||
|
self.wordSpacingBox.setMaximum(2000)
|
||||||
|
self.wordSpacingBox.setValue(120) # 初始化字符间距
|
||||||
|
self.wordSpacingBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.leftMarginBox.setSingleStep(5)
|
||||||
|
self.leftMarginBox.setMinimum(1)
|
||||||
|
self.leftMarginBox.setMaximum(2000)
|
||||||
|
self.leftMarginBox.setValue(200) # 初始化页面左边距
|
||||||
|
self.leftMarginBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.topMarginBox.setSingleStep(5)
|
||||||
|
self.topMarginBox.setMinimum(1)
|
||||||
|
self.topMarginBox.setMaximum(2000)
|
||||||
|
self.topMarginBox.setValue(200) # 初始化页面上边距
|
||||||
|
self.topMarginBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.rightMarginBox.setSingleStep(5)
|
||||||
|
self.rightMarginBox.setMinimum(1)
|
||||||
|
self.rightMarginBox.setMaximum(2000)
|
||||||
|
self.rightMarginBox.setValue(200) # 初始化页面右边剧
|
||||||
|
self.rightMarginBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.bottomMarginBox.setSingleStep(5)
|
||||||
|
self.bottomMarginBox.setMinimum(1)
|
||||||
|
self.bottomMarginBox.setMaximum(2000)
|
||||||
|
self.bottomMarginBox.setValue(200) # 初始化页面下边距
|
||||||
|
self.bottomMarginBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.lindSpacingSigmaBox.setSingleStep(1)
|
||||||
|
self.lindSpacingSigmaBox.setMinimum(1)
|
||||||
|
self.lindSpacingSigmaBox.setMaximum(1000)
|
||||||
|
self.lindSpacingSigmaBox.setValue(6) # 初始化行间距扰动
|
||||||
|
self.lindSpacingSigmaBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.fontSizeSigmaBox.setSingleStep(2)
|
||||||
|
self.fontSizeSigmaBox.setMinimum(1)
|
||||||
|
self.fontSizeSigmaBox.setMaximum(1000)
|
||||||
|
self.fontSizeSigmaBox.setValue(20) # 初始化字体大小扰动
|
||||||
|
self.fontSizeSigmaBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.wordSpacingSigmaBox.setSingleStep(1)
|
||||||
|
self.wordSpacingSigmaBox.setMinimum(1)
|
||||||
|
self.wordSpacingSigmaBox.setMaximum(1000)
|
||||||
|
self.wordSpacingSigmaBox.setValue(3) # 初始化字间距扰动
|
||||||
|
self.wordSpacingSigmaBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.perturbXSigmaBox.setSingleStep(1)
|
||||||
|
self.perturbXSigmaBox.setMinimum(1)
|
||||||
|
self.perturbXSigmaBox.setMaximum(1000)
|
||||||
|
self.perturbXSigmaBox.setValue(4) # 笔画横向偏移扰动
|
||||||
|
self.perturbXSigmaBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.perturbYSigmaBox.setSingleStep(1)
|
||||||
|
self.perturbYSigmaBox.setMinimum(1)
|
||||||
|
self.perturbYSigmaBox.setMaximum(1000)
|
||||||
|
self.perturbYSigmaBox.setValue(4) # 笔画纵向偏移扰动
|
||||||
|
self.perturbYSigmaBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.perturbThetaSigmaBox.setSingleStep(1)
|
||||||
|
self.perturbThetaSigmaBox.setDecimals(2)
|
||||||
|
self.perturbThetaSigmaBox.setMinimum(0.00)
|
||||||
|
self.perturbThetaSigmaBox.setMaximum(1)
|
||||||
|
self.perturbThetaSigmaBox.setValue(0.05) # 笔画旋转偏移扰动
|
||||||
|
self.perturbThetaSigmaBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
self.endCharsBox.setText(',。!?') # 防止行首字符
|
||||||
|
self.endCharsBox.setAlignment(Qt.AlignVCenter | Qt.AlignHCenter)
|
||||||
|
|
||||||
|
|
||||||
|
self.splitBetweenInputAndOption.setStretchFactor(0,5)
|
||||||
|
self.splitBetweenInputAndOption.setStretchFactor(1,1)
|
||||||
|
|
||||||
|
|
||||||
|
def connectSlots(self):
|
||||||
|
self.runBtn.clicked.connect(self.run)
|
||||||
|
self.backgroundBlankRadioBtn.clicked.connect(self.backgroundBlankRadioBtnClicked)
|
||||||
|
self.backgroundImageRadioBtn.clicked.connect(self.backgroundImageRadioBtnClicked)
|
||||||
|
self.upPresetBtn.clicked.connect(self.upMovePreset)
|
||||||
|
self.downPresetBtn.clicked.connect(self.downMovePreset)
|
||||||
|
self.addPresetBtn.clicked.connect(self.addPreset)
|
||||||
|
self.delPresetBtn.clicked.connect(self.delPreset)
|
||||||
|
self.presetList.itemClicked.connect(self.presetItemSelected)
|
||||||
|
|
||||||
|
|
||||||
|
def backgroundBlankRadioBtnClicked(self):
|
||||||
|
self.useBackgroundImage = False
|
||||||
|
self.backgroundHint.setEnabled(False)
|
||||||
|
self.backgroundBox.setEnabled(False)
|
||||||
|
self.backgroundSizeHint.setText('背景图片大小')
|
||||||
|
self.backgroundSizeBoxX.setText('2000')
|
||||||
|
self.backgroundSizeBoxY.setText('4000')
|
||||||
|
|
||||||
|
def backgroundImageRadioBtnClicked(self):
|
||||||
|
self.useBackgroundImage = True
|
||||||
|
self.backgroundHint.setEnabled(True)
|
||||||
|
self.backgroundBox.setEnabled(True)
|
||||||
|
self.backgroundSizeHint.setText('背景图片缩放')
|
||||||
|
self.backgroundSizeBoxX.setText('1')
|
||||||
|
self.backgroundSizeBoxY.setText('1')
|
||||||
|
|
||||||
|
def refreshList(self):
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
try:
|
||||||
|
result = cursor.execute('''select name from %s order by id asc''' % (self.presetTableName)).fetchall()
|
||||||
|
except:
|
||||||
|
print('数据库读取不正常') # 这里可能还需要加一个重新载入数据库的操作, 不过懒得写了
|
||||||
|
self.presetList.clear()
|
||||||
|
for item in result:
|
||||||
|
self.presetList.addItem(item[0])
|
||||||
|
|
||||||
|
def presetItemSelected(self):
|
||||||
|
currentRow = self.presetList.currentRow()
|
||||||
|
currentItemName = self.presetList.item(currentRow).text()
|
||||||
|
presetData = self.conn.cursor().execute('''select
|
||||||
|
useBackgroundImage, imageName,
|
||||||
|
backgroundSizeBoxX, backgroundSizeBoxY, fontName, fontSize,
|
||||||
|
fontColor, lineSpacing, leftMargin, topMargin,
|
||||||
|
rightMargin, bottomMargin, wordSpacing, lineSpacingSigma,
|
||||||
|
fontSizeSigma, wordSpacingSigma, endChars, perturbXSigma,
|
||||||
|
perturbYSigma, perturbThetaSigma
|
||||||
|
from %s where name = '%s'; ''' % (
|
||||||
|
self.presetTableName, currentItemName)).fetchone()
|
||||||
|
|
||||||
|
useBackgroundImage = presetData[0]
|
||||||
|
imageName = presetData[1]
|
||||||
|
backgroundSizeBoxX = presetData[2]
|
||||||
|
backgroundSizeBoxY = presetData[3]
|
||||||
|
fontName = presetData[4]
|
||||||
|
fontSize = presetData[5]
|
||||||
|
fontColor = presetData[6]
|
||||||
|
lineSpacing = presetData[7]
|
||||||
|
leftMargin = presetData[8]
|
||||||
|
topMargin = presetData[9]
|
||||||
|
rightMargin = presetData[10]
|
||||||
|
bottomMargin = presetData[11]
|
||||||
|
wordSpacing = presetData[12]
|
||||||
|
lineSpacingSigma = presetData[13]
|
||||||
|
fontSizeSigma = presetData[14]
|
||||||
|
wordSpacingSigma = presetData[15]
|
||||||
|
endChars = presetData[16]
|
||||||
|
perturbXSigma = presetData[17]
|
||||||
|
perturbYSigma = presetData[18]
|
||||||
|
perturbThetaSigma = presetData[19]
|
||||||
|
|
||||||
|
if useBackgroundImage:
|
||||||
|
self.backgroundImageRadioBtn.click()
|
||||||
|
else:
|
||||||
|
self.backgroundBlankRadioBtn.click()
|
||||||
|
self.backgroundBox.setCurrentText(imageName)
|
||||||
|
self.backgroundSizeBoxX.setText(str(backgroundSizeBoxX))
|
||||||
|
self.backgroundSizeBoxY.setText(str(backgroundSizeBoxY))
|
||||||
|
self.fontPathBox.setCurrentText(fontName)
|
||||||
|
self.fontSizeBox.setValue(fontSize)
|
||||||
|
colorTuple = tuple(eval(fontColor))
|
||||||
|
print(colorTuple)
|
||||||
|
self.fontColorBox.color = QColor()
|
||||||
|
self.fontColorBox.color.setRgb(colorTuple[0], colorTuple[1], colorTuple[2])
|
||||||
|
self.fontColorBox.setColor()
|
||||||
|
self.lineSpacingBox.setValue(lineSpacing)
|
||||||
|
self.leftMarginBox.setValue(leftMargin)
|
||||||
|
self.topMarginBox.setValue(topMargin)
|
||||||
|
self.rightMarginBox.setValue(rightMargin)
|
||||||
|
self.bottomMarginBox.setValue(bottomMargin)
|
||||||
|
self.wordSpacingBox.setValue(wordSpacing)
|
||||||
|
self.lindSpacingSigmaBox.setValue(lineSpacingSigma)
|
||||||
|
self.fontSizeSigmaBox.setValue(fontSizeSigma)
|
||||||
|
self.wordSpacingSigmaBox.setValue(wordSpacingSigma)
|
||||||
|
self.endCharsBox.setText(endChars)
|
||||||
|
self.perturbXSigmaBox.setValue(perturbXSigma)
|
||||||
|
self.perturbYSigmaBox.setValue(perturbYSigma)
|
||||||
|
self.perturbThetaSigmaBox.setValue(perturbThetaSigma)
|
||||||
|
|
||||||
|
|
||||||
|
def addPreset(self):
|
||||||
|
presetName, _ = QInputDialog.getText(self,'添加或更新预设','请输入预设名称')
|
||||||
|
|
||||||
|
print(presetName)
|
||||||
|
if _ == False:
|
||||||
|
return False
|
||||||
|
imageName = self.backgroundBox.currentText().replace("'", "''")
|
||||||
|
imageSizeX = int(self.backgroundSizeBoxX.text())
|
||||||
|
imageSizeY = int(self.backgroundSizeBoxY.text())
|
||||||
|
fontName = self.fontPathBox.currentText().replace("'", "''")
|
||||||
|
fontSize = self.fontSizeBox.value()
|
||||||
|
fontColor = self.fontColorBox.color
|
||||||
|
fontColor = (fontColor.red(), fontColor.green(), fontColor.blue())
|
||||||
|
lineSpacing = self.lineSpacingBox.value()
|
||||||
|
leftMargin = self.leftMarginBox.value()
|
||||||
|
topMargin = self.topMarginBox.value()
|
||||||
|
rightMargin = self.rightMarginBox.value()
|
||||||
|
bottomMargin = self.bottomMarginBox.value()
|
||||||
|
wordSpacing = self.wordSpacingBox.value()
|
||||||
|
lineSpacingSigma = self.lindSpacingSigmaBox.value()
|
||||||
|
fontSizeSigma = self.fontSizeSigmaBox.value()
|
||||||
|
wordSpacingSigma = self.wordSpacingSigmaBox.value()
|
||||||
|
endChars = self.endCharsBox.text().replace("'", "''")
|
||||||
|
perturbXSigma = self.perturbXSigmaBox.value()
|
||||||
|
perturbYSigma = self.perturbYSigmaBox.value()
|
||||||
|
perturbThetaSigma = self.perturbThetaSigmaBox.value()
|
||||||
|
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
result = cursor.execute('''select name from %s where name = '%s';''' % (self.presetTableName, presetName.replace("'", "''"))).fetchone()
|
||||||
|
if result == None: # 如果没有重名的预设
|
||||||
|
maxIdItem = cursor.execute('''select id from %s order by id desc;''' % (self.presetTableName)).fetchone()
|
||||||
|
if maxIdItem == None:
|
||||||
|
maxId = 0
|
||||||
|
else:
|
||||||
|
maxId = maxIdItem[0]
|
||||||
|
print(maxId)
|
||||||
|
cursor.execute('''insert into %s (id, name, useBackgroundImage, imageName,
|
||||||
|
backgroundSizeBoxX, backgroundSizeBoxY, fontName, fontSize,
|
||||||
|
fontColor, lineSpacing, leftMargin, topMargin,
|
||||||
|
rightMargin, bottomMargin, wordSpacing, lineSpacingSigma,
|
||||||
|
fontSizeSigma, wordSpacingSigma, endChars, perturbXSigma,
|
||||||
|
perturbYSigma, perturbThetaSigma)
|
||||||
|
values (%s, '%s', %s, '%s',
|
||||||
|
%s, %s, '%s', %s,
|
||||||
|
'%s', %s, %s, %s,
|
||||||
|
%s, %s, %s, %s,
|
||||||
|
%s, %s, '%s', %s,
|
||||||
|
%s, %s);'''
|
||||||
|
% (self.presetTableName, maxId+1, presetName, self.useBackgroundImage, imageName,
|
||||||
|
imageSizeX, imageSizeY, fontName, fontSize,
|
||||||
|
fontColor, lineSpacing, leftMargin, topMargin,
|
||||||
|
rightMargin, bottomMargin, wordSpacing, lineSpacingSigma,
|
||||||
|
fontSizeSigma, wordSpacingSigma, endChars, perturbXSigma,
|
||||||
|
perturbYSigma, perturbThetaSigma))
|
||||||
|
else: # 如果有重名的预设
|
||||||
|
answer = QMessageBox.question(self, '更新预设', '已经存在相同名字的预设,是否更新?', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
|
||||||
|
if answer != QMessageBox.Yes:
|
||||||
|
return False
|
||||||
|
print(answer)
|
||||||
|
cursor.execute('''update %s set useBackgroundImage=%s, imageName='%s',
|
||||||
|
backgroundSizeBoxX=%s, backgroundSizeBoxY=%s, fontName='%s', fontSize=%s,
|
||||||
|
fontColor='%s', lineSpacing=%s, leftMargin=%s, topMargin=%s,
|
||||||
|
rightMargin=%s, bottomMargin=%s, wordSpacing=%s, lineSpacingSigma=%s,
|
||||||
|
fontSizeSigma=%s, wordSpacingSigma=%s, endChars='%s', perturbXSigma=%s,
|
||||||
|
perturbYSigma=%s, perturbThetaSigma=%s where name = '%s' '''
|
||||||
|
% (self.presetTableName, self.useBackgroundImage, imageName,
|
||||||
|
imageSizeX, imageSizeY, fontName, fontSize,
|
||||||
|
fontColor, lineSpacing, leftMargin, topMargin,
|
||||||
|
rightMargin, bottomMargin, wordSpacing, lineSpacingSigma,
|
||||||
|
fontSizeSigma, wordSpacingSigma, endChars, perturbXSigma,
|
||||||
|
perturbYSigma, perturbThetaSigma, presetName))
|
||||||
|
QMessageBox.information(self, '成功', '预设更新成功')
|
||||||
|
self.conn.commit()
|
||||||
|
self.refreshList()
|
||||||
|
|
||||||
|
def delPreset(self):
|
||||||
|
currentRow = self.presetList.currentRow()
|
||||||
|
if currentRow < 0:
|
||||||
|
return False
|
||||||
|
currentItemName = self.presetList.item(currentRow).text()
|
||||||
|
answer = QMessageBox.question(self, '删除预设', '确认要删除“%s”预设吗?' % currentItemName)
|
||||||
|
if answer == QMessageBox.No:
|
||||||
|
return False
|
||||||
|
id = self.conn.cursor().execute('''select id from %s where name = '%s'; ''' % (self.presetTableName, currentItemName)).fetchone()[0]
|
||||||
|
self.conn.cursor().execute("delete from %s where id = '%s'; " % (self.presetTableName, id))
|
||||||
|
self.conn.cursor().execute("update %s set id=id-1 where id > %s" % (self.presetTableName, id))
|
||||||
|
self.conn.commit()
|
||||||
|
self.refreshList()
|
||||||
|
|
||||||
|
def upMovePreset(self):
|
||||||
|
currentRow = self.presetList.currentRow()
|
||||||
|
if currentRow < 1:
|
||||||
|
return False
|
||||||
|
currentItemName = self.presetList.currentItem().text().replace("'", "''")
|
||||||
|
id = self.conn.cursor().execute(
|
||||||
|
"select id from %s where name = '%s'" % (self.presetTableName, currentItemName)).fetchone()[0]
|
||||||
|
self.conn.cursor().execute("update %s set id=10000 where id=%s-1 " % (self.presetTableName, id))
|
||||||
|
self.conn.cursor().execute("update %s set id = id - 1 where name = '%s'" % (self.presetTableName, currentItemName))
|
||||||
|
self.conn.cursor().execute("update %s set id=%s where id=10000 " % (self.presetTableName, id))
|
||||||
|
self.conn.commit()
|
||||||
|
self.refreshList()
|
||||||
|
self.presetList.setCurrentRow(currentRow - 1)
|
||||||
|
|
||||||
|
def downMovePreset(self):
|
||||||
|
currentRow = self.presetList.currentRow()
|
||||||
|
totalRow = self.presetList.count()
|
||||||
|
if currentRow < 0 or currentRow > totalRow - 2:
|
||||||
|
return False
|
||||||
|
currentItemName = self.presetList.currentItem().text().replace("'", "''")
|
||||||
|
id = self.conn.cursor().execute(
|
||||||
|
"select id from %s where name = '%s'" % (self.presetTableName, currentItemName)).fetchone()[0]
|
||||||
|
self.conn.cursor().execute("update %s set id=10000 where id=%s+1 " % (self.presetTableName, id))
|
||||||
|
self.conn.cursor().execute("update %s set id = id + 1 where name = '%s'" % (self.presetTableName, currentItemName))
|
||||||
|
self.conn.cursor().execute("update %s set id=%s where id=10000 " % (self.presetTableName, id))
|
||||||
|
self.conn.commit()
|
||||||
|
self.refreshList()
|
||||||
|
if currentRow < totalRow:
|
||||||
|
self.presetList.setCurrentRow(currentRow + 1)
|
||||||
|
else:
|
||||||
|
self.presetList.setCurrentRow(currentRow)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if not self.checkOutputPath(): # 如果输出检查发生了错误 就停止
|
||||||
|
return False
|
||||||
|
if self.fontPathBox.currentText() == '':
|
||||||
|
QMessageBox.information(self, '字体问题', '选择的字体为空,运行停止。请将 ttf 格式的字体放到本软件根目录的 fonts 文件夹中,再重新启动软件。')
|
||||||
|
return False
|
||||||
|
if self.useBackgroundImage:
|
||||||
|
imageName = self.backgroundBox.currentText() # 图片文件名
|
||||||
|
if imageName == '':
|
||||||
|
QMessageBox.warning(self, '背景问题', '你选择了使用图片背景,但背景图片文件为空,运行停止。请将 jpg、png 格式的图片放到本软件根目录的 backgrounds 文件夹中,再重新启动软件。')
|
||||||
|
return False
|
||||||
|
if (self.backgroundSizeBoxX.text() == '' or self.backgroundSizeBoxY.text() == '') or (int(self.backgroundSizeBoxX.text()) == 0 or int(self.backgroundSizeBoxY.text()) == 0):
|
||||||
|
QMessageBox.warning(self, '背景问题', '背景图片大小错误,请检查')
|
||||||
|
return False
|
||||||
|
inputText = self.inputBox.toPlainText()
|
||||||
|
if inputText == '':
|
||||||
|
print('没有输入文字')
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 背景图片
|
||||||
|
imageSizeX = int(self.backgroundSizeBoxX.text())
|
||||||
|
imageSizeY = int(self.backgroundSizeBoxY.text())
|
||||||
|
if not self.useBackgroundImage:
|
||||||
|
background = Image.new(mode="RGB", size=(imageSizeX, imageSizeY),color=(255, 255, 255))
|
||||||
|
else:
|
||||||
|
imagePath = os.path.abspath('./backgrounds/' + imageName)
|
||||||
|
try:
|
||||||
|
background = Image.open(imagePath, 'r')
|
||||||
|
except:
|
||||||
|
QMessageBox.warning(self, '背景问题', '所选背景图片不是可打开的图片文件')
|
||||||
|
return False
|
||||||
|
width, height = background.size
|
||||||
|
background = background.resize((width * imageSizeX, height * imageSizeY), resample=Image.LANCZOS)
|
||||||
|
|
||||||
|
# 字体文件
|
||||||
|
fontName = self.fontPathBox.currentText()
|
||||||
|
fontPath = os.path.abspath('./fonts/' + fontName)
|
||||||
|
try:
|
||||||
|
font = ImageFont.truetype(fontPath)
|
||||||
|
except:
|
||||||
|
QMessageBox.warning(self, '字体问题', '所选字体不是可打开的 ttf 字体文件')
|
||||||
|
return False
|
||||||
|
|
||||||
|
fontSize = self.fontSizeBox.value()
|
||||||
|
fontColor = self.fontColorBox.color
|
||||||
|
fontColor = (fontColor.red(), fontColor.green(), fontColor.blue())
|
||||||
|
lineSpacing = self.lineSpacingBox.value()
|
||||||
|
leftMargin = self.leftMarginBox.value()
|
||||||
|
topMargin = self.topMarginBox.value()
|
||||||
|
rightMargin = self.rightMarginBox.value()
|
||||||
|
bottomMargin = self.bottomMarginBox.value()
|
||||||
|
wordSpacing = self.wordSpacingBox.value()
|
||||||
|
lineSpacingSigma = self.lindSpacingSigmaBox.value()
|
||||||
|
fontSizeSigma = self.fontSizeSigmaBox.value()
|
||||||
|
wordSpacingSigma = self.wordSpacingSigmaBox.value()
|
||||||
|
endChars = self.endCharsBox.text()
|
||||||
|
perturbXSigma = self.perturbXSigmaBox.value()
|
||||||
|
perturbYSigma = self.perturbYSigmaBox.value()
|
||||||
|
perturbThetaSigma = self.perturbThetaSigmaBox.value()
|
||||||
|
showImage = self.showImageBox.isChecked()
|
||||||
|
|
||||||
|
|
||||||
|
template = Template(
|
||||||
|
background=background,
|
||||||
|
font_size=fontSize,
|
||||||
|
font=font,
|
||||||
|
line_spacing=lineSpacing,
|
||||||
|
fill=fontColor, # 字体“颜色”
|
||||||
|
left_margin=leftMargin,
|
||||||
|
top_margin=topMargin,
|
||||||
|
right_margin=rightMargin,
|
||||||
|
bottom_margin=bottomMargin,
|
||||||
|
word_spacing=wordSpacing,
|
||||||
|
line_spacing_sigma=lineSpacingSigma, # 行间距随机扰动
|
||||||
|
font_size_sigma=fontSizeSigma, # 字体大小随机扰动
|
||||||
|
word_spacing_sigma=wordSpacingSigma, # 字间距随机扰动
|
||||||
|
end_chars=endChars, # 防止特定字符因排版算法的自动换行而出现在行首
|
||||||
|
perturb_x_sigma=perturbXSigma, # 笔画横向偏移随机扰动
|
||||||
|
perturb_y_sigma=perturbYSigma, # 笔画纵向偏移随机扰动
|
||||||
|
perturb_theta_sigma=perturbThetaSigma, # 笔画旋转偏移随机扰动
|
||||||
|
)
|
||||||
|
|
||||||
|
window = ConsoleWindow(self.parent())
|
||||||
|
thread = GenerateImagesThread()
|
||||||
|
window.thread = thread
|
||||||
|
thread.text = inputText
|
||||||
|
thread.template = template
|
||||||
|
thread.outputPath = self.outputPath
|
||||||
|
thread.showImage = showImage
|
||||||
|
thread.signal.connect(window.consolePrintBox.print)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def checkOutputPath(self):
|
||||||
|
self.outputPath = self.outputPathBox.text()
|
||||||
|
if not os.path.exists(self.outputPath): # 如果输出路径不存在
|
||||||
|
respond = QMessageBox.question(self, '路径错误', '输出文件夹不存在,是否创建?', QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
|
||||||
|
if respond == QMessageBox.Yes:
|
||||||
|
try:
|
||||||
|
os.mkdir(self.outputPath)
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
QMessageBox.warning(self, '路径错误', '无法创建输出文件夹,请检查输出路径')
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return False # 任务取消
|
||||||
|
else:
|
||||||
|
return True # 路径存在, 继续任务
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 启用和停用某些选项
|
||||||
|
def switchUseable(self):
|
||||||
|
if self.backgroundSwitch.isChecked() == False:
|
||||||
|
self.backgroundHint.setEnabled(False)
|
||||||
|
self.backgroundBox.setEnabled(False)
|
||||||
|
else:
|
||||||
|
self.backgroundHint.setEnabled(True)
|
||||||
|
self.backgroundBox.setEnabled(True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
56
src/moduels/HelpTab.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import webbrowser
|
||||||
|
import os
|
||||||
|
|
||||||
|
from PySide2.QtCore import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
from PySide2.QtSql import *
|
||||||
|
from PySide2.QtWidgets import *
|
||||||
|
|
||||||
|
from moduels.SponsorDialog import SponsorDialog
|
||||||
|
|
||||||
|
|
||||||
|
# 帮助页面
|
||||||
|
class HelpTab(QWidget):
|
||||||
|
def __init__(self, version, platfm):
|
||||||
|
super().__init__()
|
||||||
|
self.platfm = platfm
|
||||||
|
self.openHelpFileButton = QPushButton(self.tr('打开帮助文档'))
|
||||||
|
self.openVideoHelpButtone = QPushButton(self.tr('查看视频教程'))
|
||||||
|
self.openGiteePage = QPushButton(self.tr('当前版本是 %s,到 Gitee 检查新版本') % version)
|
||||||
|
self.openGithubPage = QPushButton(self.tr('当前版本是 %s,到 Github 检查新版本') % version)
|
||||||
|
self.linkToDiscussPage = QPushButton(self.tr('加入 QQ 群'))
|
||||||
|
self.tipButton = QPushButton(self.tr('打赏作者'))
|
||||||
|
|
||||||
|
self.openHelpFileButton.setMaximumHeight(100)
|
||||||
|
self.openVideoHelpButtone.setMaximumHeight(100)
|
||||||
|
self.openGiteePage.setMaximumHeight(100)
|
||||||
|
self.openGithubPage.setMaximumHeight(100)
|
||||||
|
self.linkToDiscussPage.setMaximumHeight(100)
|
||||||
|
self.tipButton.setMaximumHeight(100)
|
||||||
|
|
||||||
|
self.openHelpFileButton.clicked.connect(self.openHelpDocument)
|
||||||
|
self.openVideoHelpButtone.clicked.connect(lambda: webbrowser.open(self.tr(r'https://www.bilibili.com/video/BV14a4y1J7X8/')))
|
||||||
|
self.openGiteePage.clicked.connect(lambda: webbrowser.open(self.tr(r'https://gitee.com/haujet/QuickHand/releases')))
|
||||||
|
self.openGithubPage.clicked.connect(lambda: webbrowser.open(self.tr(r'https://github.com/HaujetZhao/QuickHand/releases')))
|
||||||
|
self.linkToDiscussPage.clicked.connect(lambda: webbrowser.open(
|
||||||
|
self.tr(r'https://qm.qq.com/cgi-bin/qm/qr?k=DgiFh5cclAElnELH4mOxqWUBxReyEVpm&jump_from=webapi')))
|
||||||
|
self.tipButton.clicked.connect(lambda: SponsorDialog(platfm))
|
||||||
|
|
||||||
|
self.masterLayout = QVBoxLayout()
|
||||||
|
self.setLayout(self.masterLayout)
|
||||||
|
self.masterLayout.addWidget(self.openHelpFileButton)
|
||||||
|
self.masterLayout.addWidget(self.openVideoHelpButtone)
|
||||||
|
self.masterLayout.addWidget(self.openGiteePage)
|
||||||
|
self.masterLayout.addWidget(self.openGithubPage)
|
||||||
|
self.masterLayout.addWidget(self.linkToDiscussPage)
|
||||||
|
self.masterLayout.addWidget(self.tipButton)
|
||||||
|
|
||||||
|
def openHelpDocument(self):
|
||||||
|
try:
|
||||||
|
if self.platfm == 'Darwin':
|
||||||
|
import shlex
|
||||||
|
os.system("open " + shlex.quote(self.tr("./misc/README_zh.html")))
|
||||||
|
elif self.platfm == 'Windows':
|
||||||
|
os.startfile(os.path.realpath(self.tr('./misc/README_zh.html')))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
18
src/moduels/SponsorDialog.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from PySide2.QtWidgets import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
|
||||||
|
class SponsorDialog(QDialog):
|
||||||
|
def __init__(self, platfm, parent=None):
|
||||||
|
super(SponsorDialog, self).__init__(parent)
|
||||||
|
self.resize(784, 890)
|
||||||
|
if platfm == 'Windows':
|
||||||
|
self.setWindowIcon(QIcon('icon.ico'))
|
||||||
|
else:
|
||||||
|
self.setWindowIcon(QIcon('icon.icns'))
|
||||||
|
self.setWindowTitle(self.tr('打赏作者'))
|
||||||
|
self.exec()
|
||||||
|
|
||||||
|
def paintEvent(self, event):
|
||||||
|
painter = QPainter(self)
|
||||||
|
pixmap = QPixmap('./sponsor.jpg')
|
||||||
|
painter.drawPixmap(self.rect(), pixmap)
|
||||||
45
src/moduels/SystemTray.py
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PySide2.QtCore import *
|
||||||
|
from PySide2.QtGui import *
|
||||||
|
from PySide2.QtWidgets import *
|
||||||
|
|
||||||
|
|
||||||
|
class SystemTray(QSystemTrayIcon):
|
||||||
|
def __init__(self, icon, window):
|
||||||
|
super(SystemTray, self).__init__()
|
||||||
|
self.window = window
|
||||||
|
self.setIcon(icon)
|
||||||
|
self.setParent(window)
|
||||||
|
self.activated.connect(self.trayEvent) # 设置托盘点击事件处理函数
|
||||||
|
self.tray_menu = QMenu(QApplication.desktop()) # 创建菜单
|
||||||
|
self.QuitAction = QAction(self.tr('退出'), self, triggered=self.quit) # 添加一级菜单动作选项(退出程序)
|
||||||
|
self.tray_menu.addAction(self.QuitAction)
|
||||||
|
self.setContextMenu(self.tray_menu) # 设置系统托盘菜单
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
def showWindow(self):
|
||||||
|
self.window.showNormal()
|
||||||
|
self.window.activateWindow()
|
||||||
|
self.window.setWindowFlags(Qt.Window)
|
||||||
|
self.window.show()
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
sys.stdout = sys.__stdout__
|
||||||
|
self.hide()
|
||||||
|
qApp.quit()
|
||||||
|
|
||||||
|
def trayEvent(self, reason):
|
||||||
|
# 鼠标点击icon传递的信号会带有一个整形的值,1是表示单击右键,2是双击,3是单击左键,4是用鼠标中键点击
|
||||||
|
if reason == 2 or reason == 3:
|
||||||
|
if self.window.isMinimized() or not self.window.isVisible():
|
||||||
|
# 若是最小化,则先正常显示窗口,再变为活动窗口(暂时显示在最前面)
|
||||||
|
self.window.showNormal()
|
||||||
|
self.window.activateWindow()
|
||||||
|
self.window.setWindowFlags(Qt.Window)
|
||||||
|
self.window.show()
|
||||||
|
else:
|
||||||
|
# 若不是最小化,则最小化
|
||||||
|
self.window.showMinimized()
|
||||||
|
# self.window.setWindowFlags(Qt.SplashScreen)
|
||||||
|
self.window.show()
|
||||||
9
src/pyinstaller打包.bat
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
pyinstaller --hidden-import pkg_resources.py2_warn --noconfirm -w -i icon.ico QuickHand.py
|
||||||
|
|
||||||
|
echo d | xcopy /y /s .\dist\rely .\dist\QuickHand
|
||||||
|
|
||||||
|
del /F /Q QuickHand_Win64_pyinstaller.7z
|
||||||
|
|
||||||
|
7z a -t7z QuickHand_Win64_pyinstaller.7z .\dist\QuickHand -mx=9 -ms=200m -mf -mhc -mhcf -mmt -r
|
||||||
|
|
||||||
|
pause
|
||||||
13
src/requirements.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
srt
|
||||||
|
keyboard
|
||||||
|
numpy
|
||||||
|
setuptools
|
||||||
|
aliyun-python-sdk-core
|
||||||
|
PyQt5
|
||||||
|
audiotsm
|
||||||
|
scipy
|
||||||
|
cos-python-sdk-v5
|
||||||
|
tencentcloud-sdk-python
|
||||||
|
oss2
|
||||||
|
pyaudio
|
||||||
|
auditok @ git+https://github.com/amsehili/auditok@v0.1.8
|
||||||
BIN
src/sponsor.jpg
Normal file
|
After Width: | Height: | Size: 283 KiB |