首页 > 解决方案 > 由于 tkinter GUI 中的 tkraise() 导致位置混乱

问题描述

我正在尝试使用 .csv 文件中的给定值绘制图表。正如预期的那样,情节似乎没有引起任何问题。问题是画布实际上扰乱了前一帧的位置。

请注意,我正在使用具有 tkraise 功能的两个框架,其中另一个框架 ID 使用按钮调用,从现在开始显示框架。这发生得很顺利,但位置有点受到干扰。有什么办法可以保留帧中数据在第一帧中按要求居中的位置?

我想强调这个特殊的 DataStored 类,其中图表的情节正在发生。

这是我的代码:

import tkinter as tk
from tkinter import messagebox

import serial
from serial.tools import list_ports

from os import path
import continuous_threading
import csv
from datetime import datetime

from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)

FONT = ("Helvetica", 20)
attributes = {'padx': 20, 'pady': 20}
th = None

class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.title('DAS')
        self.geometry('600x450')

        container = tk.Frame(self)
        container.pack(fill=tk.BOTH, expand=True)
        self.frames = {}
        self.frames[0] = Display(container, self)
        self.frames[0].grid(row=0, column=0, sticky='nsew')
        self.frames[1] = DataStored(container, self)
        self.frames[1].grid(row=0, column=0, sticky='nsew')

        self.show_frame(0)

    def show_frame(self, frame):
        frame = self.frames[frame]
        frame.tkraise()

class Display(tk.Frame):
    def __init__(self, container, controller):
        super().__init__(container)

        name = tk.Label(self, text='Data Acquistion System', font=FONT)
        name.pack(fill='x')
        left_wrapper = tk.Frame(self)
        left_wrapper.pack(side='left', **attributes)
        right_wrapper = tk.Frame(self)
        right_wrapper.pack(side='left', **attributes)

        port_label = tk.Label(left_wrapper, text='Port:', font=FONT)
        port_label.grid(row=0, column=0)

        port_option = tk.StringVar(left_wrapper, value='None')
        ports_availiable = self.get_arduino_ports()
        port_value = tk.OptionMenu(left_wrapper, port_option, *ports_availiable)
        port_value.grid(row=0, column=1)

        baud_label = tk.Label(left_wrapper, text='Baudrate:', font=FONT)
        baud_label.grid(row=1, column=0)
        baud_value = tk.Entry(left_wrapper)
        baud_value.grid(row=1, column=1)
        baud_value.insert(0, 9600)

        connect_button = tk.Button(left_wrapper, text='Connect', command=lambda: self.connect_to_port(port_option.get(), baud_value.get()))
        connect_button.grid(row=2, column=1)
        playback_button = tk.Button(left_wrapper, text='Playback', command=lambda: controller.show_frame(1))
        playback_button.grid(row=3, column=1)

        size = {'height': 4, 'width': 15}
        temperature_label = tk.Label(right_wrapper, text='Temperature(in °C):', font=FONT)
        self.temperature_val = tk.Text(right_wrapper, **size)
        self.temperature_val.configure(state='disabled')
        temperature_label.grid(row=0, column=0)
        self.temperature_val.grid(row=0, column=1)

    def get_arduino_ports(self):
        """
        Returns port in which Arduino is connected. If multiple ports are found it returns first one.
        """
        arduino_ports = [
        # grep returns same list of ports as comports. It also filter out devices using regex.
        p.device for p in list_ports.grep(r'Arduino')
        ]
        if not arduino_ports:
            return ['None']
        return arduino_ports

    def connect_to_port(self, port, baudrate=9600):
        """
        Function to establish connection with port.
        """
        global BOARD
        global DATA_FILE
        if not port:
            return None
        try:
            BOARD = serial.Serial(port, baudrate)
            BOARD.flush()
        except serial.SerialException:
            print("Not able to connect to the board.")
            messagebox.showwarning("Serial Error", "Not able to connect to board")
            return
        DATA_FILE = open("data.csv", "a")
        DATA_FILE.write("time, temperature\n")
        global th
        th = continuous_threading.PeriodicThread(0.5, target=self.read_data)
        th.start()

    def read_data(self):
        """
        Read data from the connected board.
        """
        if serial.in_waiting > 0:
            time_now = datetime.now().strftime("%H:%M:%S")
            received = BOARD.read().decode('utf-8')
            DATA_FILE.write(','.join((time_now, received))+'\n')
            self.temperature_val.delete(0, tk.END)
            self.temperature_val.insert(0, received) 

class DataStored(tk.Frame):
    def __init__(self, container, controller):
        super().__init__(container)
        tk.Label(self, text='Playback Data', font=FONT).pack(fill=tk.X)
        top_frame = tk.Frame(self)
        top_frame.pack(fill=tk.X)
        bottom_frame = tk.Frame(self)
        bottom_frame.pack(fill=tk.X)

        update = tk.Button(bottom_frame, text='Update', command=lambda: self.update_playback(top_frame))
        update.pack()
        back = tk.Button(bottom_frame, text='Back', command=lambda: controller.show_frame(0))
        back.pack()

    def update_playback(self, container):
        time = []
        temperature = []
        
        if not path.exists("data.csv"):
            messagebox.showwarning("Warning", "No data found to plot.")
            return

        with open("data.csv", "r") as file:
            reader = csv.reader(file)
            next(reader)
            for row in reader:
                time_now, temperature_now = row[0], row[1]
                time.append(time_now)
                temperature.append(temperature_now)
        for widget in container.winfo_children():
            widget.destroy()
        fig = Figure(figsize=(3, 3), dpi=100)
        plot1 = fig.add_subplot(111)
        plot1.plot(time, temperature, 'b-o')
        canvas = FigureCanvasTkAgg(fig, master=container)
        canvas.draw()
        canvas.get_tk_widget().pack()
        toolbar = NavigationToolbar2Tk(canvas, container)
        toolbar.update()
        canvas.get_tk_widget().pack()


BOARD = None
DATA_FILE = None
        
if __name__ == "__main__":
    window = App()
    window.mainloop()

标签: pythontkinter

解决方案


推荐阅读