2021-02-23 调用excel数据,修改单元格格式,并用tkinter制作图片浏览器直观查看

前言

女朋友这两天提了个需求,需要从mysql调数据生成图表,并直观显示图片可供截图,有需求就要满足,并且这次因为代码不是写给自己看的,所以要美观整洁,打好注释
从mysql调数据的代码她自己写了,我这里就用一张excel表来代替,到时候只要她自己改,调用就可以了

代码

import xlwings as xw
from PIL import ImageGrab,ImageTk
from tkinter import *
from tkinter import messagebox
from tkinter.ttk import *                                           # 界面美化
from PIL import Image                                               # 调用顺序不可提前,否则下方Image.open会识别为tkinter中的image
import os
import pandas as pd
import datetime
import time

#======================================== 获取excel数据,并导入新的工作表中 =====================================
def get_data():
    df = pd.read_excel('data.xlsx',sheet_name='Sheet1')             # 读取excel表数据,生成dataframe
    df_entry = df[df['来源分区'].isin([name_entry.get()])]           # 用isin函数筛选输入框内来源分区的数据
    df_empty = df[df['来源分区'].isin(["不存在"])]                   # 定义一个空df表,用于判定df_entry获得的数据是否存在

    global empty                                                    # 声明empty为全局变量,用于判定后续函数是否执行

    if df_entry.equals(df_empty):                                   # 如果df_entry获得的数据为不存在,给empty变量赋值为1
        empty = 1
    else:                                                           # 如果df_entry获得的数据存在,执行导出df表到excel,并给empty变量赋值为0
        df_entry.to_excel(path, index=False)
        empty = 0
#===============================================================================================================

#============================================ 更改表格样式 =======================================================
def form_style():
    app = xw.App(visible=False, add_book=False)                     # 打开excel程序
    wb = app.books.open(path)                                       # 打开需要的工作簿
    sht = wb.sheets[0]                                              # 定位工作表

    k = 17                                                          # 每隔15条数据插入一行,用于后方代码复制列索引
    while k <= sht.used_range.last_cell.row:
        sht.api.Rows(k).Insert()
        k += 16

    max_row = sht.used_range.last_cell.row                          # 获取表格最大行数
    max_column = sht.used_range.last_cell.column                    # 获取表格最大列数
    sht.used_range.autofit()                                        # 所有单元格自适应列宽行高
    sht.used_range.api.HorizontalAlignment = -4108                  # 将所有单元格格式设置为水平居中
    sht.used_range.api.Font.Name = "Microsoft YaHei"
    sht.range(1, 1).expand('right').color = [141, 180, 226]         # 设置列索引行的单元格背景颜色

    i = 3                                                           # 从第三行起隔行设置行单元格背景颜色
    while i <= max_row :
        sht.range(i, 1).expand('right').color = [184, 204, 228]
        i += 2

    k = 17                                                          # 每隔15条数据复制第一行的列索引
    while k <= sht.used_range.last_cell.row:
        sht.api.Rows(1).Copy(sht.api.Rows(k))
        k += 16

    wb.save()                                                       # 保存
    wb.close()                                                      # 关闭
    app.quit()                                                      # 退出
#===============================================================================================================

#=========================================== 保存表格截图,所见即所得 ============================================
def excel_save_img(path, sheet=0, img_suffix="png"):
    app = xw.App(visible=False, add_book=False)                         # 打开excel程序
    wb = app.books.open(path)                                           # 打开需要的工作簿
    sht = wb.sheets[sheet]                                              # 定位工作表
    max_row = sht.used_range.last_cell.row                              # 获取表格最大行数
    max_column = sht.used_range.last_cell.column                        # 获取表格最大列数
    name = str(sht.range('A2').value)                                   # 获取A2的值作为名称
    try:
        j = 16                                                          # 每15行数据截一张图(索引行不算在内)
        o = 1
        while j < max_row + 16 :
            all_range = sht.range((-15+j, 1),(j, max_column))
            all_range.api.CopyPicture()                                 # 复制图片区域
            sht.api.Paste()                                             # 粘贴图片在当前表格上
            pic = sht.pictures[0]                                       # 获取刚刚粘贴的图片
            pic.api.Copy()                                              # 复制图片
            img = ImageGrab.grabclipboard()                             # 获取剪贴板的图片数据
            img.save(str_today + name + str(o) + "." + img_suffix)      # 保存图片
            pic.delete()                                                # 删除sheet上的图片
            time.sleep(0.1)                                             # 添加100毫秒缓冲,防止剪贴板失效报错
            j += 16
            o += 1
    except:
        messagebox.showerror('', '出了点小差错,请再试一次')
        wb.close()                                                      # 不保存,直接关闭
        app.quit()                                                      # 退出
    else:
        wb.close()                                                      # 不保存,直接关闭
        app.quit()                                                      # 退出
        tk_root2()                                                      # 生成图片浏览窗口
#================================================================================================================

#============================================= tkinter图形界面主窗口 =============================================
def tk_root1():
    root = Tk()                                                          # 生成gui窗体
    root.title("数据筛选调用")                                            # 定义窗体标题
    name_label = Label(root, text="分行名称")                             # 文本标签
    name_label.grid(row=1, column=1,padx=10,pady=10)                      # 文本定位
    global name_entry                                                     # 声明day_entry变量为全局变量,方便调用
    global date_start_entry                                               # 声明date_start_entry变量为全局变量,方便调用
    global date_end_entry                                                 # 声明date_end_entry变量为全局变量,方便调用
    name_entry = Entry(root, width=20)                                    # 输入框(分行名称)
    name_entry.grid(row=1, column=2,columnspan=2,padx=10, pady=10)        # 输入框(分行名称)定位
    date_start_label = Label(root, text="开始时间")                        # 文本标签(开始时间)
    date_start_label.grid(row=2, column=1, padx=10,pady=10)               # 文本标签(开始时间)定位
    date_start_entry = Entry(root,width =20)                              # 输入框(开始时间)
    date_start_entry.grid(row=2,column=2,columnspan=2,padx=10,pady=10)    # 输入框(开始时间)定位
    date_end_label = Label(root, text="结束时间")                         # 文本标签(结束时间)
    date_end_label.grid(row=3, column=1, padx=10, pady=5)                 # 文本标签(结束时间)定位
    date_end_entry = Entry(root,width = 20)                               # 输入框(结束时间)
    date_end_entry.grid(row=3,column=2,columnspan=2,padx=10,pady=5)       # 输入框(结束时间)定位
    btn1 = Button(root, text="获取数据", command=print_form)              # 计算按钮,按下执行print_form()函数
    btn1.grid(row=4, column=2, padx=10,pady=15)                           # 计算按钮定位
    btn2 = Button(root, text="关闭程序", command=root.destroy)            # 关闭程序按钮,按下关闭该程序
    btn2.grid(row=4, column=3,padx=10,pady=15)                            # 关闭程序按钮定位

    root.mainloop()                                                       # tkinter主循环代码,不可删除
#================================================================================================================

#================================================ 图片浏览窗口 ===================================================
def tk_root2():
    pic_suffix = ('png')                                            # 定义图片后缀名为png
    pics = [p for p in os.listdir('.')\
            if p.endswith(pic_suffix) \
            and p.startswith(str_today + name_entry.get())]         # 获取当前文件夹下所有指定文件(后缀名为png且以本日日期和输入的分行名称开头)的文件名

    def changePic(flag):                                            # 定义图片浏览窗口调用图片的函数
        global current                                              # 声明current为全局变量
        new = current + flag                                        # 浏览首张图片时current值默认为-1,flag值默认为1

        if new < 0:                                                 # if-elif-else语句判定是否为第一或最后一张图片
            messagebox.showerror('', '这已经是第一张图片了')
        elif new >= len(pics):
            messagebox.showerror('', '这已经是最后一张图片了')
        else:
            pic_use = pics[new]                                     # new值默认为0,即pic_use默认为筛选文件后的第一张图
            pic_see = ImageTk.PhotoImage(Image.open(pic_use))       # 默认打开第一张图
            img_label['image']= pic_see                             # 此行代码未理解意义
            img_label.image = pic_see                               # 此行代码未理解意义
            text_label = Label(root2, text="第" + str(new+1) + "张",font=("微软雅黑", 20))
            text_label.grid(row=1, column=1)                        # 标签指明这是第几张图片,定位
            current = new                                           # 将current 重新赋值,实际意义为current=current+flag

    def btnPreClick():                                              # 定义上一张按钮函数
        changePic(-1)                                               # 给flag赋值-1,执行changePic函数
    def btnNextClick():                                             # 定义下一张按钮函数
        changePic(1)                                                # 给flag赋值1,执行changePic函数


    root2 =Toplevel()                                               # 生成图片浏览器gui窗体
    root2.title("图片浏览")                                          # 定义图片浏览器标题

    img_label = Label(root2, text= "666")                           # 生成label标签,用于放置调用的图片
    img_label.grid(row=0, column=0, columnspan=3)                   # 图片标签定位

    btnPre = Button(root2, text='上一张', command=btnPreClick)       # 生成上一张按钮,点击后获得上一张图片
    btnPre.grid(row=1, column=0)                                     # 上一张按钮定位

    btnNext = Button(root2, text='下一张', command=btnNextClick)     # 生成下一张按钮,点击后获得下一张图片
    btnNext.grid(row=1, column=2)                                    # 下一张按钮定位

    global current                                                   # 声明current为全局变量
    current = -1                                                     # 设置current默认值为-1
    changePic(1)                                                     # 执行changePic函数,flag值默认为1

    root2.mainloop()                                                 # 子窗口循环代码,不可删除
#================================================================================================================

#================================================ 获取数据函数 ===================================================
def print_form():
    get_data()                                                       # 获取excel数据,并导入新的工作表中
    global empty                                                     # 声明empty为全局变量
    if empty == 0:                                                   # 如果empty值为0,即输入框输入的值存在,继续执行函数
        form_style()                                                 # 更改表格样式
        excel_save_img(path)                                         # 保存表格截图
    elif empty == 1:                                                 # 如果empty值为1,即输入框输入的值不存在
        messagebox.showerror('', '查无此行,请重新输入')              # 不执行后续函数,弹消息框提醒
#================================================================================================================

#************************************************* 主程序执行 ****************************************************
today = datetime.date.today()                                        # 声明今天的时间
str_today = today.strftime('%Y-%m-%d')                               # 将获得的datetime时间格式按指定格式转换为字符串
path = "test.xlsx"                                                   # 指定生成的excel表名字
tk_root1()                                                           # tkinter主窗口程序生成
#*****************************************************************************************************************

成果

在这里插入图片描述

此处下两个输入框是给她预留调用sql里时间的变量,我的代码里暂时用不上
在这里插入图片描述
在文件夹内,图片也会按照当日时间,顺序以及输入的分行名称存储

总结

其他具体代码问题前前后后其实踩了不少坑,不过基本都在注释里写清楚了,剪贴板有时会被占用,也用了try-except语句去梳理好整个流程。

  • 0
    点赞
  • 2
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值