【问题标题】:How do I transform a class/window from a "normal" window to a Toplevel() window in Tkinter?如何在 Tkinter 中将类/窗口从“普通”窗口转换为 Toplevel() 窗口?
【发布时间】:2020-07-31 05:30:19
【问题描述】:

我是 Tkinter 编程的新手,我正在尝试将窗口/类“GraphPage_cpu”设置为该结构中的 Toplevel() 窗口。我该如何去做,以便按下“StartPage”上的“CPU Usage”按钮并打开一个包含图形页面的新窗口?

另外,我必须对用户“j_4321”给予极大的赞扬。在弄清楚如何绘制 CPU 度量方面,他真的帮了我很多!

import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import Toplevel
from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showinfo, showwarning, askquestion
from tkinter import OptionMenu
from tkinter import StringVar

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
from matplotlib import style
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.dates as mdates
from psutil import cpu_percent
from psutil import virtual_memory
from datetime import datetime, timedelta

from sklearn.metrics import silhouette_score
from sklearn.cluster import KMeans
import sklearn.cluster as cluster
import scipy.spatial.distance as sdist
from sklearn.ensemble import IsolationForest

import pandas as pd
import numpy as np
import seaborn as sn

from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import StandardScaler

RANDOM_STATE = 42 #used to help randomly select the data points
low_memory=False
LARGE_FONT= ("Verdana", 12)
style.use("ggplot")

f = Figure(figsize=(5,5), dpi=100)
a = f.add_subplot(111)


class Analyticsapp(tk.Tk):

    def __init__(self, *args, **kwargs):
        
        tk.Tk.__init__(self, *args, **kwargs)
        
        #tk.Tk.iconbitmap(self, default="iconimage_kmeans.ico") #Icon for program
        tk.Tk.wm_title(self, "Advanched analytics")
        
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)
        
        self.frames = {} 
        
        for F in (StartPage, GraphPage_cpu):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()
        
class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text=
                         "Advanched analytics", font=LARGE_FONT)
        label.pack(pady=10, padx=10)
        
        button3 = ttk.Button(self, text="CPU Usage", 
                            command=lambda: controller.show_frame(GraphPage_cpu))
        button3.pack(fill='x')

class GraphPage_cpu(tk.Frame):

    def __init__(self, parent, controller, nb_points=360):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="CPU Usage", font=LARGE_FONT)
        label.pack(pady=10, padx=10, side='top')

        # matplotlib figure
        self.figure = Figure(figsize=(5, 5), dpi=100)
        self.ax = self.figure.add_subplot(111)
        # format the x-axis to show the time
        myFmt = mdates.DateFormatter("%H:%M:%S")
        self.ax.xaxis.set_major_formatter(myFmt)
        # initial x and y data
        dateTimeObj = datetime.now() + timedelta(seconds=-nb_points)
        self.x_data = [dateTimeObj + timedelta(seconds=i) for i in range(nb_points)]
        self.y_data = [0 for i in range(nb_points)]
        # create the plot
        self.plot = self.ax.plot(self.x_data, self.y_data, label='CPU')[0]
        self.ax.set_ylim(0, 100)
        self.ax.set_xlim(self.x_data[0], self.x_data[-1])

        self.canvas = FigureCanvasTkAgg(self.figure, self)

        toolbar = NavigationToolbar2Tk(self.canvas, self)
        toolbar.update()

        button1 = ttk.Button(self, text="Back",
                             command=lambda: controller.show_frame(StartPage))
        button1.pack(side='bottom')
        
        self.canvas.get_tk_widget().pack(side='top', fill=tk.BOTH, expand=True)
        self.animate_cpu()

    def animate_cpu(self):
        # append new data point to the x and y data
        self.x_data.append(datetime.now())
        self.y_data.append(cpu_percent())
        # remove oldest data point
        self.x_data = self.x_data[1:]
        self.y_data = self.y_data[1:]
        #  update plot data
        self.plot.set_xdata(self.x_data)
        self.plot.set_ydata(self.y_data)
        self.ax.set_xlim(self.x_data[0], self.x_data[-1])
        self.canvas.draw_idle()  # redraw plot
        self.after(1000, self.animate_cpu)  # repeat after 1s
        
app = Analyticsapp()
app.geometry('500x400')
app.mainloop()

【问题讨论】:

  • “他真的帮了我……”:谢谢你的信任,但你知道,我是个女人。我认为在有疑问时使用中性代词是一种很好的做法,或者避免使用代词:例如“……j_4321,谁真的帮了我……”。
  • 对不起。我认为这更多是因为英语不是我的第一语言。 -但我以后会注意这一点。感谢您的回复。
  • 别担心,我没有看错,但我认为最好让你知道,因为有时它会伤害人们的感情。

标签: python function class tkinter


【解决方案1】:

您可以让GraphPage_cpu 继承自Toplevel 而不是Frame

class GraphPage_cpu(tk.Toplevel):

    def __init__(self, parent, controller, nb_points=360):
        tk.Toplevel.__init__(self, parent)
        ...

然后,您需要更改button1 命令,因为图形不再隐藏起始页,也许在单击按钮时使用self.withdraw 隐藏图形。在这种情况下,您不再需要 __init__ 中的 controller 参数。

现在,您需要修改Analyticsapp.__init__GraphPage_cpu 现在是 Toplevel,而不是 Frame,因此您必须从创建所有页面的 for 循环中删除它。您可以单独创建它,例如:

 self.graph_cpu = GraphPage_cpu(self, nb_points=360)
 self.graph_cpu.withdraw()  # hide the toplevel

并添加一个类方法来显示顶层:

def show_graph_cpu(self):
    self.graph_cpu.deiconify()

最后你需要修改Start Page中的button3来显示图表:

button3 = ttk.Button(self, text="CPU Usage", 
                     command=controller.show_graph_cpu)

这里是完整的代码:

import tkinter as tk
from tkinter import ttk

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
from matplotlib import style
import matplotlib.dates as mdates
from psutil import cpu_percent
from datetime import datetime, timedelta


RANDOM_STATE = 42 #used to help randomly select the data points
low_memory = False
LARGE_FONT = ("Verdana", 12)
style.use("ggplot")


class Analyticsapp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        #tk.Tk.iconbitmap(self, default="iconimage_kmeans.ico") #Icon for program
        tk.Tk.wm_title(self, "Advanched analytics")

        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        for F in (StartPage,):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.graph_cpu = GraphPage_cpu(self, nb_points=360)
        self.graph_cpu.withdraw()  # hide window

        self.show_frame(StartPage)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()

    def show_graph(self):
        self.graph_cpu.deiconify()

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Advanched analytics", font=LARGE_FONT)
        label.pack(pady=10, padx=10)

        button3 = ttk.Button(self, text="CPU Usage",
                             command=controller.show_graph)
        button3.pack(fill='x')

class GraphPage_cpu(tk.Toplevel):

    def __init__(self, parent, nb_points=360):
        tk.Toplevel.__init__(self, parent)
        self.protocol('WM_DELETE_WINDOW', self.withdraw)  # make the close button in the titlebar withdraw the toplevel instead of destroying it
        label = tk.Label(self, text="CPU Usage", font=LARGE_FONT)
        label.pack(pady=10, padx=10, side='top')

        # matplotlib figure
        self.figure = Figure(figsize=(5, 5), dpi=100)
        self.ax = self.figure.add_subplot(111)
        # format the x-axis to show the time
        myFmt = mdates.DateFormatter("%H:%M:%S")
        self.ax.xaxis.set_major_formatter(myFmt)
        # initial x and y data
        dateTimeObj = datetime.now() + timedelta(seconds=-nb_points)
        self.x_data = [dateTimeObj + timedelta(seconds=i) for i in range(nb_points)]
        self.y_data = [0 for i in range(nb_points)]
        # create the plot
        self.plot = self.ax.plot(self.x_data, self.y_data, label='CPU')[0]
        self.ax.set_ylim(0, 100)
        self.ax.set_xlim(self.x_data[0], self.x_data[-1])

        self.canvas = FigureCanvasTkAgg(self.figure, self)

        toolbar = NavigationToolbar2Tk(self.canvas, self)
        toolbar.update()

        button1 = ttk.Button(self, text="Hide", command=self.withdraw)
        button1.pack(side='bottom')

        self.canvas.get_tk_widget().pack(side='top', fill=tk.BOTH, expand=True)
        self.animate_cpu()

    def animate_cpu(self):
        # append new data point to the x and y data
        self.x_data.append(datetime.now())
        self.y_data.append(cpu_percent())
        # remove oldest data point
        self.x_data = self.x_data[1:]
        self.y_data = self.y_data[1:]
        #  update plot data
        self.plot.set_xdata(self.x_data)
        self.plot.set_ydata(self.y_data)
        self.ax.set_xlim(self.x_data[0], self.x_data[-1])
        self.canvas.draw_idle()  # redraw plot
        self.after(1000, self.animate_cpu)  # repeat after 1s

app = Analyticsapp()
app.geometry('500x400')
app.mainloop()

另外,在GraphPage_cpu.__init__,我已经添加了

self.protocol('WM_DELETE_WINDOW', self.withdraw)

这使得标题栏中的关闭按钮撤回顶层而不是破坏它。

【讨论】:

  • 非常感谢!这节省了一天。 WM_DELETE_WINDOW 是锦上添花!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-01
  • 2018-12-18
  • 2013-10-21
  • 2019-06-12
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
相关资源
最近更新 更多