我正在嘗試使GUI顯示(並最終讓用戶構建)電路。下面是應用程序應該是什麼樣子的粗略草圖。PyQt5 - 正確地動態調整大小和佈局組件
底部面板(現爲簡單QToolBar
)應該是恆定的高度,但跨越應用和側板(IOPanel
S IN的下面的代碼)的寬度應具有恆定的寬度和跨越應用程序的高度。
應用(Canvas
,這也是目前QWidget
與重寫paintEvent
方法,但可能最終成爲一個QGraphicsView
,或者至少一些滾動一個QGraphicsScene
),則應該填充剩餘空間的主要部分。
這是我當前的代碼:
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()
運行的代碼給我下面的:
在這裏,我有彩色的組件,以更好地看到他們使用這樣的代碼在自己建設:
p = self.palette()
p.setColor(self.backgroundRole(), Qt.blue)
self.setPalette(p)
self.setAutoFillBackground(True)
綠色是中央面板(MainWindow.panel
),藍色是IOPanel
s,Field
s應該是紅色的,而Canvas
應該是白色的。
忽略底部的工具欄,它是我上面沒有包括的一些額外代碼(儘可能保持最小和相關),但它沒有調整任何尺寸,也沒有佈局管理,除了它自己的子代碼QWidget
。事實上,包括我上面最小例子中的繪畫代碼給出了與沒有運行按鈕的較薄的底部工具欄類似的結果。我只是在這裏包括工具欄,以顯示其在總體佈局中的預期行爲(因爲工具欄工作正常)。
這個結果有幾個問題。
問題1
的Field
■不要露面,最初。 但是,一旦我調整了主窗口的大小,它們確實出現(並且適當地放置在它們各自的面板內)。爲什麼是這樣?主窗口resizeEvent
所做的唯一的事情是update_wire_ys
和update_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
完全不露面,事實上它paintEvent
不會被調用(「ASFD」永遠不會被打印到控制檯)。我並未覆蓋其sizeHint
,因爲我希望中央面板的佈局能夠自行適當調整Canvas
的大小。我希望添加組件時的伸展係數爲1可以實現這一點。
hbox.addWidget(self.canvas, 1, Qt.AlignCenter)
如何讓畫布實際顯示並填充中央面板上的所有剩餘空間?
我已經設法正確地重構我的代碼,它現在可以工作(並且希望在添加更多內容時繼續工作)。 –