我正在嘗試創建一個方形按鈕網格,如果視窗太小而無法顯示所有這些按鈕,則該網格可滾動。我希望在最左邊的列和最上面的行上有顯示按鈕索引的標簽。
有沒有辦法創建一個 QScrollArea,其中最頂行和最左側列中的小部件(標簽)“凍結”。類似于您如何凍結 Excel 作業表中的行和列,它們在您滾動時跟隨視圖。
在此處查看模型:

歡迎使用 Qt 和 PyQt。
uj5u.com熱心網友回復:
我使用此答案中概述的方法解決了多個 QScrollAreas 的問題。這個想法是讓凍結區域QScrollArea禁用滾動,而未凍結的QScrollArea滾動條信號連接到凍結的QScrollArea滾動條槽。
這是我的模型的代碼,最上面的行和最左邊的列被凍結。特別相關的部分是FrozenScrollArea類和Window類內部的連接。
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
QApplication,
QPushButton,
QWidget,
QScrollArea,
QGridLayout,
QLabel,
QFrame,
QSpacerItem,
QSizePolicy,
)
ROWS = 10
COLS = 20
SIZE = 35
style = """
Button {
padding: 0;
margin: 0;
border: 1px solid black;
}
Button::checked {
background-color: lightgreen;
}
"""
class Button(QPushButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setFixedSize(SIZE, SIZE)
self.setCheckable(True)
self.setStyleSheet(style)
class Label(QLabel):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setAlignment(Qt.AlignCenter)
self.setFixedSize(SIZE, SIZE)
class Labels(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QGridLayout()
layout.setHorizontalSpacing(0)
layout.setVerticalSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
class FrozenScrollArea(QScrollArea):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWidgetResizable(True)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.verticalScrollBar().setEnabled(False)
self.horizontalScrollBar().setEnabled(False)
class FrozenRow(FrozenScrollArea):
def __init__(self, parent):
super().__init__()
labels = Labels(parent)
for c in range(COLS):
label = Label(self, text = str(c))
labels.layout().addWidget(label, 0, c, 1, 1, Qt.AlignCenter)
labels.layout().addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum), 0, COLS, 1, 1)
self.setFrameShape(QFrame.NoFrame)
self.setFixedHeight(SIZE)
self.setWidget(labels)
class FrozenColumn(FrozenScrollArea):
def __init__(self, parent):
super().__init__()
labels = Labels(parent)
for r in range(ROWS):
label = Label(self, text = str(r))
labels.layout().addWidget(label, r, 0, 1, 1, Qt.AlignCenter)
labels.layout().addItem(QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding), ROWS, 0, 1, 1)
self.setFrameShape(QFrame.NoFrame)
self.setFixedWidth(SIZE)
self.setWidget(labels)
class ButtonGroup(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
layout = QGridLayout()
for r in range(ROWS):
for c in range(COLS):
button = Button(self)
layout.addWidget(button, r, c, 1, 1)
layout.setHorizontalSpacing(0)
layout.setVerticalSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(layout)
class Buttons(QScrollArea):
def __init__(self, parent):
super().__init__()
self.setFrameShape(QFrame.NoFrame)
self.setWidget(ButtonGroup(parent))
class Window(QWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# layout
layout = QGridLayout()
self.setLayout(layout)
layout.setHorizontalSpacing(0)
layout.setVerticalSpacing(0)
layout.setContentsMargins(0, 0, 0, 0)
# frozen row (top)
self.frozenRow = FrozenRow(self)
layout.addWidget(self.frozenRow, 0, 1, 1, 1)
# frozen column (left)
self.frozenColumn = FrozenColumn(self)
layout.addWidget(self.frozenColumn, 1, 0, 1, 1)
# button grid
self.buttons = Buttons(self)
layout.addWidget(self.buttons, 1, 1, 1, 1)
# scrollbar connections
self.buttons.horizontalScrollBar().valueChanged.connect(self.frozenRow.horizontalScrollBar().setValue) # horizontal scroll affects frozen row only
self.buttons.verticalScrollBar().valueChanged.connect(self.frozenColumn.verticalScrollBar().setValue) # vertical scroll affects frozemn column only
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec())
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/361437.html
標籤:Python qt pyqt qscrollarea
