고정 열 예제

이 예제는 QTableView 에서 열을 고정하는 방법을 보여줍니다.

"Screenshot of the example"

Qt의 모델/뷰 프레임워크를 사용하여 첫 번째 열이 고정된 테이블을 구현합니다. 이 기법은 테이블의 가장자리에 있는 한 여러 열이나 행에 적용할 수 있습니다.

모델/보기 프레임워크를 사용하면 여러 보기를 사용하여 하나의 모델을 다양한 방식으로 표시할 수 있습니다. 이 예에서는 동일한 모델에 두 개의 보기(하나의 모델을 공유하는 두 개의 table views )를 사용합니다. 고정 열은 기본 테이블 뷰의 자식이며, 다음 섹션에서 단계별로 설명할 오버레이 기법을 사용하여 원하는 시각 효과를 제공합니다.

고정 테이블 위젯 클래스 정의

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);

};

참고: QAbstractItemViewQTableView 의 조상입니다.

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());
}

예제 프로젝트 @ code.qt.io

© 2025 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.