删除 PlotWidget 后如何删除选项卡小部件中的空 space(void)?

How to remove empty space(void) in the tab widget after removing a PlotWidget?

我有一个小型仪表板应用程序,我可以在其中动态添加和删除图表。问题是,当我单击 x 按钮(杀死图形小部件)时,图形从视图中消失,但在剩余图形上方留下一个空隙(参见随附的屏幕截图)。

我在这方面几乎是一个完全的初学者,但我怀疑我没有正确处理小部件和对象的删除?

在我下面的简化代码中,我有 class dashboard_tab,通过单击按钮我创建了一个 add_new_graph 对象,该对象创建了一个新的图形小部件 self.graphWidget = pg.PlotWidget()

当启动图形小部件关闭(或终止)时,我调用以下代码:

def kill_widget(self):
        self.lay.removeWidget(self.graphWidget)
        self.graphWidget.deleteLater()
        self.graphWidget = None

这似乎以某种方式起作用,因为图形小部件从视图中消失了,但不需要的空隙却没有。

然后我的想法是也杀死 add_new_graph 对象...如果它与我的问题有任何关系...通过创建从 add_new_graph 对象返回到dashboard_tab 对象...但它无法正常工作。

所以我的问题是:

如有任何正确方向的建议,我们将不胜感激!

class MainWindow(QtWidgets.QWidget):
    def __init__(self, parent):
        super(QtWidgets.QWidget, self).__init__(parent)
        self.layout = QtWidgets.QVBoxLayout(self)

        self.tab_holder = QtWidgets.QTabWidget()
        tab1 = dashboard_tab()

        self.tab_holder.addTab(tab1, "Dashboard")
        self.layout.addWidget(self.tab_holder)


class dashboard_tab(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.lay = QtWidgets.QVBoxLayout(self)

        self.numGraphs = 0

        addGraphBtn = QtWidgets.QToolButton()
        addGraphBtn.setText("  Add Graph")

        addGraphBtnMenu = QtWidgets.QMenu()
        addGraphBtnMenu.addAction('Add Temp Graph', self.add_graph)
        addGraphBtn.setMenu(addGraphBtnMenu)

        self.lay.addWidget(addGraphBtn)

    def add_graph(self):
        # Create a unique graph name
        self.name = ("graph" + str(self.numGraphs))

        self.graph = add_new_graph(self.name)
        self.lay.addWidget(self.graph)

        # Up graph name index every time a new graph is created
        self.numGraphs += 1


class add_new_graph(QtWidgets.QWidget):

    def __init__(self, name):
        super().__init__()
        self.name = name

        self.lay = QtWidgets.QHBoxLayout(self)

        self.graphWidget = pg.PlotWidget()
        self.killWidgetBtn = QtWidgets.QPushButton('')
        self.killWidgetBtn.clicked.connect(self.kill_widget)

        self.lay.addWidget(self.killWidgetBtn)
        self.lay.addWidget(self.graphWidget)

    def kill_widget(self):
        self.lay.removeWidget(self.killWidgetBtn)
        self.killWidgetBtn.deleteLater()
        self.killWidgetBtn = None

        self.lay.removeWidget(self.graphWidget)
        self.graphWidget.deleteLater()
        self.graphWidget = None


if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

仪表板应用程序屏幕截图

发生的情况是您只删除了子窗口小部件(图表和按钮),而不是您添加到布局中的容器窗口小部件。

即使在删除这些对象之后,容器的布局也有一个最小尺寸 contents margins(取决于操作系统和当前样式,它们通常在 5 到 10 像素之间),这就是 "void"你可以看到。

您可以删除容器而不是删除子窗口小部件。


class add_new_graph(QtWidgets.QWidget):
    def __init__(self, name):
        # ...
        self.killWidgetBtn.clicked.connect(<b>self.deleteLater</b>)

无论如何,您可能希望在删除此类小部件时收到警告,因此我建议让家长有责任这样做:


class dashboard_tab(QtWidgets.QWidget):
    # ...
    def add_graph(self):
        # ...
        graph = add_new_graph(self.name)
        graph.deleteRequested.connect(self.deleteGraph)

    def deleteGraph(self, graph):
        # some warning message box, maybe?
        if QtWidgets.QMessageBox.warning(self, 'Close?', 
            'Delete the graph?', 
            QtWidgets.QMessageBox.Ok|QtWidgets.QMessageBox.Cancel
            ) != QtWidgets.QMessageBox.Ok:
                return
        graph.deleteLater()

class add_new_graph(QtWidgets.QWidget):
    deleteRequested = QtCore.pyqtSignal(object)

    def __init__(self, name):
        # ...
        self.killWidgetBtn.clicked.connect(
            lambda: <b>self.deleteRequested.emit(self)</b>)

一个建议,如果可以的话:对 类 使用大写名称(这样它们可以很容易地与函数区分开来),并且不要使用 "action descriptions" 作为它们的名称:类 通常不会 "do" 事情本身,他们的方法会。