QFontMetrics возвращает неточные результаты

У меня есть пользовательский делегат в моем QTableWidget выделить совпадения, если пользователь что-то ищет. К сожалению, положение прямоугольника часто не совсем подходит. Это происходит с некоторыми символами или фразами или в зависимости от количества совпадений или размера ведущей строки. Я не могу найти что-то конкретное, вызывающее это. Вот один пример: пример.

Это моя процедура рисования (немного грязно из-за проб и ошибок, пытающихся решить проблему):

void custom_delegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const{

const QTableWidget* table_widget = qobject_cast<const QTableWidget*>(qstyleoption_cast<const QStyleOptionViewItemV3*>(&option)->widget);
const int cell_width = table_widget->columnWidth(index.column());

// basic table cell rectangle
QRect rect_a = option.rect;

// adjust rectangle to match text begin
QStyle* style;
if(table_widget != 0){
style = table_widget->style();
}else{
style = QApplication::style();
}
const int text_horizontal_margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, table_widget) + 1;
QRect rect_b = rect_a.adjusted(text_horizontal_margin, 0, -text_horizontal_margin, 0);

// adjust rectangle to match text height
QFont cell_font = index.model()->data(index, Qt::FontRole).value<QFont>();
cell_font.setPointSize(9);
QFontMetrics fm(cell_font);
const int height = fm.height();

rect_b.setY(rect_a.y() + (rect_a.height() - height)/2);
rect_b.setHeight(height);

// displayed text
std::string cell_text = qstrtostr(fm.elidedText(index.model()->data(index, Qt::DisplayRole).toString(),Qt::ElideRight,rect_a.width()));
int found_pos = find_ci(cell_text, this->filter_string, 0);
int old_pos = 0;
int found_width = 0;
QRect rect_c = rect_b;

// find occurence of filter string in cell_text
while(found_pos != std::string::npos){

std::string front = cell_text.substr(0, found_pos);
rect_c.setX(rect_b.x() + fm.tightBoundingRect(QString::fromStdString(front)).width());
rect_c.setWidth(fm.width(QString::fromStdString(cell_text.substr(found_pos, this->filter_string.size()))));
painter->fillRect(rect_c, Qt::yellow);
old_pos = found_pos+1;
found_pos = find_ci(cell_text, this->filter_string, old_pos);
}
}

Заметки: filter_string это искомая строка, find_ci это просто обертка для std::string::find включая нечувствительность к регистру, но не важно здесь, так как этот тестовый случай полностью строчный, и я использую std::string для не-QT вещи.

Редактировать: Для расчета ширины я пробовал fm.tightBoundingRect().width(), fm.boundingRect.width() а также fm.width() с разными, но никогда не правильными результатами.

Я использую Qt 5.2

4

Решение

В моем случае я получил желаемый результат с помощью следующего хака:

auto initialRect = fm.boundingRect(text);
auto improvedRect = fm.boundingRect(initialRect, 0, text);

Не совсем понятно, почему другая перегрузка boundingRect возвращает правильный результат, но может быть просто случайным, потому что, как указано в документации:

Ограничительный прямоугольник, возвращаемый этой функцией, несколько больше, чем вычисленный более простым boundingRect() функция. Эта функция использует максимальный левый и правый шрифт, необходимый для правильного выравнивания многострочного текста. Также, fontHeight() а также lineSpacing() используются для расчета высоты, а не высоты отдельных персонажей.

width предложенный вами метод также вернет больший результат, но он не кажется правильным, так как его следует использовать только тогда, когда вам нужна позиция для следующего слова:

[…] width() возвращает расстояние до следующей строки.

Кроме того, иногда имеет значение, передаете ли вы результат painter.device() в QFontMetrics конструктор.

2

Другие решения


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