web-dev-qa-db-ja.com

PyQtでウィジェットを動的に追加および削除する

pyQtを使用して、ウィジェットを動的に追加または削除できるインターフェースを作成しようとしています。追加または削除されるウィジェット用に別のクラスを定義したい。インスタンス化したウィジェットをメインインターフェース内に表示することができないようです。これが私が使用しているコードです:

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_()

問題は、以下のコードを 'addWidget'メソッド内で使用すると、まさにそれが実行したいことを実行しますが、クラスメソッドが機能していないようです。

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

なぜz = Test()が結果を出さないのでしょうか?何か案は?ありがとう!

13
boundless

実際には、機能します。問題は、あなたのTestウィジェットにQPushButtonがあり、レイアウト管理がないことです。したがって、ボタンを考慮に入れてminimumSizeを計算することはできません。そのウィジェットをレイアウトに配置すると、ウィジェットは0に縮小されます(QWidgetにはデフォルトminimumSizeがないため)。何も表示されません。

2つの選択肢があります。手動でレイアウトを管理し、不必要な苦痛の世界に入るか、またはレイアウトマネージャーに依存します。一般に、後者を優先する必要があります。

スクリプトを次のように書き直します(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_()
16
Avaris

クリックするとボタンが自動的に削除されるようにする小さな変更を次に示します。

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_()

これにより、削除時にメモリリークが発生することはなく、ボタンは実際に使用できます。私は、ダウンロードとチャンクの監視について、進行状況バーのこのパターンを数十ずつ追跡し、スレッド化とマルチ処理でも問題なく動作します。簡単なQThreadsではありません...

4
ClearType3000

ボタンを押すたびに、またはプログラムのイベント中にウィジェットを削除したい場合は、deleteLater()メソッドを使用します:self.yourwidget.deleteLater()

self.button.clicked.connect(delete_widget);

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

self.widget.deleteLater();

上記の関数を使用すると、ウィジェットがアプリケーションから消えます

2
Natesh bhat