1. 程式人生 > 其它 >Python的tkinter和pyinstaller打造易用的工具

Python的tkinter和pyinstaller打造易用的工具

Python 可執行檔案 圖形化工具

Python工具

打造可執行的工具,方便其他人使用

命令列工具

命令列工具還是需要了解基本的路徑等資訊

影象化介面工具

tkinter
介面與邏輯分離
  UI執行緒和邏輯執行緒的分離
  TKinter自身重新整理GUI是單執行緒的 
    GUI放在主執行緒中,而其他程式碼放在工作執行緒中,並在它們之間使用執行緒安全佇列進行通訊
主執行緒輪詢是否有回撥事件或者資料改變。不論是 Pub/Sub 的方案,還是 Event 的方案,本質上都是這樣一種 loop
解決多執行緒與 UI 執行緒互動的問題:  解決辦法是利用繼承實現介面和業務邏輯的分離
解決GUI阻塞,而且不在子執行緒裡更新GUI的辦法,還是利用python自帶的佇列Queue,以及Tkinter下面的after方法。

程式碼

#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# FileName: Openfile

import tkinter as tk
import tkinter.filedialog
import tkinter.dialog
import threading
import time


def fmt_time(time_stamp):
    time_array = time.localtime(time_stamp)
    date_time = time.strftime("%Y-%m-%d %H:%M:%S", time_array)
    return date_time


class GUI():
    def __init__(self, root_win):
        # top level的根視窗
        root_win.title("檔案處理")
        # 建立主框架frame,採用相對佈局pack,有兩個大frame,上下
        frame = tk.Frame(root_win)
        frame.pack(side=tk.TOP, padx=100, pady=100)
        # 建立第二層框架frame,放置在主框架frame上。第二層frame有1個放上
        frame_top = tk.Frame(frame)
        frame_top.pack(side=tk.TOP, padx=50, pady=50)
        # side引數,引數可以設定LEFT、RIGHT、TOP 和 BOTTOM 四個方位,預設設定是:side=tkinter.TOP
        # padx, pady 元件外部在x(y)方向上填充的空間大小,預設單位為畫素
        # frame_bom-標誌執行的命令的位置 ,然後在裡面新增一個Button按鈕,框架一般是用於在複雜的佈局起到將元件分組作用
        frame_bom = tk.LabelFrame(root_win, text="執行", labelanchor="n")
        frame_bom.pack(side=tk.BOTTOM, padx=50, pady=50)

        # ###### frame_top
        # 開啟檔案
        # 建立一個按鈕元件,fg=foreground的縮寫,就是設定前景色
        self.open_there = tk.Button(frame_top, text="開啟檔案", fg="blue", command=self.askopenfilename)
        self.open_there.grid(row=0)
        # 設定文字顯示框
        self.input_text_show = tk.Text(frame_top, width=30, height=2)
        self.input_text_show.tag_config("tag_1", backgroun="yellow", foreground="red")
        self.input_text_show.grid(row=0, column=1)

        # 儲存檔案
        # # 建立一個按鈕元件,fg=foreground的縮寫,就是設定前景色
        self.save_there = tk.Button(frame_top, text="儲存位置", fg="green", command=self.asksaveasfile)
        self.save_there.grid(row=1)
        # # 設定文字顯示框
        self.out_text_show = tk.Text(frame_top, width=30, height=2)
        self.out_text_show.tag_config("tag_2", backgroun="yellow", foreground="red")
        self.out_text_show.grid(row=1, column=1)

        # define options for opening or saving a file
        self.file_opt = options = {}
        options['defaultextension'] = '.txt'
        options['filetypes'] = [('all files', '.*'), ('text files', '.txt')]
        options['initialdir'] = 'C:\\Users'
        options['initialfile'] = 'myfile.txt'
        options['parent'] = root_win
        options['title'] = u'選擇檔案'

        # ###### frame_bom
        # 第二部分frame
        # # # 建立一個按鈕元件,fg=foreground的縮寫,就是設定前景色
        self.click_there = tk.Button(frame_bom, text="click", fg="red", width=10, command=self.deal_file_thread)
        self.click_there.pack(side=tk.LEFT, padx=20, pady=20)

    def askopenfilename(self):
        # get filename 不定長引數--** 以字典的方式接收引數
        filename = tkinter.filedialog.askopenfilename(**self.file_opt)
        # open file on your own
        if filename is not None:
            self.input_text_show.insert(tk.END, '\n' + filename + '\n')
            return self.input_text_show.get(tk.END)

    def asksaveasfile(self):
        """Returns an opened file in write mode."""
        file_wrapper = tkinter.filedialog.asksaveasfile(mode='w', **self.file_opt)
        if file_wrapper is not None:
            file_text_out = file_wrapper.name
            return self.out_text_show.insert(tk.END, file_text_out)

    def __dealfile(self):
        """Returns an opened file in write mode."""
        file_text_in = self.input_text_show.get('1.0', tk.END)
        input_file = file_text_in.replace('\n', '')
        file_text_out = self.out_text_show.get('1.0', tk.END)
        out_file = file_text_out.replace('\n', '')
        with open(input_file, mode='r', encoding='utf-8') as fr, \
                open(out_file, mode="w", encoding='utf-8') as fw:
            i = 0
            while i < 3:
                print(fmt_time(time.time()))
                time.sleep(1)
                i += 1
            for data in fr:
                fw.write(data)
        tk.dialog.Dialog(None, {'title': 'File Modified', 'text': '儲存完成', 'bitmap': 'warning', 'default': 0,
                                'strings': ('OK', 'Cancle')})
        print('儲存完成')

    def deal_file_thread(self):
        T = threading.Thread(target=self.__dealfile, args=())
        T.start()


if __name__ == "__main__":
    root_wins = tk.Tk()
    GUI(root_wins)
    root_wins.mainloop()

打包成exe檔案

Pyinstaller
將 Python 程式打包成一個獨立可執行軟體包,支援 Windows、Linux 和 Mac OS X
  pip install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple
使用:
   -F,-onefile	產生單個的可執行檔案
 Pyinstaller.  -F D:\PyWindEXE\Openfile.py -i D:\PyWindEXE\my.ico  --noconsole

參考

 Python多處理將子程序的stdout重定向到Tkinter Text https://www.icode9.com/content-3-482676.html
Python GUI:Tkinter——08 https://blog.csdn.net/weixin_42141390/article/details/106583809
在tkinter中使用Queue(執行緒,Python 3)  https://www.pythonheidong.com/blog/article/474937/ee9fad5702114ab469fd/
Tkinter 吐槽之一:多執行緒與 UI 互動 https://www.cnblogs.com/libitum/p/14848615.html
【Python】TKinter在多執行緒時重新整理GUI的一些碎碎念 https://blog.csdn.net/u013700771/article/details/103321783
Python GUI庫TKinter子執行緒與主執行緒控制元件傳遞訊息策略 https://blog.csdn.net/l198738655/article/details/113564328