Изменение размера раздела QTableView с помощью пользовательского редактора

У меня есть заявление с QTableView и модель, полученная из QAbstractItemModel: первый столбец таблицы содержит текст (метка для каждой строки), а второй столбец показывает значение, которое можно выбрать с помощью QComboBox создан из пользовательского элемента делегата. Содержимое таблицы может изменяться динамически (количество строк, язык …).

Я хотел бы изменить размер столбцов, чтобы второй соответствовал содержанию, а первый растягивался, занимая оставшееся пространство.

Моя первая попытка была:

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

Результат:

result1

Проблема в том, что когда QComboBox выбран, он не соответствует разделу и обрезается:

result2

Мне удалось решить эту проблему, вручную увеличив ширину:

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

result3

Теперь проблема заключается в том, что при использовании такой константы (в данном случае 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);
// ...
}

Но теперь поля со списком либо обрезаются, либо укорачиваются.

result4 result5


Как я могу решить установить размер раздела на основе всего диапазона содержимого, а не только видимых данных?


Я отвечаю на вопрос с наилучшим подходом, который я когда-либо нашел, и тем, который я использую в проекте прямо сейчас, но я не убежден в этом (я подробно излагаю причины ответа), поэтому я Хотелось бы узнать правильный способ сделать это. Спасибо!

0

Решение

sizeHint в делегате правильный путь, но вместо создания редактора, заполните QStyleOptionComboBox структурировать и использовать qApp->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, nullptr);, где sh это размер внутренней строки. Ты можешь использовать QFontMetrics рассчитать это или просто вызвать базовый класс QStyledItemDelegate::sizeHint(...),

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

Результаты:

result1 result2


Недостатками этого решения являются:

  • У меня нет информации относительно дополнительного места, требуемого QComboBox так что это еще не зависит от стиля (как со вторым подходом к вопросу)
  • Если к делегату элемента будут добавлены новые редакторы, мне бы пришлось включить их вручную в вычисление подсказки по размеру, что не страшно, но похоже на плохой дизайн.

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

По вопросам рекламы [email protected]