在PyQt5上添加/删除QSlider小部件

时间:2022-11-22 23:02:41

I want to dynamically change the number of sliders on my application window, in dependence of the number of checked items in a QStandardItemModel structure.

我想动态地更改应用程序窗口上的滑块数量,这依赖于qstandardtemmodel结构中检查的项的数量。

My application window has an instance of QVBoxLayout called sliders, which I update when a button is pressed:

我的应用程序窗口有一个名为sliders的QVBoxLayout实例,我在按下按钮时更新它:

first removing all sliders eventually in there:

首先把所有滑块都移走:

self.sliders.removeWidget(slider)

And then creating a new set.

然后创建一个新的集合。

The relevant code:

相关代码:

def create_sliders(self):
    if len(self.sliders_list):
        for sl in self.sliders_list:
            self.sliders.removeWidget(sl)
    self.sliders_list = []
    for index in range(self.model.rowCount()):
        if self.model.item(index).checkState():
            slid = QSlider(Qt.Horizontal)
            self.sliders.addWidget(slid)
            self.sliders_list.append(slid)

The principle seems to work, however what happens is weird as the deleted sliders do not really disappear but it is as they were 'disconnected' from the underlying layout.

这一原则似乎行得通,但是奇怪的是,删除的滑块并没有真正消失,而是因为它们与底层布局“断开”了。

When created, the sliders keep their position among other elements while I resize the main window. However, once they've been removed, they occupy a fixed position and can for instance disappear if I reduce the size of the window. Unfortunately I'm having difficulties in linking images (it says the format is not supported when I try to link from pasteboard), so I hope this description is enough to highlight the issue.

创建时,当我调整主窗口的大小时,滑块在其他元素中保持它们的位置。但是,一旦它们被移除,它们就会占据一个固定的位置,例如,如果我减小窗口的大小,它们就会消失。不幸的是,我在链接图像时遇到了困难(它说当我尝试从pasteboard链接时不支持这种格式),所以我希望本文的描述足以突出这个问题。

Do I have to remove the sliders using a different procedure?

我是否必须使用不同的程序来移除滑块?

EDIT

编辑

Thanks to @eyllansec for his reply, it condenses a bunch of other replies around the topic, which I wasn't able to find as I did not know the method deleteLater() which is the key to get rid of widgets inside a QLayout.

感谢@eyllansec的回复,它浓缩了关于这个主题的许多其他回复,我无法找到,因为我不知道deleteLater()方法,它是在QLayout中删除小部件的关键。

I am marking it as my chosen (hey, it's the only one and it works, after all!), however I want to propose my own code which also works with minimal changes w.r.t. to what I proposed in the beginning.

我将它标记为我的选择(嘿,它是唯一的而且它毕竟是有效的!)

The key point here is that I was using the metod QLayout.removeWidget(QWidget) which I was wrongly thinking, it would..er..Remove the widget! But actually what it does is (if I understood it right) remove it from the layout instance.

这里的关键是我使用了metod QLayout.removeWidget(QWidget),我错误地认为它会。删除小部件!但是实际上它所做的是(如果我理解正确的话)从布局实例中删除它。

That is why it was still hanging in my window, although it seemed disconnected

这就是为什么它仍然挂在我的窗户上,尽管它似乎是断开的

Manual reference

手册参考

Also, the proposed code is far more general than what I need, as it is a recursion over layout contents, which could in principle be both other QLayout objects or QWidgets (or even Qspacer), and be organized in a hierarchy (i.e., a QWidget QLayout within a QLayout and so on).

此外,所提议的代码远比我需要的更一般,因为它是对布局内容的递归,原则上可以是其他QLayout对象或QWidgets(甚至Qspacer),并且可以在层次结构中组织。, QWidget QLayout在QLayout中,等等)。

check this other answer

检查其他的答案

From there, the use of recursion and the series of if-then constructs.

从这里开始,使用递归和一系列if-then结构。

My case is much simpler though, as I use this QVLayout instance to just place my QSliders and this will be all. So, for me, I stick to my list for now as I do not like the formalism of QLayout.TakeAt(n) and I don't need it. I was glad that the references I build in a list are absolutely fine to work with.

我的情况要简单得多,因为我使用这个QVLayout实例来放置我的QSliders,这就足够了。所以,对我来说,我现在坚持我的清单,因为我不喜欢QLayout.TakeAt(n)的形式主义,我不需要它。我很高兴我在列表中建立的参考是绝对可以使用的。

In the end, this is the slightly changed code that works for me in this case:

最后,这是稍微修改过的代码,在这种情况下对我有效:

def create_sliders(self):
    if len(self.sliders_list):
        for sl in self.sliders_list:
            sl.deleteLater()
    self.sliders_list = []
    for index in range(self.model.rowCount()):
        if self.model.item(index).checkState():
            slid = QSlider(Qt.Horizontal)
            self.sliders.addWidget(slid)
            self.sliders_list.append(slid)

1 个解决方案

#1


1  

It is not necessary to save the sliders in a list, they can be accessed through the layout where it is contained. I have implemented a function that deletes the elements within a layout. The solution is as follows:

不需要将滑块保存在列表中,可以通过包含滑块的布局来访问它们。我实现了一个删除布局中的元素的函数。解决办法如下:

def create_sliders(self):
    self.clearLayout(self.sliders)

    for index in range(self.model.rowCount()):
        if self.model.item(index).checkState():
            slid = QSlider(Qt.Horizontal)
            self.sliders.addWidget(slid)

def clearLayout(self, layout):
    if layout:
        while layout.count():
            item = layout.takeAt(0)
            widget = item.widget()
            if widget:
                widget.deleteLater()
            else :
                self.clearLayout(item.layout())
            layout.removeItem(item)

#1


1  

It is not necessary to save the sliders in a list, they can be accessed through the layout where it is contained. I have implemented a function that deletes the elements within a layout. The solution is as follows:

不需要将滑块保存在列表中,可以通过包含滑块的布局来访问它们。我实现了一个删除布局中的元素的函数。解决办法如下:

def create_sliders(self):
    self.clearLayout(self.sliders)

    for index in range(self.model.rowCount()):
        if self.model.item(index).checkState():
            slid = QSlider(Qt.Horizontal)
            self.sliders.addWidget(slid)

def clearLayout(self, layout):
    if layout:
        while layout.count():
            item = layout.takeAt(0)
            widget = item.widget()
            if widget:
                widget.deleteLater()
            else :
                self.clearLayout(item.layout())
            layout.removeItem(item)