简体   繁体   English

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

[英]Close separately two windows in Python GTK (Glade)

I recently started developing some simple GUIs using Python GTK and Glade.我最近开始使用 Python GTK 和 Glade 开发一些简单的 GUI。 I've created a GUI which consists of a main window with a button while the action of pressing the button is the popup of a second window with a matplotlib plot on it.我创建了一个 GUI,它由一个带有按钮的主窗口组成,而按下按钮的动作是第二个窗口的弹出窗口,上面有一个 matplotlib 图。

The problem I face is that when i close the second window then the first one is also closed and i would like to be able and terminate them separately.我面临的问题是,当我关闭第二个窗口时,第一个窗口也关闭了,我希望能够分别终止它们。

Below is the python code and here is the glade file with GUI's layout.下面是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()

The imports are from vext.gi, numpy and matplotlib python packages, the Glade version I use is 3.22.1 and my OS is Elementary Linux 5.1 Hera.导入来自vext.gi、numpy 和 matplotlib python 包,我使用的 Glade 版本是 3.22.1,我的操作系统是 Elementary Linux 5.1 Hera。

You need to change the calls:您需要更改调用:

.connect("delete-event", Gtk.main_quit)

So that they only call Gtk.main_quit if this is the last open window.这样他们只在这是最后一个打开的窗口时才调用Gtk.main_quit

Replace that direct call to Gtk.main_quit with this:用这个替换对Gtk.main_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()

This makes it so that closing a window will only exit the application if it is the last visible window.这使得关闭窗口只会在它是最后一个可见窗口时退出应用程序。


If you only do:如果你只做:

window.hide()
return True

in your destroy-event handler, you will not have the application close ever.在您的销毁事件处理程序中,您将永远不会关闭应用程序。

Combining that which I didn't see as an issue as I couldn't run your program with the code I suggest would result in main_quit being called when all of the windows are closed.结合我没有看到的问题,因为我无法使用我建议的代码运行您的程序,这将导致在所有窗口关闭时调用main_quit

After some research ( Reopen window throws Gtk-CRITICAL **: gtk_widget_get_window: assertion 'GTK_IS_WIDGET (widget)' failed ) and some experimenting I concluded that the second-popup window, which is triggered by the button of my main window, should not be closed with the event function Gtk.main_quit(), but it should be hidden using the event function hide().经过一些研究( 重新打开窗口抛出 Gtk-CRITICAL **: gtk_widget_get_window: assertion 'GTK_IS_WIDGET (widget)' failed )和一些实验后我得出结论,由我的主窗口按钮触发的第二个弹出窗口不应该是使用事件函数 Gtk.main_quit() 关闭,但应该使用事件函数 hide() 隐藏它。 As a result the first-main window will remain open.因此,第一个主窗口将保持打开状态。

However, since the matplotlib plot is plotted on a FigureCanvas which is contained on the child widget (scrollbar window) of my second-popup window, then it is required the delete-event of popup-window to destroy the scrollbar window in order to be able to replot and avoid errors about existing child widgets.但是,由于 matplotlib 图绘制在 FigureCanvas 上,该图包含在我的第二个弹出窗口的子窗口小部件(滚动条窗口)上,因此需要弹出窗口的删除事件来销毁滚动条窗口,以便能够重新绘制并避免有关现有子小部件的错误。

So in the code of my original question the following modifications add the required functionality:因此,在我的原始问题的代码中,以下修改添加了所需的功能:

[1] Delete the scrollbar window widget from glade file [1]从glade文件中删除滚动条窗口小部件

[2] Add a scrollbar window on top of popup window: [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()

[3] Change the event function of popup window: [3] 改变弹窗的事件函数:

window2.connect("delete-event", self.destroy)

where the destroy function is defined as:其中 destroy 函数定义为:

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

Then no matter how many times I close the second window and press the button in main window, the plot is plotted on the (hidden) second window.然后无论我关闭第二个窗口多少次并按下主窗口中的按钮,绘图都会绘制在(隐藏的)第二个窗口上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM