고정된 열 예시
이 예제는 테이블 뷰( QTableView) 내에서 열을 고정하는 방법을 보여줍니다.

Qt의 모델/뷰 프레임워크를 사용하여 첫 번째 열이 고정된 테이블을 구현합니다. 이 기법은 테이블의 가장자리에 위치한 열이나 행이라면 여러 개에 적용할 수 있습니다.
모델/뷰 프레임워크를 사용하면 하나의 모델을 여러 뷰를 통해 다양한 방식으로 표시할 수 있습니다. 이 예제에서는 동일한 모델에 두 개의 뷰, 즉 하나의 모델을 공유하는 두 개의 ` table views `를 사용합니다. 고정된 열은 메인 테이블 뷰의 자식이며, 다음 섹션에서 단계별로 설명할 오버레이 기법을 사용하여 원하는 시각적 효과를 구현합니다.

FreezeTableWidget 클래스 정의
FreezeTableWidget 클래스에는 생성자와 소멸자가 있습니다. 또한, 오버레이로 사용할 테이블 뷰와 두 테이블 뷰가 공유하는 모델이라는 두 개의 비공개 멤버가 있습니다. 섹션 크기를 동기화하고 고정된 열의 지오메트리를 재조정하는 데 도움이 되도록 두 개의 슬롯이 추가되었습니다. 또한, ` resizeEvent()` 및 ` moveCursor()` 함수 두 가지를 재구현했습니다.
class FreezeTableWidget : public QTableView {
Q_OBJECT
public:
FreezeTableWidget(QAbstractItemModel * model);
~FreezeTableWidget();
protected:
void resizeEvent(QResizeEvent *event) override;
QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
void scrollTo (const QModelIndex & index, ScrollHint hint = EnsureVisible) override;
private:
QTableView *frozenTableView;
void init();
void updateFrozenTableGeometry();
private slots:
void updateSectionWidth(int logicalIndex, int oldSize, int newSize);
void updateSectionHeight(int logicalIndex, int oldSize, int newSize);
};참고: ` QAbstractItemView `는 ` QTableView`의 상위 클래스입니다.
FreezeTableWidget 클래스 구현
생성자는 model 을 인수로 받아 고정 열을 표시하는 데 사용할 테이블 뷰를 생성합니다. 그런 다음 생성자 내에서 init() 함수를 호출하여 고정 열을 설정합니다. 마지막으로, QHeaderView::sectionResized() 신호(가로 및 세로 헤더용)를 적절한 슬롯에 연결합니다. 이를 통해 고정 열의 섹션이 헤더와 동기화되도록 보장합니다. 또한 고정 열이 테이블의 나머지 부분과 함께 세로로 스크롤되도록 세로 스크롤바를 서로 연결합니다.
FreezeTableWidget::FreezeTableWidget(QAbstractItemModel * model)
{
setModel(model);
frozenTableView = new QTableView(this);
init();
//connect the headers and scrollbars of both tableviews together
connect(horizontalHeader(),&QHeaderView::sectionResized, this,
&FreezeTableWidget::updateSectionWidth);
connect(verticalHeader(),&QHeaderView::sectionResized, this,
&FreezeTableWidget::updateSectionHeight);
connect(frozenTableView->verticalScrollBar(), &QAbstractSlider::valueChanged,
verticalScrollBar(), &QAbstractSlider::setValue);
connect(verticalScrollBar(), &QAbstractSlider::valueChanged,
frozenTableView->verticalScrollBar(), &QAbstractSlider::setValue);
}init() 함수에서는 고정 열을 표시하는 오버레이 테이블 뷰가 올바르게 설정되었는지 확인합니다. 즉, 이 테이블 뷰( frozenTableView)는 메인 테이블 뷰와 동일한 모델을 가져야 합니다. 다만, 여기서 차이점은 frozenTableView 의 가시적인 열은 첫 번째 열뿐이며, 나머지 열은 setColumnHidden()을 사용하여 숨긴다는 점입니다.
void FreezeTableWidget::init()
{
frozenTableView->setModel(model());
frozenTableView->setFocusPolicy(Qt::NoFocus);
frozenTableView->verticalHeader()->hide();
frozenTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed);
viewport()->stackUnder(frozenTableView);고정된 열의 z-순서와 관련하여, 이를 뷰포트 위에 배치합니다. 이는 뷰포트에서 ` stackUnder()`를 호출하여 구현됩니다. 시각적 일관성을 위해, 이 열이 메인 테이블 뷰의 포커스를 빼앗지 않도록 방지합니다. 또한, 두 뷰가 동일한 선택 모델을 공유하도록 하여 한 번에 하나의 셀만 선택할 수 있도록 합니다. 애플리케이션의 외관을 개선하고 메인 테이블뷰와 일관된 동작을 보장하기 위해 몇 가지 추가 조정이 이루어집니다. 컬럼이 올바른 위치에 배치되도록 updateFrozenTableGeometry() 를 호출했다는 점에 유의하십시오.
frozenTableView->setStyleSheet("QTableView { border: none;"
"background-color: #8EDE21;"
"selection-background-color: #999}"); //for demo purposes
frozenTableView->setSelectionModel(selectionModel());
for (int col = 1; col < model()->columnCount(); ++col)
frozenTableView->setColumnHidden(col, true);
frozenTableView->setColumnWidth(0, columnWidth(0) );
frozenTableView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenTableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
frozenTableView->show();
updateFrozenTableGeometry();
setHorizontalScrollMode(ScrollPerPixel);
setVerticalScrollMode(ScrollPerPixel);
frozenTableView->setVerticalScrollMode(ScrollPerPixel);
}고정된 컬럼의 크기를 조정할 때, 매끄러운 통합을 위해 메인 테이블 뷰의 동일한 컬럼도 그에 따라 크기가 조정되어야 합니다. 이는 가로 및 세로 헤더 모두에서 발산되는 sectionResized() 신호의 newSize 값을 통해 컬럼의 새 크기를 가져옴으로써 달성됩니다.
void FreezeTableWidget::updateSectionWidth(int logicalIndex, int /* oldSize */, int newSize)
{
if (logicalIndex == 0){
frozenTableView->setColumnWidth(0, newSize);
updateFrozenTableGeometry();
}
}
void FreezeTableWidget::updateSectionHeight(int logicalIndex, int /* oldSize */, int newSize)
{
frozenTableView->setRowHeight(logicalIndex, newSize);
}고정된 열의 너비가 수정되었으므로, updateFrozenTableGeometry() 를 호출하여 위젯의 기하학적 구조를 그에 맞게 조정합니다. 이 함수에 대해서는 아래에서 더 자세히 설명합니다.
QTableView::resizeEvent()을 재구현할 때, 우리는 기본 클래스 구현을 호출한 후 updateFrozenTableGeometry() 를 호출합니다.
void FreezeTableWidget::resizeEvent(QResizeEvent * event)
{
QTableView::resizeEvent(event);
updateFrozenTableGeometry();
}키보드로 테이블을 탐색할 때, 현재 선택 영역이 고정된 열 뒤로 숨겨지지 않도록 해야 합니다. 이를 동기화하기 위해 QTableView::moveCursor()을 재구현하고, 필요 시 기본 클래스 구현을 호출한 후 스크롤바 위치를 조정합니다.
QModelIndex FreezeTableWidget::moveCursor(CursorAction cursorAction,
Qt::KeyboardModifiers modifiers)
{
QModelIndex current = QTableView::moveCursor(cursorAction, modifiers);
if (cursorAction == MoveLeft && current.column() > 0
&& visualRect(current).topLeft().x() < frozenTableView->columnWidth(0) ){
const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x()
- frozenTableView->columnWidth(0);
horizontalScrollBar()->setValue(newValue);
}
return current;
}고정 열의 기하 구조 계산은 그 아래에 있는 테이블의 기하 구조를 기반으로 하므로, 고정 열은 항상 올바른 위치에 표시됩니다. QFrame::frameWidth() 함수를 사용하면 어떤 스타일을 사용하든 이 기하 구조를 올바르게 계산하는 데 도움이 됩니다. 우리는 뷰포트와 헤더의 기하 구조를 활용하여 고정 열의 경계를 설정합니다.
void FreezeTableWidget::updateFrozenTableGeometry()
{
frozenTableView->setGeometry(verticalHeader()->width() + frameWidth(),
frameWidth(), columnWidth(0),
viewport()->height()+horizontalHeader()->height());
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.