凍結カラムの例
この例では、QTableView 内のカラムをフリーズする方法を示します。
Qtのモデル/ビュー・フレームワークを使用して、最初の列が凍結されたテーブルを実装します。このテクニックは、テーブルの端であれば、複数の列や行に適用することができます。
モデル/ビュー・フレームワークでは、1つのモデルを複数のビューを使ってさまざまな方法で表示することができます。この例では、同じモデルに対して2つのビューを使用しています。1つのモデルを共有する2つのtable views 。凍結された列は、メインのテーブルビューの子であり、これから順を追って説明するオーバーレイ技術を使用して、望ましい視覚効果を提供します。
FreezeTableWidgetクラスの定義
FreezeTableWidget
クラスには、コンストラクタとデストラクタがあります。また、オーバーレイとして使用するテーブルビューと、両方のテーブルビューの共有モデルです。セクションのサイズを同期させるために2つのスロットが追加され、凍結されたカラムのジオメトリを再調整する関数も追加されています。さらに、resizeEvent ()とmoveCursor ()の2つの関数を再実装している。
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
)は、メインのテーブルビューと同じモデルでなければなりません。setColumnHiddenしかし、ここでの違いは、frozenTableView
の可視カラムは最初のカラムだけである。
void FreezeTableWidget::init() { frozenTableView->setModel(model()); frozenTableView->setFocusPolicy(Qt::NoFocus); frozenTableView->verticalHeader()->hide(); frozenTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Fixed); viewport()->stackUnder(frozenTableView);
凍結された列のZオーダーに関しては、ビューポートの上に積み重ねます。これは、ビューポート上でstackUnder ()を呼び出すことで実現されます。見栄えのために、列がメインのテーブルビューからフォーカスを奪うのを防ぎます。また、両方のビューが同じ選択モデルを共有し、一度に1つのセルしか選択できないようにしています。アプリケーションの見栄えを良くし、メインのテーブルビューと一貫した動作をさせるために、他にもいくつかの微調整を行っています。列が正しい場所を占めるようにするために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()); }
© 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.