見出し画像

Qt5再入門: 基本タグページのコーディング

前回の記事で、データベースやディレクトリ用のページの基本となるタブページをデザインしました。今回は、これのコーディングになります。

まずはヘッダーファイルです。

// tabpage.h

#ifndef TABPAGE_H
#define TABPAGE_H

#include <QWidget>
#include <QStandardItemModel>

namespace Ui {
class TabPage;
}

using PairItem = QPair<QStandardItem*, QStandardItem*>;

/**
* @brief タブページ抽象クラス
*/
class TabPage : public QWidget
{
 Q_OBJECT

public:
 /**
  * @brief コンストラクタ
  * @param parent 親ウィジェット
  */
 explicit TabPage(QWidget *parent = nullptr);

 /**
  * @brief デストラクタ
  */
 ~TabPage();

 /**
  * @brief メインモデルの初期化
  */
 void initMainModel();

 /**
  * @brief メインモデルに行を追加する
  * @param label ラベル
  * @param value 値
  * @return 追加した行のアイテムポインタ2つ(ラベルと値)
  */
 PairItem addRowToMainModel(const QString &label, const QVariant &value);

 /**
  * @return メインモデルを返す ※追記
  */
  QStandardItemModel *mainModel() { return pMainModel_; }

 /**
  * @brief メインモデルをロードする
  */
 virtual void loadMainModel() = 0;

signals:
 /**
  * @brief 更新 ※追記
  */
 void refresh();

 /**
  * @brief コンソールログへのシグナル
  * @param msg メッセージ
  */
 void consoleLog(const QString &msg);

 /**
  * @brief ステータス表示へのシグナル
  * @param msg メッセージ
  * @param timeout タイムアウト値
  */
 void showStatus(const QString &msg, int timeout = 0);

private:
 Ui::TabPage *ui_;
 QStandardItemModel *pMainModel_;
};

#endif // TABPAGE_H

コンストラクタ、デストラクタ、ui_メンバ変数以外はすべて新規です(ウィザードで自動作成された変数 ui は、ui_ と名前を変更しています)。基本的に、TabPageクラスから派生したページはメインモデル、メインビュー、いずれも使えるようにしておきます。また、MainWindowクラスのコンソールログ、ステータスが利用できるように、それぞれに対応できるシグナルを用意します。このTabPageクラスは、サブクラス化して、純粋仮想関数loadMainModelの実装を要求する抽象クラスになっています。

次にソースファイルです。

// tabpage.cpp

#include "tabpage.h"
#include "ui_tabpage.h"

TabPage::TabPage(QWidget *parent)
 : QWidget(parent)
 , ui_(new Ui::TabPage)
 , pMainModel_(new QStandardItemModel(0, 2, this))
{
 ui_->setupUi(this);

 // メインビューとメインモデルを関連付ける
 ui_->mainView->setModel(pMainModel_);

 // モデルデータ変更時にテーブルの列をリサイズ ※追記
 connect(pMainModel_, &QStandardItemModel::dataChanged,
         ui_->mainView, &QTableView::resizeColumnsToContents
         );

 // リフレッシュボタンを再シグナル ※追記
 connect(ui_->refreshButton, &QPushButton::clicked,
         this, &TabPage::refresh
         );
}

TabPage::~TabPage()
{
 delete ui_;
}

void TabPage::initMainModel() {
 // メインモデルをクリアする
 pMainModel_->clear();

 // メインモデルのヘッダーを設定する
 pMainModel_->setHorizontalHeaderLabels(
       QStringList() << tr("Name") << tr("Value")
       );
}

PairItem TabPage::addRowToMainModel(
   const QString &label,
   const QVariant &value
   ) {
 // ラベルのアイテムを作成する
 auto item0 = new QStandardItem(label);

 // 値のアイテムを作成する
 auto item1 = new QStandardItem(value.toString());

 // 値アイテムのユーザーロールに実値を設定する
 item1->setData(value);

 // アイテム2つをモデルの行として追加する
 pMainModel_->appendRow(
       QList<QStandardItem*>() << item0 << item1
       );

 // 作成したアイテム2つをペアにして返す。
 return PairItem(item0, item1);
}

肝心要の機能はloadMainModel仮想関数に委ねているので、ここではサブクラスで共通して使えるであろう、メインモデルの初期化と、行の追加メソッドを定義します。
行の追加メソッドでは、作成したQStandardItem(いわばセル)のポインタ2つを返しています。カプセル化の観点から、ポインタを外部に渡してしまうのは褒められた作りではないかもしれませんが、できたセルをリードオンリーにするなど、セルに対する後処理を可能にしたいので、このようになっています。

※ 2021/10/2追記

メインモデルのデータ変更時にメインビューの列をリサイズするようにしました。
RefreshボタンのシグナルをTabPage::refreshとして再シグナル化しています。

まとめ

TabPageクラスについては以上になります。RefreshボタンやQSplitterなども装備していますが、いずれも実際にはサブクラスで利用することを想定しています。
直近では、FilePageを作る筋書きなので、次回はこのTabPageクラスをサブクラス化して、FilePageとして仕立てていきます。

この記事が気に入ったらサポートをしてみませんか?