摘要
記一次寫程序時遇到的跟圖片有關的編程。用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_())