QComboBoxのカスタムテーブルビュー実装

カスタムドロップダウンテーブルの実装アプローチ

前回のリスト形式に続き、今回はQComboBoxのドロップダウン領域にテーブルビューを表示する高度なカスタマイズ手法を解説します。この実装では、鉄道サイトの地域選択インターフェースのような多列データ表現が可能となります。

主要コンポーネント設計

システムは以下のクラス構造で構築されています:

  • BaseComboBox: 基本機能を提供する抽象基底クラス
  • ListDropDown: 単一リスト表示の実装
  • TableDropDown: テーブル表示の実装
  • CustomHeaderView: カスタム描画するヘッダビュー
  • CitySelector: 都市選択専用の実装クラス

基本インターフェース定義

class BaseComboBox : public QWidget {
public:
    explicit BaseComboBox(ItemDisplayType type, QWidget* parent = nullptr);
    
    void SetDelimiter(char delimiter);
    void AddEntry(const QString& entry);
    void AddEntries(const QVector<QString>& entries);
    
    void SetEntryWidth(int width);
    void SetEntryHeight(int height);
    void SetMaxVisibleItems(int count);

protected:
    virtual bool eventFilter(QObject*, QEvent*) override;
    virtual void AppendEntry(const QString& entry) = 0;
    virtual void AdjustEntryWidth(int width) = 0;
    virtual void AdjustEntryHeight(int height) = 0;
    
    QWidget* CreateEntryWidget(const QString& text);
    
private:
    void InitializeComponents();
};

テーブルドロップダウンの実装

class TableDropDown : public BaseComboBox {
    Q_OBJECT

public:
    explicit TableDropDown(ItemDisplayType type = CheckableItem, 
                          QWidget* parent = nullptr);
    
    void SetColumnCount(int columns);
    void SetHeaderLabels(const QStringList& labels);
    void SetHeaderVisible(bool visible);
    void FinalizeData();

protected:
    virtual bool eventFilter(QObject*, QEvent*) override;
    virtual void AppendEntry(const QString& entry) override;
    virtual void AdjustEntryWidth(int width) override;
    virtual void AdjustEntryHeight(int height) override;
    virtual void PadIncompleteRows();

private slots:
    void HandleHeaderClick(int index);

private:
    void SetupTableView();
    int m_ColumnCount = 2;
};

透過背景の実現手法

ドロップダウンの背景を透過させるには、親ウィジェットの属性設定が必要です:

if (QWidget* parent = comboBox->view()->parentWidget()) {
    parent->setAttribute(Qt::WA_TranslucentBackground);
    parent->setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
}

都市選択コンポーネントの使用例

CitySelector selector(parentWidget);
selector.SetDisplayType(LabelItem);
selector.SetHorizontalHeaders({"ABCDEF", "GHIJ", "KLMN", "PQRSTUVM", "XYZ"});
selector.SetVerticalHeaders({"A", "B", "C", "D", "E"});

selector.SetCurrentGroup('B');
selector.AddEntry("Beijing");
selector.AddEntry("Shanghai");
selector.FinalizeData();

スクロール位置のリセット処理

テーブルスクロール後の表示不具合を防ぐため、ドロップダウン非表示時にトップ位置にリセットします:

bool TableDropDown::eventFilter(QObject* target, QEvent* event) {
    if (target == m_ComboBox->view()->parentWidget() && 
        event->type() == QEvent::Hide) {
        if (QTableWidget* table = qobject_cast(m_DropDownWidget)) {
            table->scrollToTop();
        }
    }
    return BaseComboBox::eventFilter(target, event);
}

タグ: Qt QComboBox TableView CustomWidget QHeaderView

5月24日 11:18 投稿