c – 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的包装,包括case-insensitivity但在这里不重要,因为这个测试用例是完全小写的,我使用std :: string作为非qt东西.

编辑:对于宽度计算我尝试fm.tightBoundingRect().width(),fm.boundingRect.width()和fm.width()具有不同但从不正确的结果.

我使用Qt 5.2

最佳答案 在我的情况下,我得到了以下hack所需的结果:

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

目前还不完全清楚为什么other overload of boundingRect会返回正确的结果,但可能只是偶然的,因为文档说明:

The bounding rectangle returned by this function is somewhat larger than that calculated by the simpler boundingRect() function. This function uses the maximum left and right font bearings as is necessary for multi-line text to align correctly. Also, fontHeight() and lineSpacing() are used to calculate the height, rather than individual character heights.

你提出的width方法也会返回更大的结果,但它似乎不正确,因为它只应在你需要下一个单词的位置时使用:

[…] width() returns the distance to where the next string should be drawn.

此外,有时您是否将painter.device()的结果传递给QFontMetrics构造函数也很重要.

点赞