2017-04-22 17 views
1

私は回路を表示して(そして最終的にはユーザービルドをさせる)GUIを作ろうとしています。以下は、アプリケーションがどのように見えるのかの概略を示しています。PyQt5 - コンポーネントを適切に動的にサイジングしてレイアウトする

Sketch of application

ボトムパネル(現在単純QToolBar)一定の高さであることが、アプリケーションとサイドパネル(下記のコードでIOPanel S)の幅に及ぶべきで一定の幅を有し、スパンべきアプリケーションの高さ

(現在オーバーライドpaintEvent方法とQWidgetであるが、最終的にQGraphicsView又はスクロール少なくとも何かをQGraphicsSceneなるかもしれないCanvas、)アプリケーションの主要部分は、残りのスペースを満たすべきです。

これは私の現在のコードです:

そのコードを実行
from PyQt5.QtWidgets import * 
from PyQt5.QtCore import Qt, QSize 


class MainWindow(QMainWindow): 
    def __init__(self, *args): 
     super().__init__(*args) 
     self._wire_ys = None 
     self._init_ui() 
     self.update_wire_ys() 

    def update_wire_ys(self): 
     self._wire_ys = [(i + 0.5) * self.panel.height()/4 for i in range(4)] 
     self.input.update_field_positions() 
     self.output.update_field_positions() 

    def wire_ys(self): 
     return self._wire_ys 

    def _init_ui(self): 
     self.panel = QWidget(self) 
     self.canvas = Canvas(self, self.panel) 
     self.input = IOPanel(self, self.panel) 
     self.output = IOPanel(self, self.panel) 

     hbox = QHBoxLayout(self.panel) 
     hbox.addWidget(self.canvas, 1, Qt.AlignCenter) 
     hbox.addWidget(self.input, 0, Qt.AlignLeft) 
     hbox.addWidget(self.output, 0, Qt.AlignRight) 

     self.setCentralWidget(self.panel) 
     self.addToolBar(Qt.BottomToolBarArea, self._create_run_panel()) 
     self.reset_placement() 

    def _create_run_panel(self): 
     # some other code to create the toolbar 
     return QToolBar(self) 

    def reset_placement(self): 
     g = QDesktopWidget().availableGeometry() 
     self.resize(0.4 * g.width(), 0.4 * g.height()) 
     self.move(g.center().x() - self.width()/2, g.center().y() - self.height()/2) 

    def resizeEvent(self, *args, **kwargs): 
     super().resizeEvent(*args, **kwargs) 
     self.update_wire_ys() 


class IOPanel(QWidget): 
    def __init__(self, main_window, *args): 
     super().__init__(*args) 
     self.main = main_window 
     self.io = [Field(self) for _ in range(4)] 

    def update_field_positions(self): 
     wire_ys = self.main.wire_ys() 
     for i in range(len(wire_ys)): 
      field = self.io[i] 
      field.move(self.width() - field.width() - 10, wire_ys[i] - field.height()/2) 

    def sizeHint(self): 
     return QSize(40, self.main.height()) 


class Field(QLabel): 
    def __init__(self, *args): 
     super().__init__(*args) 
     self.setAlignment(Qt.AlignCenter) 
     self.setText(str(0)) 
     self.resize(20, 20) 


# This class is actually defined in another module and imported 
class Canvas(QWidget): 
    def __init__(self, main_window, *args): 
     super().__init__(*args) 
     self.main = main_window 

    def paintEvent(self, e): 
     print("ASFD") 
     qp = QPainter() 
     qp.begin(self) 
     self._draw(qp) 
     qp.end() 

    def _draw(self, qp): 
     # Draw stuff 
     qp.drawLine(0, 0, 1, 1) 


# __main__.py 
def main(): 
    import sys 
    app = QApplication(sys.argv) 
    w = MainWindow() 
    w.show() 
    sys.exit(app.exec_()) 


if __name__ == '__main__': 
    main() 

は私に次のようになります:

Result

ここで私はより自分の中でこのようなコードを使用してそれらを参照するコンポーネントを色付けしています構成:

p = self.palette() 
p.setColor(self.backgroundRole(), Qt.blue) 
self.setPalette(p) 
self.setAutoFillBackground(True) 

グリーン中央のパネル(MainWindow.panel)、青色はIOPanels、Fieldsは赤色、Canvasは白色とみなされます。

下のツールバーを無視して、これは私が上に含まれていない余分なコードです(可能な限り最小限にしておきます)。QWidget以外は何もサイズ変更もレイアウト管理もしません。実際、上記の最小限の例のペイントコードを含めても、Runボタンを使用しないで、シンナーボトムツールバーと同様の結果が得られました。私は、一般的なレイアウトで(ツールバーが正しく動作しているので)期待される動作を示すためにここにツールバーを含めています。

この結果にはいくつかの問題があります。

問題1

Field sが最初に、表示されません。 しかし、は、メインウィンドウのサイズを変更すると表示されます(それぞれのパネル内に適切に配置されます)。どうしてこれなの?メインウィンドウのresizeEventが行うのはupdate_wire_ysupdate_field_positionsだけで、メインウィンドウの__init__でも同様です。

問題2つの

IOPanel sは適切に整列されていません。最初のパネルは、中央パネルの左側にある必要があります。それらの添加順序を変更するように、これを修正します。

hbox.addWidget(self.input, 0, Qt.AlignLeft) 
hbox.addWidget(self.canvas, 1, Qt.AlignCenter) 
hbox.addWidget(self.output, 0, Qt.AlignRight) 

しかし、Qt.AlignXはすでにかかわらず、それらが追加されている順序の、これを行うべきではないのですか?後で別のパネルを左側に追加する場合は、すべてのコンポーネントを削除し、新しいパネルを追加してから再追加する必要がありますか?3つの

IOPanel sが適切なサイズではありません

問題。それらは、中央パネルの全高さに及んで、中央パネルの左/右端に接触する必要があります。これがレイアウトやパネルの色付けに問題があるかどうかはわかりません。私は間違って何をしていますか?

問題4

Canvasは(コンソールに出力されることは決してありません「ASFD」)まったく表示されませんし、実際にそのpaintEventが呼び出されることはありません。私はsizeHintをオーバーライドしていません。セントラルパネルのレイアウトにCanvasのサイズを適切に合わせたいからです。私は、コンポーネントを追加すると伸び率が1になることを期待していました。

hbox.addWidget(self.canvas, 1, Qt.AlignCenter) 

キャンバスを実際に表示して中央パネルの残りのスペースをすべて埋めるにはどうすればよいですか?

答えて

1

これは典型的なスパゲッティコードです。多くの要素が絡まっていますが、テストするのが難しく、sizeEventなどの多くの問題が発見されています。オブジェクトupdate_field_positionsupdate_wire_ysは、お互いのオブジェクトを処理します。この回答で

私はシンプルな実装を提案します:

  • IOPanel CLASは、画像サイズの変更を処理QVBoxLayoutが含まれている必要があります。

  • MainWindowクラスでは、レイアウトで整列を使用しますが、順番に整列を追加する必要があります。

    from PyQt5.QtWidgets import * 
    from PyQt5.QtGui import * 
    from PyQt5.QtCore import * 
    
    class Field(QLabel): 
        def __init__(self, text="0", parent=None): 
         super(Field, self).__init__(parent=parent) 
         self.setAlignment(Qt.AlignCenter) 
         self.setText(text) 
    
    
    class IOPanel(QWidget): 
        numbers_of_fields = 4 
        def __init__(self, parent=None): 
         super(IOPanel, self).__init__(parent=None) 
         lay = QVBoxLayout(self) 
         for _ in range(self.numbers_of_fields): 
          w = Field() 
          lay.addWidget(w) 
    
         self.setMinimumSize(QSize(40, 0)) 
         sizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred) 
         self.setSizePolicy(sizePolicy) 
    
    
    
    class Panel(QWidget): 
        def __init__(self, parent=None): 
         super(Panel, self).__init__(parent=None) 
         lay = QHBoxLayout(self) 
         self.input = IOPanel() 
         self.output = IOPanel() 
         self.canvas = QWidget() 
    
         lay.addWidget(self.input, 0, Qt.AlignLeft) 
         lay.addWidget(self.canvas, 0, Qt.AlignCenter) 
         lay.addWidget(self.output, 0, Qt.AlignRight) 
    
    
    class MainWindow(QMainWindow): 
        def __init__(self, parent=None): 
         super(MainWindow, self).__init__(parent=parent) 
         self.initUi() 
         self.reset_placement() 
    
        def initUi(self): 
         panel = Panel(self) 
         self.setCentralWidget(panel) 
         self.addToolBar(Qt.BottomToolBarArea, QToolBar(self)) 
    
        def reset_placement(self): 
         g = QDesktopWidget().availableGeometry() 
         self.resize(0.4 * g.width(), 0.4 * g.height()) 
         self.move(g.center().x() - self.width()/2, g.center().y() - self.height()/2) 
    
    
    def main(): 
        import sys 
        app = QApplication(sys.argv) 
        w = MainWindow() 
        w.show() 
        sys.exit(app.exec_()) 
    
    
    if __name__ == '__main__': 
        main() 
    

    スクリーンショット:

    enter image description here

    lay.addWidget(self.input, 0, Qt.AlignLeft) 
    lay.addWidget(self.canvas, 0, Qt.AlignCenter) 
    lay.addWidget(self.output, 0, Qt.AlignRight) 
    
  • は、私たちがQSizePolicy()使用IOPanelsetMinimumSize()

完全なコードのための最小の幅を配置するには

+0

私は自分のコードを適切に再構築できました。今は動作しています(さらに多くのものを追加してもうまくいけばうまくいくでしょう)。 –

関連する問題