У меня есть заявление с 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
) потому что у меня нет информации о шрифте в модели.
Другой подход, который я попробовал, — установить политику настройки размера QComboBox
в QItemDelegate::createEditor
метод:
QWidget* myItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
auto comboBox = new QComboBox(parent);
comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
// ...
}
Но теперь поля со списком либо обрезаются, либо укорачиваются.
Как я могу решить установить размер раздела на основе всего диапазона содержимого, а не только видимых данных?
Я отвечаю на вопрос с наилучшим подходом, который я когда-либо нашел, и тем, который я использую в проекте прямо сейчас, но я не убежден в этом (я подробно излагаю причины ответа), поэтому я Хотелось бы узнать правильный способ сделать это. Спасибо!
sizeHint
в делегате правильный путь, но вместо создания редактора, заполните QStyleOptionComboBox
структурировать и использовать qApp->style()->sizeFromContents(QStyle::CT_ComboBox, &opt, sh, nullptr);
, где sh
это размер внутренней строки. Ты можешь использовать QFontMetrics
рассчитать это или просто вызвать базовый класс QStyledItemDelegate::sizeHint(...)
,
Лучший вариант, который я нашел до сих пор, — это 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
который, как отмечено в вопросе, не корректно комбинирует поля со списком в ячейке.
ОБНОВИТЬ
Я обновил решение, следуя указаниям из комментариев, и принял ответ. Вот полный код для дальнейшего использования:
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;
}