[英]Draw a correct grid with PyQt5
我在 PyQt5 上有點掙扎:我必須實現 Conway's Game of Life,我從 GUI 常規設置開始。 我想過堆疊(垂直)兩個小部件,一個用於顯示游戲板,另一個包含按鈕和滑塊。
這就是我想出的(我是個菜鳥)
我想相對於邊緣正確地擬合網格。 看起來它在專用畫布下方構建了網格:首先修復畫布然后在其上繪畫會很棒,但是布局、小部件和所有這些都讓我大吃一驚。
這是我的(寫得很快,寫得不好)代碼
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QLabel, QSlider, QPushButton, QWidget
from PyQt5.QtCore import Qt, QRect
from PyQt5.QtGui import QPixmap, QColor, QPainter
WINDOW_WIDTH, WINDOW_HEIGHT = 800, 600
SQUARE_SIDE = 20
ROWS, COLS = int(WINDOW_HEIGHT/SQUARE_SIDE), int(WINDOW_WIDTH/2*SQUARE_SIDE)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
layout = QVBoxLayout()
buttons_layout = QHBoxLayout()
self.label = QLabel()
self.label.setContentsMargins(0,0,0,0)
self.label.setStyleSheet('background-color: white; ')
self.label.setAlignment(Qt.AlignCenter)
slider = QSlider(Qt.Horizontal)
start_button = QPushButton('Start')
pause_button = QPushButton('Pause')
reset_button = QPushButton('Reset')
load_button = QPushButton('Load')
save_button = QPushButton('Save')
layout.addWidget(self.label)
buttons_layout.addWidget(start_button)
buttons_layout.addWidget(pause_button)
buttons_layout.addWidget(reset_button)
buttons_layout.addWidget(load_button)
buttons_layout.addWidget(save_button)
buttons_layout.addWidget(slider)
layout.addLayout(buttons_layout)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.make_grid()
def make_grid(self):
_canvas = QPixmap(WINDOW_WIDTH, WINDOW_HEIGHT)
_canvas.fill(QColor("#ffffff"))
self.label.setPixmap(_canvas)
painter = QPainter(self.label.pixmap())
for c in range(COLS):
painter.drawLine(SQUARE_SIDE*c, WINDOW_HEIGHT, SQUARE_SIDE*c, 0)
for r in range(ROWS):
painter.drawLine(0, SQUARE_SIDE*r, WINDOW_WIDTH, SQUARE_SIDE*r)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT)
window.setWindowTitle("Conway's Game of Life")
window.show()
app.exec_()
感謝您的幫助,祝您有美好的一天!
像素圖未以完整尺寸顯示的原因是因為您對窗口和像素圖都使用了WINDOW_WIDTH
和WINDOW_HEIGHT
。 由於窗口還包含工具欄和它自己的邊距,因此您強制它比它應該的小,因此“剪掉”了板。
更簡單的解決方案是設置標簽的scaledContents
屬性:
self.label.setScaledContents(True)
但結果會有點難看,因為標簽的尺寸會比您繪制的像素圖略小,使其變得模糊。
另一種(更好)的可能性是在窗口顯示后設置固定大小,以便 Qt 處理所有對象所需的大小:
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
# window.setFixedSize(WINDOW_WIDTH, WINDOW_HEIGHT)
window.setWindowTitle("Conway's Game of Life")
window.show()
window.setFixedSize(window.size())
app.exec_()
即使它不是您問題的一部分,我也會向您建議一個略有不同的概念,它不涉及 QLabel。
使用您的方法,您將面臨兩種可能性:
更好的解決方案是完全避免使用 QLabel,並使用自定義繪畫實現您自己的小部件。
這是一個簡單的例子:
class Grid(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setMinimumSize(800, 600)
self.columns = 40
self.rows = 30
# some random objects
self.objects = [
(10, 20),
(11, 21),
(12, 20),
(12, 22),
]
def resizeEvent(self, event):
# compute the square size based on the aspect ratio, assuming that the
# column and row numbers are fixed
reference = self.width() * self.rows / self.columns
if reference > self.height():
# the window is larger than the aspect ratio
# use the height as a reference (minus 1 pixel)
self.squareSize = (self.height() - 1) / self.rows
else:
# the opposite
self.squareSize = (self.width() - 1) / self.columns
def paintEvent(self, event):
qp = QPainter(self)
# translate the painter by half a pixel to ensure correct line painting
qp.translate(.5, .5)
qp.setRenderHints(qp.Antialiasing)
width = self.squareSize * self.columns
height = self.squareSize * self.rows
# center the grid
left = (self.width() - width) / 2
top = (self.height() - height) / 2
y = top
# we need to add 1 to draw the topmost right/bottom lines too
for row in range(self.rows + 1):
qp.drawLine(left, y, left + width, y)
y += self.squareSize
x = left
for column in range(self.columns + 1):
qp.drawLine(x, top, x, top + height)
x += self.squareSize
# create a smaller rectangle
objectSize = self.squareSize * .8
margin = self.squareSize* .1
objectRect = QRectF(margin, margin, objectSize, objectSize)
qp.setBrush(Qt.blue)
for col, row in self.objects:
qp.drawEllipse(objectRect.translated(
left + col * self.squareSize, top + row * self.squareSize))
現在您不再需要make_grid
,您可以使用Grid
代替 QLabel。
請注意,我刪除了一個像素來計算正方形大小,否則將不會顯示最后一行/列線,就像您的像素圖中發生的那樣(考慮在 20x20 邊正方形中,將從 0.5 開始的 20px 線將在像素處剪裁19.5)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.