【Python-利用动态二维码传输文件(五)】动态二维码文件发送端开发,使用Tkinter filedialog实现任意格式文件选中,并显示发送状态

2023-11-17

        之前四篇文章论证了利用二维码传输文件的可行性,本章使用tkinter开发【动态二维码文件发送端】,发送端具备文件选择、开始发送文件、停止发送文件以及显示发送状态的功能,程序界面下:

 

这里下载源码运行↓↓↓       

使用tkinter开发动态二维码文件发送端-图像识别文档类资源-CSDN下载    


目录

一、程序的界面设计

二、tkinter选择文件功能开发

三、文件拆分成二维码功能开发

四、发送和停止线程开发

五、发送状态更新功能开发

六、运行效果和完整代码


        经过简单分析,要开发该程序,需要完成以下五个步骤,1)程序的界面设计;2)选择文件功能开发;3)文件拆分成二维码功能开发;4)发送和停止线程开发;5)发送状态更新功能开发。接一下一个一个步骤进行研究。

一、程序的界面设计

        程序界面内容不多,只需用到图片显示组件、文本组件、按钮组件,然后使用tkinter的网格布局.grid(row=,column=,......)把组件放置在对应的位置即可。由于文件路径、图片、状态会随着用户的操作发生变化,这里把文件路径变量_label_filepath、图片对象变量_label_dt、进度和状态变量_label_progress_text_label_state_text设置为程序的全局变量,方便后续开启线程调用全局global变量,更新上述组件。

        主要代码如下:

from tkinter import Tk, Label, Button, StringVar
from PIL import Image, ImageTk

# 显示图片组件
_label_dt = None
# 显示文件路径组件,_label_filepath_text为文件路径
_label_filepath_text = None
# 显示发送状态组件,_label_progress_text为进度,_label_state_text为状态
_label_progress_text = None
_label_state_text = None

def open_window():
    # 创建窗口
    root = Tk()
    # 设置窗口的标题
    root.title("动态二维码文件发送端")
    # 创建图片组件,None.png为未启动发送时的默认图片
    _pil_image = Image.open('None.png')
    # 缩放图片
    _w, _h = _pil_image.size
    _pil_image_resized = resize(_w, _h, 300, 300, _pil_image)
    _tk_image = ImageTk.PhotoImage(_pil_image_resized)
    # 创建图片组件,放置在root中
    global _label_dt
    _label_dt = Label(root, image=_tk_image, width=300, height=300)
    _label_dt.grid(row=0, columnspan=4, column=0)
    _button = Button(root, text="选择待发送文件......", command=open_file)
    _button.grid(row=1, column=0,columnspan=2)
    # 创建label可变文本,用于动态更新选中的文件路径
    global _label_filepath_text
    _label_filepath_text = StringVar()
    _label_filepath = Label(root, textvariable=_label_filepath_text)
    _label_filepath.grid(row=1,column=2, columnspan=2)
    # 创新开始、停止按钮
    _button_start = Button(root, text="开始发送", command=start_send_file)
    _button_stop = Button(root, text="停止发送", command=stop_send_file)
    _button_start.grid(row=2, column=0)
    _button_stop.grid(row=2, column=1)
    # 创建label可变文本,用于动态更新发送文件状态
    global _label_progress_text
    _label_progress_text = StringVar()
    _label_progress_text.set("[0/0]")
    _label_progress = Label(root, textvariable=_label_progress_text)
    _label_progress.grid(row=2, column=2)
    # 创建label可变文本,用于动态更新发送文件状态
    global _label_state_text
    _label_state_text = StringVar()
    _label_state_text.set("待发送")
    _label_state = Label(root, textvariable=_label_state_text)
    _label_state.grid(row=2, column=3)
    # 显示窗口
    root.mainloop()

# 缩放图片的函数,w是原来图片的宽,h是原来图片的高,w_box是想缩放的宽,h_box是想缩放的高
# pil_image是原图片对象,函数会返回一个缩放好的图像对象
def resize(w, h, w_box, h_box, pil_image):
    f1 = 1.0 * w_box / w
    f2 = 1.0 * h_box / h
    factor = min([f1, f2])
    width = int(w * factor)
    height = int(h * factor)
    return pil_image.resize((width, height), Image.Resampling.LANCZOS)

二、tkinter选择文件功能开发

        第三篇文章中的python程序是通过固定地址读取默认图片文件的。本章为了增加程序的灵活性,实现用户自行选择待发送文件功能。

        经过百度搜索和学习,发现tkinter中的filedialog可实现文件选取功能。下面编写open_file函数实现该功能,open_file函数通过filedialog.askopenfilename()获取用户选择的文件路径,然后使用_label_filepath_text.set()方法,把用户选中文件路径更新到界面中。

        主要代码如下:

from tkinter import filedialog

# 选择待发送的文件
def open_file():
    _file_path = filedialog.askopenfilename(title=u'选择文件', initialdir=(os.path.expanduser('C:/')))
    if _file_path is not None:
        # 设置并显示选中的文件路径
        global _label_filepath_text
        _label_filepath_text.set(_file_path)
        print(get_file_size(_file_path))
    return _file_path

        显示效果如下:

选择待发送文件

显示选中的文件全路径

三、文件拆分成二维码功能开发

        文件拆分成二维码,在之前几篇文章中都有介绍,这里就不多说了。本章主要对拆分代码进行优化:

        1)拆解前先对文件进行压缩(使用了zlib库进行压缩),减少拆分发送二维码的数量;

        2)为了简化后续接收端程序的分析难度,这里将每张二维码所处的位置、二维码总张数、发送文件类型也存入数据中。

        例如在第一帧数据中加入[1/51]文件名.xlsx前缀,接收端读取信息后就可以判断该帧处于什么位置,并知道数据一共有多少帧,是什么格式的文件。关键代码如下:

# 使用math.ceil向上取整获得分块数_frequency,并加上自己制作的第一帧,所以分块数+1
_frequency = math.ceil(_length / _step_length) + 1
# 生成待发送第一帧信息,格式如:[1/51]文件名.xlsx
_temp_str_utf8 = "[%d/%d]%s" % (1, _frequency, os.path.basename(_file_path))

        3) 利用_label_state_text.set()把拆分的状态实时显示在界面上。

        主要代码如下:

import os
import datetime
import zlib
import base64


# 按固定长度拆分_base64格式的字节流,_file_path为文件路径,_step_length为拆分的固定长度(步长)
def split_file(_file_path, _step_length):
    global _label_state_text
    _start_time = datetime.datetime.now()
    # 使用二进制模式读取以_file_path为路径的文件
    _file = open(_file_path, mode="rb")
    # 一次性读取所有字节(若文件太大请分段读取避免爆内存)
    _label_state_text.set("读取文件")
    _contents = _file.read()
    _label_state_text.set("压缩文件")
    _contents_zip = zlib.compress(_contents, zlib.Z_BEST_COMPRESSION)
    # 转换为_base64格式方面传输数据
    _label_state_text.set("编码")
    _contents_base64 = base64.b64encode(_contents_zip)
    # 调用拆分函数
    _base64_str_list = []
    # 字节流长度
    _length = len(_contents_base64)
    # 使用math.ceil向上取整获得分块数_frequency,并加上自己制作的第一帧,所以分块数+1
    _frequency = math.ceil(_length / _step_length) + 1
    # 生成待发送第一帧信息,格式如:[1/51]文件名.xlsx
    _temp_str_utf8 = "[%d/%d]%s" % (1, _frequency, os.path.basename(_file_path))
    _base64_str_list.append(_temp_str_utf8)
    # 循环拆分字节流
    _label_state_text.set("拆分文件信息")
    _j = 2
    for i in range(0, _length, _step_length):
        _temp_str = _contents_base64[i:i + _step_length]
        _temp_str_utf8 = "[%d/%d]%s" % (_j, _frequency, _temp_str.decode('utf-8'))
        _base64_str_list.append(_temp_str_utf8)
        _j = _j + 1
    _end_time = datetime.datetime.now()
    print("拆分块数:%d" % (_frequency))
    print("拆分文件用时(秒):%d" % ((_end_time - _start_time).seconds))
    return _base64_str_list

四、发送和停止线程开发

        文件拆分好后就可以动态生成二维码了,动态显示二维码在第三篇文章中已经探讨过,本章主要对代码进行优化。

        1)打印的二维码不用先拼接成链表,可边拆解边显示二维码;

        2)可以控制动态二维码的开始和暂停,由于目前没发现pythonthread类的停止方法,所以使用循环判断全局变量标志_thread_flag的方法控制线程结束。

        主要代码如下:

_thread_flag = None
_thread = None

# 根据拆分后的字节流列表动态显示二维码,_base64_str_list为拆分后的字节列表,_time_interval为显示间隔
def print_qr(_base64_str_list, _time_interval):
    global _thread_flag
    # 循环生成二维码图片
    _qr = qrcode.QRCode()
    _pil_image = None
    _pil_image_resized = None
    _tk_image = None
    _list_len = len(_base64_str_list)
    global _label_state_text
    _label_state_text.set("文件发送中")
    while _thread_flag is True:
        for i in range(0, _list_len):
            # 判断_thread_flag的值,当为False时中断执行
            if _thread_flag is True:
                # 1)清空原_qr对象数据;2)把列表中的数据加入_qr对象中
                _qr.clear()
                _qr.add_data(_base64_str_list[i], 0)
                # 1)根据列表中的数据制作二维码图片;2)缩放图片;3)显示在界面上
                _pil_image = _qr.make_image()
                _w, _h = _pil_image.size
                _pil_image_resized = resize(_w, _h, 300, 300, _pil_image)
                _tk_image = ImageTk.PhotoImage(_pil_image_resized)
                # 更新二维码显示组件_label_dt
                global _label_dt
                _label_dt.configure(image=_tk_image)
                _label_dt.image = _tk_image
                global _label_progress_text
                _label_progress_text.set("[%d/%d]" % (i, _list_len))
                # 设置二维码刷新时间间隔
                time.sleep(_time_interval)
            else:
                break


# 用于更新图片的线程
def update_qr_thread(_base64_str_list, _time_interval):
    # 设置更新频率为_time_interval秒
    # 设置线程参数,target为线程启动函数,name为线程名,args为传递给线程函数的参数
    global _thread
    _thread = threading.Thread(target=print_qr, name='print_qr', args=(_base64_str_list, _time_interval,))
    # 启动线程
    _thread.start()


# 点击,发送文件
def start_send_file():
    global _label_filepath_text, _thread_flag, _thread, _label_state_text
    if _label_filepath_text is not None:
        if (_thread is None) or (_thread.is_alive() is False):
            _f_size = get_file_size(_label_filepath_text.get())
            if 0 < _f_size < 2:
                # 拆分选中文件
                _temp_list = split_file(_label_filepath_text.get(), 512)
                # 调用二维码生成函数
                _thread_flag = True
                update_qr_thread(_temp_list, 0)
            else:
                _label_state_text.set("文件应小于2MB")
        else:
            _label_state_text.set("有发送任务正在进行")


# 点击,停止发送文件
def stop_send_file():
    global _thread_flag
    _thread_flag = False

五、发送状态更新功能开发

        界面状态更新相对简单,图片使用_label_dt.configure(image=_tk_image)更新,文字使用StringVar类调用_label_state_text.set()即可。

六、运行效果和完整代码

       

 这里下载源码运行↓↓↓       

使用tkinter开发动态二维码文件发送端-图像识别文档类资源-CSDN下载    

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Python-利用动态二维码传输文件(五)】动态二维码文件发送端开发,使用Tkinter filedialog实现任意格式文件选中,并显示发送状态 的相关文章

随机推荐

  • I2S与pcm的区别

    I2S仅仅是PCM的一个分支 接口定义都是一样的 I2S的采样频率一般为44 1KHZ和48KHZ做 PCM采样频率一般为8K 16K 有四组信号 位时钟信号 同步信号 数据输入 数据输出 I2S总线标准 I2S Inter IC Soun
  • python 调用C DLL库 传参(传递数字、字符串、数组(一维、二维)、结构体)

    usr bin env python conding utf 8 from itertools import filterfalse import PySimpleGUI as sg from ctypes import cdll from
  • 如何将tomcat的http访问,改为https方式访问

    在执行以下操作的时候 需要先了解一个证书生成工具 keytool 他是jdk自带的证书管理工具 在jdk bin目录下 可以用来生成自签名证书 导入导出证书 打印证书信息等 整个过程分为两部分 第一部分是证书的生成 第二部分是修改tomca
  • C语言 五子棋游戏(也可n子棋)

    目录 1 创造棋盘 2 玩家下棋 3 电脑下棋 4 判断输赢 赢的判断 也是最难的 行的判断 列的判断 主副对角线的判断 花费时间最长 平局或者继续 最后判断的全部代码 三个文件的代码 头文件的引用及函数的声明 测试部分 函数的实现 一个文
  • 系统架构师—软件架构设计(一)概述、构建、视图、基本架构风格

    1 软件架构概述 从需求分析到软件设计之间的过渡过程称为软件架构 只要软件架构设计好了 整个软件就不会出现坍塌性的错误 即不会崩溃 架构设计就是需求分配 将满足需求的职责分配到组件上 软件架构为软件系统提供了一个结构 行为和属性的高级抽象
  • 【机器学习】python使用支持向量机SVM

    机器学习 python使用支持向量机SVM 准备 数据集 导入SVM模块 步骤 1 读取数据集 2 划分训练样本与测试样本 3 训练SVM分类器 4 计算分类准确率 5 绘制图像 关于SVM的原理知识 在 机器学习 支持向量机中讲过 欲知详
  • 最近火出圈的GPT-4 技术Report出来了,快进来看看逐文对照翻译!

    近期OpenAI发布的GPT 4的效果好得让人惊艳 碾压了之前火到出圈的ChatGPT 通过同步发布的GPT 4 Technical Report一同看看到底发生了什么 No 0 摘要 We report the development o
  • 微服务网关 —— SpringCloud Gateway

    Gateway 简介 Spring Cloud Gateway 基于 Spring 5 Spring Boot 2 和 Project Reactor 等技术 是在 Spring 生态系统之上构建的 API 网关服务 Gateway 旨在提
  • 剑指offer 06 从尾到头打印链表

    题目 从尾到头打印链表 输入一个链表的头节点 从尾到头反过来返回每个节点的值 用数组返回 示例 输入 head 1 3 2 输出 2 3 1 题解一 栈 解法 遍历链表 将所有遍历到的值压入栈中 再利用栈 后进先出 的特性 从尾到头打印链表
  • STM32 进阶教程 1 - micropython 移植

    前言 Python是一种解释型 面向对象 动态数据类型的高级程序设计语言 Python 是一个高层次的结合了解释性 编译性 互动性和面向对象的脚本语言 具有如下特点 1 易于学习 Python有相对较少的关键字 结构简单 和一个明确定义的语
  • ChatGPT Prompting开发实战(五)

    一 如何编写有效的prompt 对于大语言模型来说 编写出有效的prompt能够帮助模型更好地理解用户的意图 intents 生成针对用户提问来说是有效的答案 避免用户与模型之间来来回回对话多次但是用户不能从LLM那里得到有意义的反馈 本文
  • outbound和inbound关系

    Inbound PCI域訪问存储器域 Outbound 存储器域訪问PCI域 RC訪问EP RC存储器域 gt outbound gt RC PCI域 gt EP PCI域 gt inbound gt EP存储器域 EP訪问RC EP存储器
  • python实现主成分估计

    什么是PCA 主成分分析的主要目的是希望用较少的变量去解释原来资料中的大部分变异 将我们手中许多相关性很高的变量转化成彼此相互独立或不相关的变量 通常是选出比原始变量个数少 能解释大部分资料中的变异的几个新变量 即所谓主成分 并用以解释资料
  • python编程基础知识

    python 切片 可以对list对象 如 1 2 3 4 字符串对象 1234 进行切片 使用 str l r str截取索引范围为 l r 索引值可以为负 表示从倒数方向 如 1表示倒数第一项 例 str 123456 str 0 2
  • 微信小程序开发之数据存储 参数传递 数据缓存

    微信小程序开发内测一个月 数据传递的方式很少 经常遇到页面销毁后回传参数的问题 小程序中并没有类似Android的startActivityForResult的方法 也没有类似广播这样的通讯方式 更没有类似eventbus的轮子可用 现在已
  • sql_labs18

    刚拿到题目时一点头绪没有 虽然提示是user agent注入 但没登录之前是看不到有关信息的 之后经过查看知道了两个admin就可以登录上 并且可以查看到user agent信息 判断闭合符 在User Agent字段结束添加单引号 触发报
  • esp32开发板学习

    1 esp32简介 esp32说到底就是一个小型的linux 可以执行我们的代码 尺寸只有一个苹果watch se的大小 可以集成各个物理组件 好像是通过开发板上的引脚来操作的 2 开发板部署python环境 2 1 在pdd花10块钱买了
  • 关闭文件指针不对

    浏览代码时看到下面几行代码 大家看看有啥问题 其中隐含的问题是关闭空的文件指针 所以写了一个测试代码 运行一下 挂了
  • C++模板类重载"<<"未定义错误

    在使用C 的模板类进行编程的时候 重载 lt lt 运算符时 如果定义不当 会出现未定义的情况 错误为LNK2019 这个问题的原因是由于C 的模板编译机制造成的 解决问题的方式是在类中声明 lt lt 运算符时 需要在运算符和参数之间的位
  • 【Python-利用动态二维码传输文件(五)】动态二维码文件发送端开发,使用Tkinter filedialog实现任意格式文件选中,并显示发送状态

    之前四篇文章论证了利用二维码传输文件的可行性 本章使用tkinter开发 动态二维码文件发送端 发送端具备文件选择 开始发送文件 停止发送文件以及显示发送状态的功能 程序界面下 这里下载源码运行 使用tkinter开发动态二维码文件发送端