简体   繁体   English

在PyQt中动态添加和删除小部件

[英]dynamically adding and removing widgets in PyQt

using PyQt, I am trying to create an interface for which I can add or remove widget dynamically. 使用PyQt,我试图创建一个接口,我可以动态添加或删除小部件。 I want to define a separate class for the widget that will be added or removed. 我想为要添加或删除的窗口小部件定义一个单独的类。 I can't seem to be able to get the widget that I instantiate to display inside the main interface. 我似乎无法获得我实例化在主界面内显示的小部件。 Here is the code I am using: 这是我正在使用的代码:

from PyQt4 import QtGui, QtCore
import sys

class Main(QtGui.QMainWindow):
    def __init__(self, parent = None):
        super(Main, self).__init__(parent)

        # central widget
        self.centralWidget = QtGui.QWidget(self)

        # main layout
        self.vLayout = QtGui.QVBoxLayout(self.centralWidget)

        # main button
        self.pButton_add = QtGui.QPushButton(self.centralWidget)
        self.pButton_add.setText('button to add other widgets')

        # scroll area
        self.scrollArea = QtGui.QScrollArea(self.centralWidget)
        self.scrollArea.setWidgetResizable(True)

        # scroll area widget contents
        self.scrollAreaWidgetContents = QtGui.QWidget(self.scrollArea)

        # scroll area widget contents - layout
        self.formLayout = QtGui.QFormLayout(self.scrollAreaWidgetContents)

        self.scrollArea.setWidget(self.scrollAreaWidgetContents)

        # add all main to the main vLayout
        self.vLayout.addWidget(self.pButton_add)
        self.vLayout.addWidget(self.scrollArea)
        # set central widget
        self.setCentralWidget(self.centralWidget)
        # connections
        self.pButton_add.clicked.connect(self.addWidget)


    def addWidget(self):
        z = Test(self.scrollAreaWidgetContents)
        count = self.formLayout.rowCount()
        self.formLayout.setWidget(count, QtGui.QFormLayout.LabelRole, z)


class Test(QtGui.QWidget):
  def __init__( self, parent):
      super(Test, self).__init__(parent)

      self.pushButton = QtGui.QPushButton(self)


app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()

the thing is, when I use the below code inside my 'addWidget' method, it exactly does what I want it to do, but the the class method doesn't seem to work. 问题是,当我在'addWidget'方法中使用下面的代码时,它完全按照我想要的方式执行,但是类方法似乎不起作用。

z = QtGui.QPushButton(self.scrollAreaWidgetContents)
count = self.formLayout.rowCount())
self.formLayout.setWidget(count, QtGui.QFormLayout.LabelRole, z)

I wonder why the z = Test() is not yielding any results? 我想知道为什么z = Test()没有产生任何结果? Any ideas? 有任何想法吗? Thanks! 谢谢!

Actually, it does work. 实际上,它确实有效。 Problem is, your Test widget has a QPushButton without any layout management. 问题是,您的Test小部件有一个没有任何布局管理的QPushButton So it can't calculate its minimumSize with taking the button into consideration. 因此,考虑到按钮,它无法计算其minimumSize When you put that widget in a layout, it just shrinks to 0 (since a QWidget has no default minimumSize ) and you don't see anything. 当你将这个小部件放在一个布局中时,它只会收缩到0 (因为QWidget没有默认的minimumSize ),你什么都看不到。

You have two choices, either you manually manage layout and enter a needless world of pain, or you rely on layout managers. 您有两种选择,要么手动管理布局,要么输入不必要的痛苦世界,要么依赖布局管理器。 In general, you should prefer the latter. 一般来说,你应该更喜欢后者。

I would re-write your script like this (Although I'm not sure why you use QFormLayout , I leave it as it is.): 我会像这样重写你的脚本(虽然我不确定你为什么使用QFormLayout ,但我保持原样。):

from PyQt4 import QtGui, QtCore
import sys

class Main(QtGui.QMainWindow):
    def __init__(self, parent = None):
        super(Main, self).__init__(parent)

        # main button
        self.addButton = QtGui.QPushButton('button to add other widgets')
        self.addButton.clicked.connect(self.addWidget)

        # scroll area widget contents - layout
        self.scrollLayout = QtGui.QFormLayout()

        # scroll area widget contents
        self.scrollWidget = QtGui.QWidget()
        self.scrollWidget.setLayout(self.scrollLayout)

        # scroll area
        self.scrollArea = QtGui.QScrollArea()
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setWidget(self.scrollWidget)

        # main layout
        self.mainLayout = QtGui.QVBoxLayout()

        # add all main to the main vLayout
        self.mainLayout.addWidget(self.addButton)
        self.mainLayout.addWidget(self.scrollArea)

        # central widget
        self.centralWidget = QtGui.QWidget()
        self.centralWidget.setLayout(self.mainLayout)

        # set central widget
        self.setCentralWidget(self.centralWidget)

    def addWidget(self):
        self.scrollLayout.addRow(Test())


class Test(QtGui.QWidget):
  def __init__( self, parent=None):
      super(Test, self).__init__(parent)

      self.pushButton = QtGui.QPushButton('I am in Test widget')

      layout = QtGui.QHBoxLayout()
      layout.addWidget(self.pushButton)
      self.setLayout(layout)



app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()

Here is a little change that will make the button delete itself once clicked: 这是一个小改动,一旦点击按钮就会自动删除:

from PyQt4 import QtGui, QtCore
import sys

class Main(QtGui.QMainWindow):
    def __init__(self, parent = None):
        super(Main, self).__init__(parent)

        # main button
        self.addButton = QtGui.QPushButton('button to add other widgets')
        self.addButton.clicked.connect(self.addWidget)

        # scroll area widget contents - layout
        self.scrollLayout = QtGui.QFormLayout()

        # scroll area widget contents
        self.scrollWidget = QtGui.QWidget()
        self.scrollWidget.setLayout(self.scrollLayout)

        # scroll area
        self.scrollArea = QtGui.QScrollArea()
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setWidget(self.scrollWidget)

        # main layout
        self.mainLayout = QtGui.QVBoxLayout()

        # add all main to the main vLayout
        self.mainLayout.addWidget(self.addButton)
        self.mainLayout.addWidget(self.scrollArea)

        # central widget
        self.centralWidget = QtGui.QWidget()
        self.centralWidget.setLayout(self.mainLayout)

        # set central widget
        self.setCentralWidget(self.centralWidget)

    def addWidget(self):
        self.scrollLayout.addRow(TestButton()) 


class TestButton(QtGui.QPushButton):
  def __init__( self, parent=None):
      super(TestButton, self).__init__(parent)
      self.setText("I am in Test widget")
      self.clicked.connect(self.deleteLater)


app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()

This way it shouldn't mem leak when deleted and the button can actually be used for stuff. 这样它就不应该在删除时发生泄漏,并且按钮实际上可以用于填充内容。 I follow this pattern for progress bars by the dozens for downloads and chunks monitoring and it works just fine even with threading and multi processing. 我按照这种模式进行数十次进度条的下载和块监控,即使使用线程和多处理也能正常工作。 And not the easy QThreads... 而不是简单的QThreads ......

If u want to say , delete a widget whenever a button is clicked , or during any event of ur program , use the deleteLater() method : self.yourwidget.deleteLater() 如果你想说,只要点击一个按钮就删除一个小部件,或者在任何你的程序事件中,使用deleteLater()方法: self.yourwidget.deleteLater()

self.button.clicked.connect(delete_widget);

def delete_widget(self):
     self.widget.deleteLater();

self.widget.deleteLater(); self.widget.deleteLater();

Using the above function makes that widget dissappear from the Application 使用上述功能使该小部件从应用程序中消失

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

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