如何避免制作两个tkinter窗口?

时间:2020-10-06 09:47:19

标签: python matplotlib tkinter

我制作了一个GUI,其中在用户值上绘制了一条线,当您单击该线时,将打开另一个窗口,您可以在其中选择某些内容。当您按确定时,它应该在终端上打印。我认为是因为单击该行时正在创建一个新的tkinter窗口,所以无法检索用户选择。如何解决此问题?非常感谢您的帮助。

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib import style
import tkinter as tk    
from tkinter import ttk
from tkinter import *
import random
import numpy as np

    
LARGE_FONT = ('Verdana',12)
style.use('ggplot')

from matplotlib import pyplot as plt    


class PageOne(tk.Tk):
    
    def __init__(self):
        tk.Tk.__init__(self)
        label = tk.Label(self,text='Experiment', font = LARGE_FONT)
        label.pack(pady=10,padx=10)

        
        self.adding_widgets()

        button2= ttk.Button(self,text='Validate', command=self.draw)
        button2.pack()

        button3= ttk.Button(self,text='Erase', command=self.dlet)
        button3.pack()


        self.lines_pts=[] 
        
        self.f1= Figure(figsize=(5,5),dpi=100)
        self.b=self.f1.add_subplot(1,1,1)
        self.b.set_xlim([0,10])
        self.b.set_ylim([0,10])  
        self.canvas = FigureCanvasTkAgg(self.f1, self)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(side=tk.TOP,fill=tk.BOTH,expand=True)
        self.f1.canvas.mpl_connect('pick_event', self.on_pick)

        
        self.lines =[]
        


    def adding_widgets(self,*args):
        labfram=ttk.LabelFrame(self,width=100,height=100,text='Enter Member Coordinates',labelanchor=N)
        labfram.pack()
        

        l1=ttk.Label(labfram,text='x0')
        l1.pack(side='left')
        self.x0=Entry(labfram,width=10,)
        self.x0.pack(side='left')


        l2=ttk.Label(labfram,text='y0')
        l2.pack(side='left')
        self.y0=Entry(labfram,width=10)
        self.y0.pack(side='left')


        l3=ttk.Label(labfram,text='x1')
        l3.pack(side='left')
        self.x1=Entry(labfram,width=10)
        self.x1.pack(side='left')


        l4=ttk.Label(labfram,text='y1')
        l4.pack(side='left')
        self.y1=Entry(labfram,width=10)
        self.y1.pack(side='left')
        
            
    def draw(self):
        
        p0 = float(self.x0.get()), float(self.y0.get())
        p1 = float(self.x1.get()), float(self.y1.get())
        self.lines_pts.append((p0,p1))

        for p0,p1 in self.lines_pts:
            x0, y0, x1, y1 = *p0, *p1
            X = x0,x1
            Y = y0,y1
        
        ax = self.b.plot(X,Y, 'r', linewidth=4,picker=5 )
        
        self.lines.append(ax) 
        self.canvas.draw() 

    
    def dlet(self):
        self.b.lines.remove(self.b.lines[-1])
        self.canvas.draw()

    
    def on_pick(self,event):
        w=Tk()
        w.title('Channel Select')
        w.geometry('250x50')

        n = StringVar() 
        ch = ttk.Combobox(w, width = 15 , textvariable = n)
        ch['values'] = ('CH1','CH2','CH3','CH4','CH5','CH6','CH7','CH8','CH9','CH10')
        ch.grid(column=1,row=0)
        ch_label = ttk.Label(w,text='Select Your Channel')
        ch_label.grid(column=0,row=0)
        ch_button = ttk.Button(w,text='OK',command=lambda: print ('value is:'+ n.get()))
        ch_button.grid(column=1,row=1)



        for line in self.lines:
            line = event.artist
        xdata, ydata = line.get_data()
        ind = event.ind
        print('on pick line:', np.array([xdata[ind], ydata[ind]]).T)



app = PageOne()
app.mainloop()

1 个答案:

答案 0 :(得分:1)

您真的要在这里创建一个新窗口吗?

def on_pick(self,event):
    w=Tk()
    w.title('Channel Select')
    w.geometry('250x50')

请注意,当您执行w=Tk()操作时,正在创建对象的实例 NEW OBJECT (即Tk()),因此这就是创建新窗口的原因。您的目标是真的要在每次单击时弹出一个窗口吗,如果没有,我想您可以删除它。

---- UPDATE ---

所以窗口不断弹出的原因是,在函数上您创建了带有该对象的实例。然后,我尝试将w=Tk()放到函数之外,但仍然会创建或显示该对象,因为它位于mainloop内。

另一种解决方案是,您可以检查该窗口是否存在或其状态是否为正常,然后只需执行focus

这是我仅在您的on_pick函数上添加的代码。我还为您的__init__方法添加了self.w = None,最初只是将w变量设置为None。

总体来说,这只是所做的更改

def on_pick(self,event):

        try:
            if self.w.state() == "normal":
                self.w.focus()

        except BaseException as on_pick_error:
            self.w=Toplevel()
            self.w.title('Channel Select')
            self.w.geometry('250x50')

            n = StringVar() 
            ch = ttk.Combobox(self.w, width = 15 , textvariable = n)
            ch['values'] = ('CH1','CH2','CH3','CH4','CH5','CH6','CH7','CH8','CH9','CH10')
            ch.grid(column=1,row=0)
            ch_label = ttk.Label(self.w,text='Select Your Channel')
            ch_label.grid(column=0,row=0)
            ch_button = ttk.Button(self.w,text='OK',command=lambda: print ('value is:'+ n.get()))
            ch_button.grid(column=1,row=1)



            for line in self.lines:
                line = event.artist
            xdata, ydata = line.get_data()
            ind = event.ind
            print('on pick line:', np.array([xdata[ind], ydata[ind]]).T)

您可能想知道这样做是什么,它只是检查您弹出的窗口的self.w的状态是否正确,它只是检查其状态是否等于“正常” strong>表示它处于活动状态,那么当它处于活动状态时,只需执行.focus()并专注于该当前窗口即可。否则,它将创建一个新窗口,其为self.w=Toplevel(),依此类推。

try:
    if self.w.state() == "normal":
        self.w.focus()

except BaseException as on_pick_error:
    self.w=Toplevel()
    self.w.title('Channel Select')
    self.w.geometry('250x50')

为什么它是顶级而不是Tk?

我建议将其设置为Toplevel,但是要由您决定,因为Toplevel和Tk可能具有相同的属性,但是请注意它们并不相同,因此取决于您。