• Python绘图系统16:动态更新tkinter组件


    Python绘图系统:

    前情提要

    AxisFrame是存放某一维坐标的组件,目前由一个标签,一个下拉选框和一个输入框构成。下拉选框主要目的是判断输入方式,目前有4个选择,分别是源代码、序列化、外部导入和无数据。

    其中源代码就是通过调用eval执行的代码,这个没什么好说的。但序列化目前的实现方式,用的仍旧是类似Pyton的语法,然后在外面套一层壳,这还是得程序员才能懂。而外部导入目前只起到一个说明的作用,即外部数据导入了,然后这个地方一变,换言之,AxisFrame自身并没有导入数据的功能。

    所以,这两个功能还是需要优化的,当ComboBox的选中项发生变化时,需要调整一下布局,故而initWidgets函数改成下面的形式,其中initRes则根据传入的数据获取模式来初始化其他控件。

    def initWidgets(self, widths):
        tk.Label(self, text=self.label, width=widths[0]).pack(side=tk.LEFT)
        slct = ttk.Combobox(self, width=widths[1], 
            textvariable=self.mode)
        slct['value'] = self.MODES
        slct.bind('<>', self.slctChanged)
        slct.pack(side=tk.LEFT)
        self.initRes(widths[3])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    源代码模式

    源码模式最简单,只要有一个Entry就可以,从外观上来看,不需要做任何修改,但代码需要写到另一个函数中。

    代码如下,其逻辑顺序是,先实现一个srcEntry,然后调用showSrcEntry将其展示出来。

    def initRes(self, width):
        self.errWidth = width
        mode = self.mode.get()
        self.srcEntry = tk.Entry(self, width=width, textvariable=self.srcText)
        if mode=="源代码":
            self.showSrcEntry()
        
    def showSrcEntry(self):
        self.srcEntry.pack(padx=5, pady=2, side=tk.LEFT, fill=tk.X)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    其中self.srcText是一个StringVar,是在initVar中定义的

    self.srcText = tk.StringVar()
    
    • 1

    然后把readPython函数改为

    def readPython(self, t=None, x=None, y=None, z=None):
        self.data = eval(self.srcText.get())
        return self.data
    
    • 1
    • 2
    • 3

    输入序列

    序列化的含义是生成一个等差数列,要有起点,有终点,还得有步长。所以最直接的创建方法,就是三个Label和三个Entry,而且这些部件需要放进一个Frame中。结合已有的源代码输入控件,initRes函数改为下列形式。

    def initRes(self, width):
        self.errWidth = width
        self.srcEntry = tk.Entry(self, width=width, textvariable=self.srcText)
        
        self.arrFrame = ttk.Frame(self, width=width-5)
        for i, key in enumerate(["起点", "终点", "步长"]):
            tk.Label(self.arrFrame, text=key).grid(row=0, column=i*3)
            tk.Entry(self.arrFrame, width=int(width/6), 
                textvariable=self.arrText[i]).grid(row=0, column=i*3+1)                
    
        self.showRes(self.mode.get())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中self.arrText是一个StringVar列表,定义在initVar中

    self.arrText = [tk.StringVar() for _ in range(3)]
    
    • 1

    self.showRes则是显示某组部件的方法

    def showRes(self, mode):
        resDct = {"源代码":self.srcEntry, "序列化":self.arrFrame}
        resDct[mode].pack(padx=5, pady=2, side=tk.LEFT, fill=tk.X)
    
    • 1
    • 2
    • 3

    最后效果如下

    在这里插入图片描述

    另一方面,需要更改getArray函数

    def getArray(self):
        vs = [float(t.get()) for t in self.arrText]
        self.data = np.arange(*vs)
        return self.data
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    绘图结果如下

    在这里插入图片描述

    源码

    本文仅改动了aframe.py中的源代码,其他代码在这篇博客后面:定制风格的绘图系统

    aframe.py改动之后的代码如下

    import tkinter as tk
    import tkinter.ttk as ttk
    
    import numpy as np
    
    class AxisFrame(ttk.Frame):
        # widths 是每个控件的宽度
        def __init__(self, master, label, mode, widths, **options):
            super().__init__(master, **options)
            self.pack()
            self.label = label
            self.initVar(mode)
            self.initWidgets(widths)
        
        def initVar(self, mode):
            self.MODES = ("序列化", "源代码", "外部导入", "无数据")
            self.mode = tk.StringVar()
            self.srcText = tk.StringVar()
            self.arrText = [tk.StringVar() for _ in range(3)]
            self.setMode(mode)
        
        def initWidgets(self, widths):
            tk.Label(self, text=self.label, width=widths[0]).pack(side=tk.LEFT)
            slct = ttk.Combobox(self, width=widths[1], 
                textvariable=self.mode)
            slct['value'] = self.MODES
            slct.bind('<>', self.slctChanged)
            slct.pack(side=tk.LEFT)
            self.initRes(widths[2])
    
        def initRes(self, width):
            self.errWidth = width
            self.srcEntry = tk.Entry(self, width=width, textvariable=self.srcText)
            
            self.arrFrame = ttk.Frame(self, width=width-5)
            for i, key in enumerate(["起点", "终点", "步长"]):
                tk.Label(self.arrFrame, text=key).grid(row=0, column=i*3)
                tk.Entry(self.arrFrame, width=int(width/6), 
                    textvariable=self.arrText[i]).grid(row=0, column=i*3+1)                
    
            self.showRes(self.mode.get())
            
        def showRes(self, mode):
            resDct = {"源代码":self.srcEntry, "序列化":self.arrFrame}
            resDct[mode].pack(padx=5, pady=2, side=tk.LEFT, fill=tk.X)
            
        def showSrcEntry(self):
            self.srcEntry.pack(padx=5, pady=2, side=tk.LEFT, fill=tk.X)
        
        def showArrFrame(self):
            self.arrFrame.pack(padx=5, pady=2, side=tk.LEFT, fill=tk.X)
    
    
        def slctChanged(self, evt):
            self.srcEntry.pack_forget()
            self.arrFrame.pack_forget()
            mode = self.mode.get()
            self.showRes(self.mode.get())
    
        def setText(self, text):
            self.entry.delete(0, "end")
            self.entry.insert(0, text)
    
        def get(self):
            return self.entry.get()
    
        def setMode(self, mode):
            if type(mode) != str:
                mode = self.MODES[mode]
            self.mode.set(mode)
    
        def setData(self, data=None, **txyz):
            if self.mode.get() == "序列化":
                return self.getArray()
            elif self.mode.get() == "外部导入":
                return self.loadData(data)
            else:
                return self.readPython(**txyz)
        
        def readPython(self, t=None, x=None, y=None, z=None):
            self.data = eval(self.srcText.get())
            return self.data
        
        def loadData(self, data):
            if type(data) != type(None):
                self.data = data
            return self.data
    
        def getArray(self):
            vs = [float(t.get()) for t in self.arrText]
            self.data = np.arange(*vs)
            return self.data
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
  • 相关阅读:
    【iOS】nil、Nil、NULL、NSNull的区别
    好用的跨平台同步笔记工具,手机和电脑可同步的笔记工具
    价格监测难点2——全覆盖监测
    网络层详解
    JavaScript的BOM操作
    算法提升:图的启发式搜索算法(A算法、A*算法)
    K8S集群etcd 某个节点数据不一致如何修复 —— 筑梦之路
    java计算机毕业设计二手车商城源码+mysql数据库+系统+lw文档+部署
    信泰如意享七金版养老年金保险怎么样,好不好?
    迅为3A5000_7A2000开发板龙芯全国产处理器LoongArch架构核心方案
  • 原文地址:https://blog.csdn.net/m0_37816922/article/details/132154143