0

次の例が機能しないのはなぜですか?

from PyQt4 import QtGui
import sys

class TestView(QtGui.QWidget):

    def __init__(self):
        super(TestView, self).__init__()
        self.initUI()

    def initUI(self):
        self.btn = QtGui.QPushButton('Button', self)
        self.btn.resize(self.btn.sizeHint())
        self.btn.move(50, 50)

class TestViewController():

    def __init__(self, view):
        view.btn.clicked.connect(self.buttonClicked)
        view.show()

    def buttonClicked(self):
        print 'clicked'

def main():
    app = QtGui.QApplication(sys.argv)
    view = TestView()
    TestViewController(view)
    app.exec_()

if __name__ == '__main__':
    main()

この例は、コントローラー( )がビュー()への参照を受け取り、ビューのボタンからのクリックされた信号をその関数に接続するMVC構造(図4のような-モデルなし)を表すことになっています。TestViewControllerTestViewview.btnself.buttonClicked

確かにその行view.btn.clicked.connect(self.buttonClicked)は実行されていますが、どうやら効果はありません。誰かがそれを解決する方法を知っていますか?


更新(ひどい解決策):

この例では、行を置き換えると

view.btn.clicked.connect(self.buttonClicked)

view.clicked = self.clicked
view.btn.clicked.connect(view.clicked)

できます。私はまだそれに満足していません。

4

1 に答える 1

2

それが機能しない理由は、コントローラークラスが何かをクリックする前にガベージコレクションされているためです。

view.clicked = self.clickedを設定すると、実際に実行しているのは、コントローラーのオブジェクトの1つをビューオブジェクトに保持して、クリーンアップされないようにすることです。これは実際には解決策ではありません。

コントローラを変数に保存すると、コントローラが収集から保護されます。

したがって、上記のコードを次のように変更すると、次のようになります。

ctrl = TestViewController(view)

これですべての設定が完了します。

そうは言っても、ここで何をしようとしているのか、よくわかりません... Qt用にMVCシステムをセットアップしようとしているようですが、Qtには、QtDesignerを使用して分離するためのかなり優れたシステムがすでにあります。コントローラーロジック(QWidgetサブクラス)からUI(ビュー/テンプレート)ファイルへのインターフェイスコンポーネント。繰り返しになりますが、私はあなたが何をしようとしているのかわかりません。これはそれのばかげたバージョンかもしれませんが、私はそれを次のようにすべて1つのクラスにすることをお勧めします:

from PyQt4 import QtGui
import sys

class TestView(QtGui.QWidget):

    def __init__(self):
        super(TestView, self).__init__()
        self.initUI()

    def initUI(self):
        self.btn = QtGui.QPushButton('Button', self)
        self.btn.resize(self.btn.sizeHint())
        self.btn.move(50, 50)
        self.btn.clicked.connect(self.buttonClicked)

    def buttonClicked(self):
        print 'clicked'

def main():
    app = QtGui.QApplication(sys.argv)
    view = TestView()
    view.show()
    app.exec_()

if __name__ == '__main__':
    main()

編集:QtのMVCを明確にする

したがって、この上記の例では、実際にUIを動的にロードして、コントローラー/ビューの分離を作成することはありません。ここに表示するのは少し難しいです。Qt /Designerベースの例/チュートリアルを実行するのが最適です-ここに1つありますhttp://bitesofcode.blogspot.com/2011/10/introduction-to-designer.htmlが、多くはオンラインで見つけることができます。

簡単に言うと、loadUiメソッドをPyQt4.uic動的ロードに置き換えることができます(これを設定するにはさまざまな方法があります)。これにより、コードは最終的に次のようになります。

from PyQt4 import QtGui
import PyQt4.uic
import sys

class TestController(QtGui.QWidget):

    def __init__(self):
        super(TestController, self).__init__()

        # load view
        uifile = '/path/to/some/widget.ui'
        PyQt4.uic.loadUi(uifile, self)

        # create connections (assuming there is a widget called 'btn' that is loaded)
        self.btn.clicked.connect(self.buttonClicked)

    def buttonClicked(self):
        print 'clicked'

def main():
    app = QtGui.QApplication(sys.argv)
    view = TestController()
    view.show()
    app.exec_()

if __name__ == '__main__':
    main()

編集2:UI参照の保存

この概念を視覚化する方が簡単な場合は、生成されたUIオブジェクトへの参照を保存することもできます。

from PyQt4 import QtGui
import PyQt4.uic
import sys

class TestController(QtGui.QWidget):

    def __init__(self):
        super(TestController, self).__init__()

        # load a view from an external template
        uifile = '/path/to/some/widget.ui'
        self.ui = PyQt4.uic.loadUi(uifile, self)

        # create connections (assuming there is a widget called 'btn' that is loaded)
        self.ui.btn.clicked.connect(self.buttonClicked)

    def buttonClicked(self):
        print 'clicked'

def main():
    app = QtGui.QApplication(sys.argv)
    view = TestController()
    view.show()
    app.exec_()

if __name__ == '__main__':
    main()
于 2012-09-04T20:15:10.553 に答える