2014-12-06 4 views
4

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

Это моя краска рутина (немного грязный из всех проб и ошибок пытается решить проблему):

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.

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

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

+0

Вы пытались передать 'painter.device()' в конструктор 'QFontMetrics'? – BartoszKP

+0

@BartoszKP Я, к сожалению, ничего не изменил. Но это заставило меня попробовать 'QFontMetrics fm (painter-> font());' который (вместе с 'fm.width()' вместо двух других) передает результат с только постоянным смещением 1px в любом случае! Большое спасибо за то, что я привел меня к этому, поэтому, если вы хотите взять кредит, я с радостью приму его – Bowdzone

ответ

2

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

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

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

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

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

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

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

Смежные вопросы