摘要
记一次写程序时遇到的跟图片有关的编程。用python写程序时,跟图片有关的地方大致有以下三个:
- 桌面图标
- 运行图标
- 背景图片
所需模块说明
- from io import BytesIO
- from PIL import Image as Imagep
- from PIL.ImageQt import ImageQt
- import base64
运行图标、背景图片编程
运行图标与背景图片的写法有些类似,所以放到一起,桌面图标将放到后面进行讲解
- 本程序对图片采用base64编码存储的方式,将图片存于py文件中,这样的好处是程序可以单独运行,不需依赖图片文件
- 由于base64编码过长,代码中将用xuanwo_base64、sidai_base64代替,图片转base64编码的方法在百度上搜索即可
- 代码分为两部分,第一部分为处理base64编码并将其设置为运行图标的代码;第二部分为处理base64编码并将其设置为背景图片的编码
- 代码详细作用在注释中皆有说明
代码:
# 运行图标部分
# 图片的base64编码
photo_xuanwo = u"xuanwo_base64"
# 解码为二进制数据
data_xuanwo = base64.b64decode(photo_xuanwo)
# 使用BytesIO对数据进行封装
pack_xuanwo = BytesIO(data_xuanwo)
# 打开图片
image_path_xuanwo = Imagep.open(pack_xuanwo)
# 显示图片
# image_path_xuanwo.show()
# ImageQt方法使图片可作为变量使用
image_vari_xuanwo = ImageQt(image_path_xuanwo)
# 将图片设置为运行图标
self.setWindowIcon(QIcon(QPixmap.fromImage(image_vari_xuanwo)))
# 背景图片部分
photo_sidai = u"sidai_base64"
data_sidai = base64.b64decode(photo_sidai)
pack_sidai = BytesIO(data_sidai)
image_path_sidai = Imagep.open(pack_sidai)
image_vari_sidai = ImageQt(image_path_sidai)
# 创建调色板
window_pale = QPalette()
# 在调色板中插入图片
window_pale.setBrush(self.backgroundRole(), QBrush(QPixmap.fromImage(image_vari_sidai)))
# 将调色板应用到窗体作为背景图片
self.setPalette(window_pale)
桌面图标编程
程序采用pyinstaller模块对程序进行封装打包。如果不做处理,打包后程序会默认显示系统图标。如需自定义图标,需按以下步骤进行:
步骤:
- 制作.ico图片,.ico图片的转化方法也是在百度上搜索即可
- 打开cmd,执行命令“pyinstaller -wF --icon=桌面图标.ico 程序.py”
- -w : 不显示命令行窗口
- -F : 产生单个的可执行文件
- --icon : 指定ico图片作为桌面图标
3.等待命令执行完成即可得到可单独执行的.exe程序
注:本人试过打包时不加--icon参数,即省略最后桌面图标那一步,发现程序在特定环境下依然能显示运行图标指定的图片。而我最初设想的也是如此,但是它在大多时候显示为系统默认图标,不理解为何,如有大神知道的可以评论解惑下~
------------------------------------------------------------------------------------------------------------------------------------------
最后附上整个程序的代码以供参考(作用是对txt文本内容进行格式处理,只为实现功能,无建立工作空间及未优化)
# coding=utf-8
import sys, os, time, re
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from tkinter import *
from io import BytesIO
from PIL import Image as Imagep
from PIL.ImageQt import ImageQt
import base64
# 函数辅助工具模块
from functools import partial
import chardet
class DelTheEnd(QMainWindow):
def __init__(self):
# 图片的base64编码
photo_xuanwo = u"xuanwo"
# 解码为二进制数据
data_xuanwo = base64.b64decode(photo_xuanwo)
# 使用BytesIO对数据进行封装
pack_xuanwo = BytesIO(data_xuanwo)
# 打开图片
image_path_xuanwo = Imagep.open(pack_xuanwo)
# 显示图片
# image_path_xuanwo.show()
# 使用ImageQt使图片可指向变量
image_vari_xuanwo = ImageQt(image_path_xuanwo)
photo_sidai = u"sidai"
data_sidai = base64.b64decode(photo_sidai)
pack_sidai = BytesIO(data_sidai)
image_path_sidai = Imagep.open(pack_sidai)
image_vari_sidai = ImageQt(image_path_sidai)
# 继承QMainWindow初始设置
super().__init__()
# 设置主窗体大小、位置
self.resize(800, 400)
self.setFixedSize(800, 400) # 限定窗体最大大小
self.move(700, 220)
# 标题
self.setWindowTitle("格式 & 排序")
vt = self.frameGeometry()
# 图标
self.setWindowIcon(QIcon(QPixmap.fromImage(image_vari_xuanwo)))
# 设置背景图片
window_pale = QPalette()
window_pale.setBrush(self.backgroundRole(), QBrush(QPixmap.fromImage(image_vari_sidai)))
self.setPalette(window_pale)
# 居中
rs = QDesktopWidget().availableGeometry().center()
vt.moveCenter(rs)
self.move(vt.topLeft())
self.widget()
# 控制窗体显示的开关
self.show()
# 全局变量,决定自定义部分中输出文本的样式顺序
self.list_range = []
def widget(self):
'''
窗体样式、布局
:return:
'''
# 文件选择部分
docu = QLabel("-------------------------选择文件-------------------------", self)
# 文档路径显示,默认为当前程序路径
self.lineedit_path = QLineEdit(os.path.dirname(os.path.realpath(sys.argv[0])), self)
browsebutton = QPushButton("浏览", self)
# 关联路径选取的“browsing”事件
browsebutton.clicked.connect(self.browsing)
dealbutton = QPushButton("确定", self)
# 关联格式选取的“radiotext”事件
dealbutton.clicked.connect(self.radiotext)
dealbutton.setToolTip("显示格式内容")
rangebutton = QPushButton("排序",self)
# 关联内容排序的“range”事件
rangebutton.clicked.connect(self.range)
rangebutton.setToolTip('''将内容排序并输出到"xxx - 排序.txt"''')
# 格式选择部分
select = QLabel("-------------------------选择格式-------------------------", self)
# 生成单选按钮
bg = QButtonGroup(self)
# 第一种输出格式
self.rb1 = QRadioButton("格式1", self)
# 默认选择第一种
self.rb1.setChecked(True)
# 第二种输出格式
self.rb2 = QRadioButton("格式2", self)
# 第三种输出格式
self.rb3 = QRadioButton("格式3", self)
bg.addButton(self.rb1)
bg.addButton(self.rb2)
bg.addButton(self.rb3)
selectbutton = QPushButton("确定", self)
# 关联文档处理并输出最终结果的“deal1”事件
selectbutton.clicked.connect(self.deal1)
# 自定义部分
custom = QLabel("-------------------------自定义-------------------------", self)
# 显示自定义格式
self.lineedit_format = QLineEdit("", self)
# 特殊符号按钮
spacebutton = QPushButton("space", self)
spacebutton.clicked.connect(lambda : self.format(' '))
tabbutton = QPushButton("tab", self)
tabbutton.clicked.connect(lambda : self.format(' '))
leftbracketbutton = QPushButton("【", self)
leftbracketbutton.clicked.connect(lambda : self.format('【'))
rightbracketbutton = QPushButton("】", self)
rightbracketbutton.clicked.connect(lambda : self.format('】'))
# 清除自定义格式按钮
clearbutton = QPushButton("重置", self)
clearbutton.setToolTip("重置自定义格式")
# 关联“clear”事件
clearbutton.clicked.connect(self.clear)
custombutton = QPushButton("确定", self)
# 关联文档处理并输出最终结果的“deal2”事件
custombutton.clicked.connect(self.deal2)
# 横纵布局
# 第一横向空间
hbox1 = QHBoxLayout()
# 向右填充
hbox1.addStretch(1)
# 将名为docu的QLabel加入横向空间
hbox1.addWidget(docu)
# 向左填充,最终将docu在横向空间中居中
hbox1.addStretch(1)
# 第二横向空间
hbox2 = QHBoxLayout()
hbox2.addWidget(self.lineedit_path)
hbox2.addWidget(browsebutton)
hbox2.addWidget(dealbutton)
hbox2.addWidget(rangebutton)
# 第三横向空间
hbox3 = QHBoxLayout()
hbox3.addStretch(1)
hbox3.addWidget(select)
hbox3.addStretch(1)
# 第四横向空间
hbox4 = QHBoxLayout()
hbox4.addWidget(self.rb1)
# 第五横向空间
hbox5 = QHBoxLayout()
hbox5.addWidget(self.rb2)
# 第六横向空间
hbox6 = QHBoxLayout()
hbox6.addWidget(self.rb3)
# 第七横向空间
hbox7 = QHBoxLayout()
hbox7.addStretch(1)
hbox7.addWidget(selectbutton)
# 第八横向空间
hbox8 = QHBoxLayout()
hbox8.addStretch(1)
hbox8.addWidget(custom)
hbox8.addStretch(1)
# 第九横向空间
hbox9 = QHBoxLayout()
hbox9.addWidget(self.lineedit_format)
# 第十横向空间
hbox10 = QHBoxLayout()
hbox10.addWidget(spacebutton)
hbox10.addWidget(tabbutton)
hbox10.addWidget(leftbracketbutton)
hbox10.addWidget(rightbracketbutton)
# 第十一横向空间
self.hbox11 = QHBoxLayout()
# 第十二横向空间
self.hbox12 = QHBoxLayout()
self.hbox12.addStretch(1)
self.hbox12.addWidget(clearbutton)
self.hbox12.addWidget(custombutton)
# 第一纵向空间
self.vbox = QVBoxLayout()
# 填入所有横向空间
self.vbox.addLayout(hbox1)
self.vbox.addLayout(hbox2)
self.vbox.addLayout(hbox3)
self.vbox.addLayout(hbox4)
self.vbox.addLayout(hbox5)
self.vbox.addLayout(hbox6)
self.vbox.addLayout(hbox7)
self.vbox.addLayout(hbox8)
self.vbox.addLayout(hbox9)
self.vbox.addLayout(hbox10)
self.vbox.addLayout(self.hbox12)
# 将纵向空间填入主窗口
widget = QWidget()
widget.setLayout(self.vbox)
# 居中
self.setCentralWidget(widget)
def browsing(self):
'''
文档路径选取功能
:return:
'''
filename = QFileDialog.getOpenFileName(self, "选取文件", os.path.dirname(os.path.realpath(sys.argv[0])))
self.lineedit_path.setText(filename[0])
if os.path.exists(filename[0]):
if re.search(".*\.txt", filename[0]):
with open(filename[0], "rb") as f:
read = f.read()
ecd = chardet.detect(read)['encoding']
with open(filename[0], "r", encoding=ecd) as f:
rl = f.readlines()
for line in rl:
if re.search("专场", line):
if re.search("【|】", line):
QMessageBox.warning(self, "Info", "Info:文本包含两部分-标题和正文,标题中不可含有‘【’或‘】’,如确认标题无误,请忽略此提示")
return
else:
QMessageBox.warning(self, "Error", "Error:请选取txt文本文件")
def format(self, select_btn):
'''
根据格式按钮生成对应格式功能
:param 对应按钮的文本:
:return:
'''
sstr = self.lineedit_format.text()
# 符号按钮格式选择
if isinstance(select_btn, str):
sstr += select_btn
if select_btn == " ":
self.list_range.append(0)
elif select_btn == " ":
self.list_range.append(1)
elif select_btn == "【":
self.list_range.append(2)
elif select_btn == "】":
self.list_range.append(3)
# 其他文本按钮格式选择
else:
sstr += select_btn.toolTip()
# 记录按钮顺序,以便之后按格式输出文本
self.list_range.append(3 + int(re.findall('\d+', select_btn.objectName())[0]))
# 显示所选格式
self.lineedit_format.setText(sstr)
def clear(self):
'''
清除所选格式
:return:
'''
self.lineedit_format.setText('')
# 清除记录的顺序
self.list_range = []
def radiotext(self):
'''
文档输出格式选择功能
:return:
'''
# 重置第十一横向空间,使清空里面的控件
self.hbox11.deleteLater()
self.hbox11 = QHBoxLayout()
# 将第十一横向空间插入对应位置
self.vbox.insertLayout(10,self.hbox11)
# 重置自定义格式
self.lineedit_format.setText('')
self.list_range = []
try:
if os.path.exists(self.lineedit_path.text()):
if re.search(".*\.txt", self.lineedit_path.text()):
with open(self.lineedit_path.text(), "rb") as f:
read = f.read()
ecd = chardet.detect(read)['encoding']
with open(self.lineedit_path.text(), "r", encoding=ecd) as f:
rl = f.readlines()
for line in rl:
for word in line:
# 标题内容不处理,对含有“【”的主内容进行处理
if word == "【":
# 选择格式部分功能
list_select = re.split("\s+", line)
# 输出对应格式到单选按钮中
if re.search('\d+\s+【', line):
# 文本内容有序号
self.rb1.setText(list_select[1] + " " + list_select[2])
self.rb2.setText(list_select[2] + " " + list_select[1])
self.rb3.setText(
list_select[2] + " " + re.findall('【.*】(.*)', list_select[1])[0] + " " +
re.findall('【(.*)】.*', list_select[1])[0])
# 提示
self.rb1.setToolTip(list_select[1] + " " + list_select[2])
self.rb2.setToolTip(list_select[2] + " " + list_select[1])
self.rb3.setToolTip(
list_select[2] + " " + re.findall('【.*】(.*)', list_select[1])[0] + " " +
re.findall('【(.*)】.*', list_select[1])[0])
else:
# 文本内容无序号
self.rb1.setText(list_select[0] + " " + list_select[1])
self.rb2.setText(list_select[1] + " " + list_select[0])
self.rb3.setText(
list_select[1] + " " + re.findall('【.*】(.*)', list_select[0])[0] + " " +
re.findall('【(.*)】.*', list_select[0])[0])
# 自定义部分功能
list_old = re.split('\s+|【|】', line)
list_new = []
for ele_old in list_old:
exist = False
if ele_old != '':
for ele_new in list_new:
if ele_new == ele_old.strip():
exist = True
if exist == False:
list_new.append(ele_old)
# 记录按钮名称的列表
count_button = []
for count in range(1, len(list_new) + 1):
count_button.append('button_format' + str(count))
# 生成按钮并自动命名
for count, ele_new in zip(count_button, list_new):
button_name = count
count = QPushButton(ele_new[0:5])
count.setObjectName(button_name)
count.clicked.connect(partial(self.format, count))
count.setToolTip(ele_new)
self.hbox11.addWidget(count)
return
else:
QMessageBox.warning(self, "Error", "Error:请选取txt文本文件")
else:
QMessageBox.about(self, "Error", "Error:文件不存在")
except BaseException as e:
QMessageBox.warning(self, "Warning", str(e))
def range(self):
'''
对所选文本内容进行排序
:return:
'''
try:
if os.path.exists(self.lineedit_path.text()):
if re.search(".*\.txt", self.lineedit_path.text()):
with open(self.lineedit_path.text(), "rb") as f:
read = f.read()
ecd = chardet.detect(read)['encoding']
with open(self.lineedit_path.text(), "r", encoding=ecd) as f:
rl = f.readlines()
# 将文本进行分类,存储于列表中
list_context_ry = []
list_context_rh = []
list_context_qj = []
list_context_qm = []
list_context_qf = []
list_context_qyy = []
list_context_qfz = []
list_context_qxs = []
list_context_qt = []
for line in rl:
if re.search('【', line):
if re.search('【前\d+件', line):
list_context_qj.append(re.findall('\d*\s*(【.+)\n*', line)[0])
elif re.search('【前\d+名', line):
list_context_qm.append(re.findall('\d*\s*(【.+)\n*', line)[0])
elif re.search('【前\d+份', line):
list_context_qf.append(re.findall('\d*\s*(【.+)\n*', line)[0])
elif re.search('【前\d+买一送一', line):
list_context_qyy.append(re.findall('\d*\s*(【.+)\n*', line)[0])
elif re.search('【\d+月\d+日', line):
list_context_rh.append(re.findall('\d*\s*(【.+)\n*', line)[0])
elif re.search('【\d+月\d+号', line):
list_context_ry.append(re.findall('\d*\s*(【.+)\n*', line)[0])
elif re.search('【前\d+分钟', line):
list_context_qfz.append(re.findall('\d*\s*(【.+)\n*', line)[0])
elif re.search('【前\d+小时', line):
list_context_qxs.append(re.findall('\d*\s*(【.+)\n*', line)[0])
else:
list_context_qt.append(re.findall('\d*\s*(【.+)\n*', line)[0])
# 限量部分
# 排序列表中各项
list_context_qj.sort()
list_context_qm.sort()
list_context_qf.sort()
list_context_qyy.sort()
# 合并列表
list_context_qj.extend(list_context_qm)
list_context_qj.extend(list_context_qf)
list_context_qj.extend(list_context_qyy)
# 秒杀部分
list_context_ry.sort()
list_context_rh.sort()
list_context_ry.extend(list_context_rh)
# 限时部分
list_context_qfz.sort()
list_context_qxs.sort()
list_context_qfz.extend(list_context_qxs)
# 其他部分
list_context_qt.sort()
# 整合所有分类并排序后内容
new_contrxt = ""
list_all_new = [list_context_qj, list_context_ry, list_context_qfz, list_context_qt]
for i in list_all_new:
for j in i:
new_contrxt += j + '\n'
new_contrxt += '\n'
# 将排序后内容输出到“xxx - 顺序.txt”
with open(self.lineedit_path.text().split('.txt')[0] + ' - 顺序.txt', "w", encoding=ecd) as f:
f.write(new_contrxt)
# 自动将路径定位到排序后文本
self.lineedit_path.setText(self.lineedit_path.text().split('.txt')[0] + ' - 顺序.txt')
QMessageBox.about(self, "Info", "Info:排序完成")
else:
QMessageBox.warning(self, "Error", "Error:请选取txt文本文件")
else:
QMessageBox.about(self, "Error", "Error:文件不存在")
except BaseException as e:
QMessageBox.warning(self, "Warning", str(e))
def deal1(self):
'''
三种常见格式部分,将结果输出到文档中
:return:
'''
try:
self.new = ""
with open(self.lineedit_path.text(), "rb") as f:
read = f.read()
ecd = chardet.detect(read)['encoding']
with open(self.lineedit_path.text(), "r", encoding=ecd) as f:
self.old = f.readlines()
for line in self.old:
# 判断是否为主内容的开关,当为True时进入主内容
exixst = False
for word in line:
if word == "【":
exixst = True
break
if exixst == True:
# 将主内容按“空格、tab、回车”进行分割
list = re.split("\s+", line)
# 将主内容按不同格式进行排序
if re.search('\d+\s+【', line):
# 文本内容有序号
if self.rb1.isChecked() == True:
self.new += (list[1] + " " + list[2] + "\n")
elif self.rb2.isChecked() == True:
self.new += (list[2] + " " + list[1] + "\n")
elif self.rb3.isChecked() == True:
self.new += (list[2] + " " + re.findall('【.*】(.*)', list[1])[0] + " " +
re.findall('【(.*)】.*', list[1])[0] + "\n")
else:
# 文本内容无序号
if self.rb1.isChecked() == True:
self.new += (list[0] + " " + list[1] + "\n")
elif self.rb2.isChecked() == True:
self.new += (list[1] + " " + list[0] + "\n")
elif self.rb3.isChecked() == True:
self.new += (list[1] + " " + re.findall('【.*】(.*)', list[0])[0] + " " +
re.findall('【(.*)】.*', list[0])[0] + "\n")
else:
self.new += "\n" + line
# 写入结果
with open(self.lineedit_path.text().split('.txt')[0] + ' - 格式.txt', 'w', encoding=ecd) as f:
f.write(self.new)
time.sleep(2)
self.lineedit_path.setText(self.lineedit_path.text().split('.txt')[0] + ' - 格式.txt')
QMessageBox.about(self, "Info", "Info:完成")
except BaseException as e:
QMessageBox.warning(self, "Warning", str(e))
def deal2(self):
'''
自定义部分,将结果输出到文档中
:return:
'''
try:
self.new = ""
with open(self.lineedit_path.text(), "rb") as f:
read = f.read()
ecd = chardet.detect(read)['encoding']
with open(self.lineedit_path.text(), "r", encoding=ecd) as f:
self.old = f.readlines()
for line in self.old:
# 判断是否为主内容的开关,当为True时进入主内容
exixst = False
for word in line:
if word == "【":
exixst = True
break
if exixst == True:
# 将主内容按“空格、tab、回车”进行分割
list_old = re.split('\s+|【|】', line)
# 记录文本行内容
list_new = [' ', ' ', '【', '】']
for ele_old in list_old:
exist = False
if ele_old != '':
for ele_new in list_new:
if ele_new == ele_old.strip():
exist = True
if exist == False:
list_new.append(ele_old)
# 按所选格式将文本行内容排序重新输出
for rrange in self.list_range:
self.new += list_new[rrange]
self.new += "\n"
else:
self.new += "\n" + line
# 写入结果
with open(self.lineedit_path.text().split('.txt')[0] + ' - 格式.txt', 'w', encoding=ecd) as f:
f.write(self.new)
time.sleep(2)
self.lineedit_path.setText(self.lineedit_path.text().split('.txt')[0] + ' - 格式.txt')
QMessageBox.about(self, "Info", "Info:完成")
except BaseException as e:
QMessageBox.warning(self, "Warning", str(e))
if __name__ == "__main__":
app = QApplication(sys.argv)
w = DelTheEnd()
sys.exit(app.exec_())