【问题标题】:Resizing QTableView section with custom editor使用自定义编辑器调整 QTableView 部分的大小
【发布时间】:2017-07-04 15:39:51
【问题描述】:

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

我想调整列的大小,以便第二个适合内容,而第一个会延伸占据剩余空间。

我的第一次尝试是:

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

结果:

问题是当QComboBox被选中时,它不适合该部分并且被剪裁了:

我已经通过手动增加宽度来解决这个问题:

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

现在的问题是,通过使用这样的常量(在这种情况下为 40),部分的宽度将根据显示的值而不是所有可能的值而变化(如果已经显示了最大的值,或者只显示了最短的值) )。此外,该常量将取决于所使用的样式,因为它还与 QComboBox 占用的空间有关。

我曾考虑使用Qt::SizeHintRole 手动计算截面宽度,但它完全被忽略了。即使是这样,我也无法计算文本的实际宽度(使用QFontMetrics::width),因为模型中没有任何字体信息。

我尝试过的另一种方法是在QItemDelegate::createEditor 方法中设置QComboBox 的调整大小策略:

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

但现在组合框要么被剪裁,要么被缩短。


如何根据完整的内容范围而不是仅可见数据来设置节大小?


我正在用我目前找到的最佳方法以及我现在在项目中使用的最佳方法自行回答这个问题,但我不相信它(我详细说明了答案的原因) 所以我想知道正确的方法。谢谢!

【问题讨论】:

    标签: c++ qt qlistview qitemdelegate sizehint


    【解决方案1】:

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

    【讨论】:

    • @ilbeldus,快速提问:为什么需要为 sizeFromContents 提供大小?我认为设置 QStyleOptionComboBox.currentText 就足够了。谢谢!
    【解决方案2】:

    到目前为止我发现的最佳选择是重新实现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;
    }
    

    结果:


    此解决方案的缺点是:

    • 我没有关于 QComboBox 所需额外空间的信息,因此它还不是独立于样式的(与问题的第二种方法一样)
    • 如果将新编辑器添加到项目委托中,那么我也必须手动将它们包括在大小提示计算中,这不是一个可怕的痛苦,但感觉就像一个糟糕的设计。

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


    更新

    我已根据 cmets 的指示和接受的答案更新了解决方案。以下是完整的代码供以后参考:

    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;
    }
    

    【讨论】:

    • 委托中的 sizeHint 是正确的方法,但不是创建编辑器(顺便说一句,你正在泄漏)填充 QStyleOptionComboBox 结构并使用 qApp->style()->sizeFromContents( QStyle::CT_ComboBox, &opt, sh, nullptr);其中 sh 是内部字符串的大小,可以使用 QFontMetrics 来计算
    • 谢谢@IlBeldus,我明天去看看QStyleOptionComboBox!关于泄漏,我认为它是正确处理的,因为我使用的是std::unique_ptr,但如果我遗漏了什么,请告诉我。
    • @IlBeldus 效果很好,非常感谢!请随时发布完整答案,以便我接受您的贡献。
    猜你喜欢
    • 2017-11-07
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 2015-02-16
    • 1970-01-01
    • 2013-06-16
    相关资源
    最近更新 更多