【问题标题】:How to remove empty space(void) in the tab widget after removing a PlotWidget?删除 PlotWidget 后如何删除选项卡小部件中的空白空间(void)?
【发布时间】:2020-03-12 15:38:51
【问题描述】:

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

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

在下面的简化代码中,我有类 dashboard_tab,通过单击按钮我创建了一个 add_new_graphobject,它创建了一个新的图形小部件 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_())

仪表板应用截图

【问题讨论】:

  • 您可以尝试在add_new_graph.kill_widget 末尾添加self.deleteLater()
  • 谢谢!这就是我最终使用下面建议的解决方案所做的事情,并且它有效!感谢您的宝贵时间。

标签: python python-3.x object pyqt5 signals-slots


【解决方案1】:

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

即使在删除这些对象之后,容器的最小尺寸仍由其布局的contents margins 给出(取决于操作系统和当前样式,它们通常在 5 到 10 像素之间),这就是您可以使用的“空白”见。

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


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

无论如何,当这样的小部件要被删除时,您可能更愿意收到警告,所以我建议让父母有责任这样做:


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: self.deleteRequested.emit(self))

如果可以的话,一个建议:对类使用大写名称(以便它们可以很容易地与函数区分开来),并且不要在它们的名称中使用“动作描述”:类通常不会通过以下方式“做”事情他们自己,他们的方法。

【讨论】:

  • 顺便说一句...我必须在 deleteLater() 函数中删除“self”才能使其工作 self.killWidgetBtn.clicked.connect(lambda: self.deleteLater()) ....和感谢您提供关于提高可读性的提示!
  • 对不起,我在第二个例子中犯了一个错误:lambda 参数应该调用self.deleteRequested.emit(self),否则它就没有意义:-)。我现在已经更正了。不客气,顺便说一句:-)
  • 感谢指正!顺便说一句,你为什么决定在这种情况下使用 lambda 函数?
猜你喜欢
  • 2021-08-09
  • 1970-01-01
  • 2021-01-17
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多