1

QTableViewとから派生したモデルを持つアプリケーションがありますQAbstractItemModel。テーブルの最初の列にはテキスト (各行のラベル) が含まれ、2 番目の列にはQComboBox、カスタム アイテム デリゲートから作成された を使用して選択できる値が表示されます。テーブルの内容は動的に変更される場合があります (行数、言語など)。

列のサイズを変更して、2 番目の列がコンテンツに収まるようにし、最初の列が残りのスペースを占めるように拡大したいと考えています。

私の最初の試みは:

tblData->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
tblData->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);

結果:

結果1

問題は、QComboBoxが選択されたときにセクションに収まらず、クリップされていることです。

結果2

幅を手動で増やすことで、この問題を解決できました。

tblData->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
tblData->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
tblData->resizeColumnToContents(1);
tblData->horizontalHeader()->resizeSection(1, tblData->horizontalHeader()->sectionSize(1) + 40);

結果3

ここでの問題は、そのような定数 (この場合は 40) を使用することで、可能なすべての値ではなく、表示される値に応じてセクションの幅が変化することです (最大値が既に表示されている場合と、最小値のみが表示されている場合)。また、その定数は、使用されるスタイルに依存します。これは、QComboBox.

を使用してセクション幅を手動で計算することを考えましたQt::SizeHintRoleが、完全に無視されます。たとえそうであったとしてもQFontMetrics::width、モデルにフォント情報がないため、( を使用して) テキストの実際の幅を計算することはできません。

私が試した別のアプローチはQComboBoxQItemDelegate::createEditorメソッドのサイズ調整ポリシーを設定することです。

QWidget* myItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
  auto comboBox = new QComboBox(parent);
  comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
  // ...
}

しかし、コンボ ボックスは切り取られているか、短くなっています。

結果4 結果5


表示されるデータだけでなく、コンテンツの全範囲に基づいてセクション サイズを設定するにはどうすればよいですか?


これまでに見つけた最良のアプローチと、現在プロジェクトで使用しているアプローチで質問に自己回答していますが、納得していません (回答の理由を詳しく説明しています)。 「正しい方法を知りたい。ありがとう!

4

2 に答える 2

0

これまでに見つけた最良のオプションは、 を再実装することQItemDelegate::sizeHintです。 からのフォント情報QStyleOptionViewItemと、 に含める要素のリストがありますQComboBox

QSize myItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
  auto hint = QItemDelegate::sizeHint(option, index);

  QFontMetrics fm(option.font);

  std::unique_ptr<QWidget> editor(createEditor(nullptr, option, index));
  auto comboBox = qobject_cast<QComboBox*>(editor.get());
  if (comboBox != nullptr) {
    int width = 0;
    for (int ii = 0; ii < comboBox->count(); ++ii) {
      width = std::max(width, fm.width(comboBox->itemText(ii)) + 20);
    }
    hint.setWidth(std::max(hint.width(), width));
  }

  return hint;
}

結果:

結果1 結果2


このソリューションの欠点は次のとおりです。

  • に必要な追加スペースに関する情報QComboBoxがないため、まだスタイルに依存していません(質問の2番目のアプローチと同様)
  • 新しいエディターがアイテム デリゲートに追加された場合、サイズ ヒントの計算にもそれらを手動で含める必要があります。これはひどい苦痛ではありませんが、悪い設計のように感じます。

PS:QComboBox::sizeHintサイズのヒントはQComboBox::sizeAdjustPolicy、質問で強調表示されているように、コンボボックスをセルに正しく調整しないを使用して計算されるため、ここでの使用は機能しません。


アップデート

コメントからの指示に従ってソリューションを更新し、回答を受け入れました。後で参照するための完全なコードは次のとおりです。

QStringList myItemDelegate::getPossibleValuesForIndex(const QModelIndex& index) const
{
  // returns list of all possible values for given index (the content of the combo box)
}

QSize myItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
  auto hint = QItemDelegate::sizeHint(option, index);

  QFontMetrics fm(option.font);    
  QStyleOptionComboBox comboOption;
  comboOption.rect  = option.rect;
  comboOption.state = option.state | QStyle::State_Enabled;

  Q_FOREACH (const auto& value, getPossibleValuesForIndex(index)) {
    hint = hint.expandedTo(qApp->style()->sizeFromContents(QStyle::CT_ComboBox,
                           &comboOption, QSize(fm.width(value), hint.height())));
  }

  return hint;
}
于 2017-07-04T15:39:51.990 に答える