0 引言
用md写发布到网络上的文章需要利用图床,如果图片体积太大,不仅上传图床需要时间,网页加载也要时间,所以可以考虑减小图片体积。经过一番搜索,找到了TinyPNG在线压缩网站,只需图片拖进网站,然后等待,然后下载。
浏览器下载完后要切换到下载目录,剪切图片,跳回图片保存目录替换图片,如果下载时指定目录的话,下次写另一篇文章,又要换到另一个位置,烦死了!
1 模型的建立
我会为每一篇文章指定一个图片保存目录,方便以后管理,而截图时直接就将图片保存在该目录下,所以我希望直接将图片拖进程序,然后它就直接变成了压缩成品,没有其他操作。
窗口接收文件;一个标签,显示文字“图片”,一个标签,文字显示为拖入图片的绝对地址;一个标签,显示目前状态;一个按钮,按下则开始工作。
理论上,不需要按钮,但是由本人控制何时开始感觉更有安全感。
为了方便查看各控件的坐标,在cad中做了初步的规划,由于界面实在太简单,也不准备再更改,就没有保存二维图,在此仅列出控件几何参数。
标签 | 定义名 | 位置 | 尺寸 |
---|---|---|---|
窗体 | xiiyue | 无 | 500,400 |
静态标签 | label_s | 40,65 | 60,30 |
路径标签 | label_picfile | 130,50 | 330,60 |
状态标签 | label_state | 40,120 | 420,160 |
确认按钮 | butn | 200,305 | 100,30 |
2 代码实现
2.1 窗体
新建类,用于创建空白控件,自动成为窗体。
class xiiyue(QWidget):
pass
其实不需要新建继承QWidget的类,我是边学边写,跟着写。新建类后想要运行它,在以下代码
if __name__ == "__main__":
app = QApplication(sys.argv) # 创建应用
xiyue = xiiyue() # 实例化
xiyue.show() # 显示窗口
sys.exit(app.exec_()) # 持续运行
这句if使得其他文件导入此文件不会运行,而执行此文件才会运行。我本来就打算在一个文件里完成所有代码,因此不需要考虑导入的问题,不过这种格式的确有逻辑清晰的优点,这样写也没毛病。
写到此时用到了QWidget,QApplication,sys,因此文件开头导入模块:
import sys
from PyQt5.QtWidgets import QWidget,QApplication
继续调整主窗体,改写init。
1,继承所有,毕竟不能影响QWidget的原本功能
2,设置窗体名
3,设置窗口大小
4,加载子控件
def __init__(self):
super(xiiyue, self).__init__()
# 设置窗口名
self.setWindowTitle("图片压缩")
# 定义窗口大小
self.resize(500, 400)
# 布置控件
self.load()
为了保证init的简洁明了,子控件的建立和外观设定都放在了load()
函数里。
2.2 子控件
定义load()
函数
def load(self):
pass
其中为各子控件的创建和设置代码
- 静态标签部分
# 建标签
self.label_s = QLabel(self)
# 标签位置和尺寸
self.label_s.setGeometry(40, 65, 60, 30)
# 标签格式,字体颜色红,大小15像素,加粗
self.label_s.setStyleSheet("color:red;font-size:15px;font-weight:bold;")
# 标签居中设置,水平垂直居中
self.label_s.setAlignment(QtCore.Qt.AlignCenter)
# 标签文字
self.label_s.setText("图片")
- 路径标签部分
self.label_picfile = QLabel(self)
self.label_picfile.setGeometry(130, 50, 330, 60)
# 标签格式,背景白,字体大小15像素
self.label_picfile.setStyleSheet("background-color:white;font-size:15px;")
# 标签居中设置,左对齐,垂直居中
self.label_picfile.setAlignment(QtCore.Qt.AlignLeft |QtCore.Qt.AlignVCenter)
self.label_picfile.setText(self.file_name)
# 标签设置自动换行
self.label_picfile.setWordWrap(True)
这里有个变量file_name
没有定义,它是存放文件名的变量,在init中加上
self.file_name = ''
- 状态标签部分
self.label_state = QLabel(self)
self.label_state.setGeometry(40, 120, 420, 160)
self.label_state.setAlignment(QtCore.Qt.AlignCenter)
self.label_state.setStyleSheet("font-size:50px;font-weight:bold;")
self.label_state.setText("就绪")
- 确认按钮部分
self.butn = QPushButton(self)
self.butn.setGeometry(200,305,100,30)
self.butn.setText("开始压缩")
以上用到了QLabel、QPushButton和QtCore同样要导入
from PyQt5.QtWidgets import QLabel,QPushButton
from PyQt5 import QtCore
2.3 拖入图片功能
现在程序的外形都有了,如图所示。
但是还没有相应的功能,本小节就实现运行图片拖入程序并获取位置信息。
在init中加入代码启用拖拽功能
# 启用拖拽
self.setAcceptDrops(True)
文件拖拽如控件时会自动调用dragEnterEvent函数,因此在类中重写此函数。
# evn参数接收拖入事件
def dragEnterEvent(self, evn):
# 获取文件名
self.file_name=evn.mimeData().text()
# 截取需要部分
self.file_name=self.file_name[8:]
# 设置路径标签文本
self.label_picfile.setText(self.file_name)
路径标签中显示出路径说明一切都准备好了,可以点击按钮开始压缩。
evn.mimeData().text()
返回的路径开头8个字符是“file:///”,需要将其剪切。
2.4 按钮功能
按下按钮就开始调用压缩函数,但是有一个问题,上传图片给tinypng然后返回结果需要一定的时间,而在这段时间内,程序会未响应的现象,心灰之余,该项目被我放弃了好长时间。现在闲着没事,搜索了一下,发现多线程可以解决这类问题。
按钮功能通过信号与槽机制实现,定义槽函数,即按钮按下后需要做的事
def butn_job(self):
if self.file_name != '':
# 设置状态标签文本,表明正在压缩
self.label_state.setText("等")
# 新建线程,指明该线程需执行的函数
self.thread_deal = threading.Thread(target=self.deal_pic)
# 线程启动
self.thread_deal.start()
# 没有拖入图片时不工作
else:
self.label_state.setText("拖入图片")
线程需要threading模块
import threading
按钮的信号需要与槽连接,内置的信号为clicked函数,在init中连接
self.butn.clicked.connect(self.butn_job)
2.5 压缩
直接写
def deal_pic(self):
# 断开按钮信号与槽的连接,处理图片时按钮点击无反应
self.butn.blockSignals(True)
# 压缩图片
source = tinify.from_file(self.file_name)
# 保存图片
source.to_file(self.file_name)
# 记录本月上传次数
compressions_this_month =str(tinify.compression_count)
# 次数没地方放,就显示在标题处吧
self.setWindowTitle("图片压缩" + "本月使用:" + compressions_this_month)
# 设置状态标签
self.label_state.setText("就绪")
# 恢复按钮信号与槽的连接
self.butn.blockSignals(False)
# 重置路径标签
self.file_name = ''
self.label_picfile.setText(self.file_name)
需要用到tinify模块
import tinify
需要提供key
在程序开头就给它加上
tinify.key = "xxxxxxxxxxxxxxxxxxx"
至此所有工作都完成,完整代码在最后,接下来是试验。
3 实机试验
我在使用的时候发现,未响应问题确实解决了,但等待时间也太久了,我加了一个计时功能以便直观感受。
导入time模块
tinify.key = "xxxxxxxxxxxxxxxxxxx"
在图片压缩的两行代码上下加入时间记录函数,并将耗时显示在标题
t1 = time.time()
source = tinify.from_file(self.file_name)
source.to_file(self.file_name)
t2 = time.time()
t = t2 - t1
compressions_this_month =str(tinify.compression_count)
self.setWindowTitle("图片压缩" + "本月使用:" + compressions_this_month + "用时:" + str(t))
随便个截图,277k,开始压缩了,看图
结束了,看图
37s,然后我下载了一个压缩图片的软件。
最后,此项目结束,有所收获,并尽量还原实际的思考过程。
完整代码
# -*- coding:utf-8 -*-
# by xiyue
import sys
import threading
import tinify
import time
from PyQt5.QtWidgets import QWidget,QLabel,QApplication,QPushButton
from PyQt5 import QtCore
class xiiyue(QWidget):
def __init__(self):
super(xiiyue, self).__init__()
#定义变量
self.file_name = ''
# 窗口标题
self.setWindowTitle("图片压缩")
# 定义窗口大小
self.resize(500, 400)
#布置控件
self.load()
# 启用Drops方法
self.setAcceptDrops(True)
#signal and slot
self.butn.clicked.connect(self.butn_job)
def load(self):
#静态标签
self.label_s = QLabel(self)
self.label_s.setGeometry(40, 65, 60, 30)
self.label_s.setStyleSheet("color:red;font-size:15px;font-weight:bold;")
self.label_s.setAlignment(QtCore.Qt.AlignCenter)
self.label_s.setText("图片")
#路径标签
self.label_picfile = QLabel(self)
self.label_picfile.setGeometry(130, 50, 330, 60)
self.label_picfile.setStyleSheet("background-color:white;font-size:15px;")
self.label_picfile.setAlignment(QtCore.Qt.AlignLeft |QtCore.Qt.AlignVCenter)
self.label_picfile.setText(self.file_name)
self.label_picfile.setWordWrap(True)
#状态标签
self.label_state = QLabel(self)
self.label_state.setGeometry(40, 120, 420, 160)
self.label_state.setAlignment(QtCore.Qt.AlignCenter)
self.label_state.setStyleSheet("font-size:50px;font-weight:bold;")
self.label_state.setText("就绪")
#确认按钮
self.butn = QPushButton(self)
self.butn.setGeometry(200,305,100,30)
self.butn.setText("开始压缩")
# 鼠标拖入事件
def dragEnterEvent(self, evn):
self.file_name=evn.mimeData().text()
self.file_name=self.file_name[8:]
self.label_picfile.setText(self.file_name)
# 按钮函数
def butn_job(self):
if self.file_name != '':
self.label_state.setText("等")
self.thread_deal = threading.Thread(target=self.deal_pic)
self.thread_deal.start()
else:
self.label_state.setText("拖入图片")
# 压缩图片
def deal_pic(self):
self.butn.blockSignals(True)
t1 = time.time()
source = tinify.from_file(self.file_name)
source.to_file(self.file_name)
t2 = time.time()
t = t2 - t1
compressions_this_month =str(tinify.compression_count)
self.setWindowTitle("图片压缩" + "本月使用:" + compressions_this_month + "用时:" + str(t))
self.label_state.setText("就绪")
self.butn.blockSignals(False)
self.file_name = ''
self.label_picfile.setText(self.file_name)
if __name__ == "__main__":
tinify.key = "xxxxxxxxxxxxxxxxxxxxxxxxx"
app = QApplication(sys.argv)
xiyue = xiiyue()
xiyue.show()
sys.exit(app.exec_())