在Python GTK(Glade)中分别关闭两个窗口

在Python GTK(Glade)中分别关闭两个窗口,python,gtk,glade,Python,Gtk,Glade,我最近开始使用PythonGTK和Glade开发一些简单的GUI。我已经创建了一个GUI,它由一个带有按钮的主窗口组成,而按下按钮的动作是弹出另一个带有matplotlib绘图的窗口 我面临的问题是,当我关闭第二个窗口时,第一个窗口也会关闭,我希望能够分别终止它们 下面是python代码和带有GUI布局的glade文件 import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk import numpy as

我最近开始使用PythonGTK和Glade开发一些简单的GUI。我已经创建了一个GUI,它由一个带有按钮的主窗口组成,而按下按钮的动作是弹出另一个带有matplotlib绘图的窗口

我面临的问题是,当我关闭第二个窗口时,第一个窗口也会关闭,我希望能够分别终止它们

下面是python代码和带有GUI布局的glade文件

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

import numpy as np
from matplotlib.figure import Figure
from matplotlib.axes import Subplot
from matplotlib.backends.backend_gtk3agg import (
    FigureCanvasGTK3Agg as FigureCanvas)

class PlotApp:

    def __init__(self):
        gladefile = 'GTK-two-windows.glade'

        self.builder = Gtk.Builder()
        self.builder.add_from_file(gladefile)

        main_win = self.builder.get_object("window1")
        main_win.connect("delete-event", Gtk.main_quit)

        button   = self.builder.get_object('button')
        button.connect('clicked', self.plot)

        main_win.show_all()

    def plot(self, widget):
        window2  = self.builder.get_object("window2")
        window2.connect("delete-event", Gtk.main_quit)

        scrolledwindow = self.builder.get_object("scrolledwindow")

        # ----- Start of Matplotlib specific code -----
        figure = Figure(figsize=(8, 6), dpi=71)
        axis = figure.add_subplot(111)
        t = np.arange(0.0, 3.0, 0.01)
        s = np.sin(2*np.pi*t)
        axis.plot(t, s)

        axis.set_xlabel('time [s]')
        axis.set_ylabel('voltage [V]')

        canvas = FigureCanvas(figure)     # a Gtk.DrawingArea
        canvas.set_size_request(800, 600)
        scrolledwindow.add_with_viewport(canvas)
        # ----- End of Matplotlib specific code -----

        window2.show_all()

if __name__ == "__main__":
    main = PlotApp()
    Gtk.main()

导入来自vext.gi、numpy和matplotlib python包,我使用的Glade版本是3.22.1,我的操作系统是初级Linux 5.1 Hera

您需要更改通话:

.connect("delete-event", Gtk.main_quit)
因此,如果这是最后一个打开的窗口,他们只能调用
Gtk.main\u quit

将对
Gtk.main\u quit
的直接调用替换为以下内容:

def exit(window, event):    
    if not any(w.get_visible() for w in Gtk.Window.list_toplevels() if w is not window):
        Gtk.main_quit()
这使得关闭窗口只会在最后一个可见窗口时退出应用程序


如果你只做:

window.hide()
return True
在销毁事件处理程序中,您将永远不会关闭应用程序

将我没有看到的问题(因为我无法运行您的程序)与我建议的代码结合起来,将导致在所有窗口关闭时调用
main\u quit

经过一些研究()和一些实验,我得出结论,第二个弹出窗口由我的主窗口按钮触发,不应使用事件函数Gtk.main_quit()关闭,但应使用事件函数hide()将其隐藏。因此,第一个主窗口将保持打开状态

但是,由于matplotlib绘图绘制在我的第二个弹出窗口的子窗口小部件(滚动条窗口)上包含的FigureCanvas上,因此需要弹出窗口的删除事件来销毁滚动条窗口,以便能够重新打印并避免现有子窗口小部件的错误

因此,在我原始问题的代码中,以下修改添加了所需的功能:

[1] 从glade文件中删除滚动条窗口小部件

[2] 在弹出窗口顶部添加滚动条窗口:

scrolledwindow = Gtk.ScrolledWindow()

    #----- Start of Matplotlib specific code -----
        figure = Figure(figsize=(8, 6), dpi=71)
        axis = figure.add_subplot(111)
        t = np.arange(0.0, 3.0, 0.01)
        s = np.sin(2*np.pi*t)
        axis.plot(t, s)

        axis.set_xlabel('time [s]')
        axis.set_ylabel('voltage [V]')

        canvas = FigureCanvas(figure)     # a Gtk.DrawingArea
        canvas.set_size_request(800, 600)
        scrolledwindow.add_with_viewport(canvas)
        #scrolledwindow.add(canvas)
    # ----- End of Matplotlib specific code -----

        window2.add(scrolledwindow)
        window2.show_all()
window2.connect("delete-event", self.destroy)
[3] 更改弹出窗口的事件功能:

scrolledwindow = Gtk.ScrolledWindow()

    #----- Start of Matplotlib specific code -----
        figure = Figure(figsize=(8, 6), dpi=71)
        axis = figure.add_subplot(111)
        t = np.arange(0.0, 3.0, 0.01)
        s = np.sin(2*np.pi*t)
        axis.plot(t, s)

        axis.set_xlabel('time [s]')
        axis.set_ylabel('voltage [V]')

        canvas = FigureCanvas(figure)     # a Gtk.DrawingArea
        canvas.set_size_request(800, 600)
        scrolledwindow.add_with_viewport(canvas)
        #scrolledwindow.add(canvas)
    # ----- End of Matplotlib specific code -----

        window2.add(scrolledwindow)
        window2.show_all()
window2.connect("delete-event", self.destroy)
其中销毁功能定义为:

def destroy(self, widget, event):
    scrolledwindow = widget.get_child()
    scrolledwindow.destroy()
    widget.hide()
    return True

然后,无论我关闭第二个窗口并按下主窗口中的按钮多少次,绘图都会绘制在(隐藏的)第二个窗口上。

感谢您的回复,这是一个合适的答案,但是,当我关闭第二个窗口并按下按钮重新打印并重新打开时,它会显示为空(没有绘图)以下警告:Gtk CRITICAL:Gtk_widget_get_window:assertion'Gtk_IS_widget(widget)Failed我使用了您提供的功能,但仍然得到相同的结果,即第二个窗口重新打开,但内容为空。这可能是合理的,因为据我所知,它仍然会破坏弹出窗口,而不是隐藏——正如本文()所述。我将在下面提供一个解决方案,根据前面的文章,这个解决方案似乎解决了这个问题。实际上,命令window.hide()将隐藏第二个窗口,而不是杀死它,但这正是我的目标,因为Gtk.main_quit()将关闭这两个窗口(主窗口,即第一个带有按钮的窗口,第二个窗口,即单击按钮后的弹出窗口)。经过进一步研究,我发现我要寻找的功能是隐藏第二个窗口,但破坏包含的滚动条窗口,以便能够回复。