1

我有一个应用程序,其中QTableView一个模型派生自QAbstractItemModel:表的第一列包含一个文本(每行的标签),而第二列显示一个可以使用QComboBox从自定义项目委托创建的值来选择的值。表格的内容可能会动态变化(行数、语言...)。

我想调整列的大小,使第二个适合内容,第一个伸展占据剩余空间。

我的第一次尝试是:

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),因为模型中没有任何字体信息。

我尝试过的另一种方法是在方法中设置调整大小QComboBox策略QItemDelegate::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

2

委托中的sizeHint是正确的方法,但不是创建编辑器,而是填充QStyleOptionComboBox结构并使用qApp->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, nullptr);,其中sh是内部字符串的大小。您可以使用它QFontMetrics来计算或只调用基类QStyledItemDelegate::sizeHint(...)

于 2017-07-05T10:07:51.610 回答
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因此它还不是独立于样式的(与问题的第二种方法一样)
  • 如果将新编辑器添加到项目委托中,那么我也必须将它们手动包含在尺寸提示计算中,这不是一个可怕的痛苦,但感觉就像一个糟糕的设计。

PS:使用QComboBox::sizeHinthere 不起作用,因为大小提示是使用QComboBox::sizeAdjustPolicywhich 计算的,如问题中突出显示的那样,不会将组合框正确调整到单元格中。


更新

我已经根据评论和接受的答案的指示更新了解决方案。这是完整的代码以供将来参考:

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 回答