v1.0.0 完成。软件功能不多,应该没什么 bug

This commit is contained in:
haujet
2020-08-08 23:44:15 +08:00
parent 713f77ff0a
commit c2d2a723d1
42 changed files with 1769 additions and 24 deletions

8
.gitignore vendored
View File

@@ -113,3 +113,11 @@ dmypy.json
# Pyre type checker
.pyre/
.idea/
*.mp4
src/moduels/HandRight/
src/build/
src/dist/
src/output/

View File

@@ -1,37 +1,73 @@
# QuickHand
# ![icon.ico](src\icon.ico) Quick Hand
#### 介绍
## 📝 介绍
快速的仿手写文字的图片生成器。基于 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
界面预览:
![image-20200808220817456](assets/image-20200808220817456.png)
#### 安装教程
1. xxxx
2. xxxx
3. xxxx
## 🔮 使用说明
#### 使用说明
原理:首先,在水平位置、竖直位置和字体大小三个自由度上,对每个字的整体做随机扰动。随后,在水平位置、竖直位置和旋转角度三个自由度上,对每个字的每个笔画做随机扰动。
1. xxxx
2. xxxx
3. xxxx
Windows 64 位系统的用户:下载软件发行版压缩包,解压,双击运行里面的 `QuickHand.exe` 就可以运行了。
#### 参与贡献
- 请将需要用到的字体文件ttf 格式)放到软件根目录的 `fonts` 文件夹中
- 请将需要用到的背景图片放到软件根目录的 `backgrounds` 文件夹中
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
排版关系参考:
![params_visualizing](assets/params_visualizing.png)
## 🔨 参与贡献
作者只有 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 文件夹根目录内。
## ☕ 打赏
万水千山总是情,一块几块都是情。本软件完全开源,用爱发电,如果你愿意,可以以打赏的方式支持我一下:
![sponsor](assets/sponsor.jpg)
#### 码云特技
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) 这个地址来了解码云上的优秀开源项目
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/)
## 😀 交流
如果有软件方面的反馈可以提交 issues或者加入 QQ 群:[1146626791](https://qm.qq.com/cgi-bin/qm/qr?k=DgiFh5cclAElnELH4mOxqWUBxReyEVpm&jump_from=webapi)

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

BIN
assets/sponsor.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

8
requirements.txt Normal file
View 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
View 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()

Binary file not shown.

BIN
src/backgrounds/letter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

BIN
src/database.db Normal file

Binary file not shown.

Binary file not shown.

BIN
src/fonts/手书体.ttf Normal file

Binary file not shown.

BIN
src/fonts/新叶念体.otf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/fonts/贤二体.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

582
src/misc/README_zh.html Normal file

File diff suppressed because one or more lines are too long

BIN
src/misc/icon.afphoto Normal file

Binary file not shown.

BIN
src/misc/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

23
src/moduels/ColorLabel.py Normal file
View 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
View 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()

View 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

View 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

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

View 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
View 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()

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

0
src/style.css Normal file
View File