简体   繁体   English

QFontMetrics 返回不准确的结果

[英]QFontMetrics returns inaccurate results

I have a custom delegate in my QTableWidget to hightlight matches if a user searches something.如果用户搜索某些内容,我的QTableWidget中有一个自定义委托来突出显示匹配项。 Unfortunately the rectangle position does often not really fit This happens on some characters or phrases or depending on the number of matches or the size of the leading string.不幸的是,矩形位置通常并不适合。这发生在某些字符或短语上,或者取决于匹配的数量或前导字符串的大小。 I can't find something specific causing this.我找不到导致这种情况的具体原因。 Here is one example:这是一个例子:例子 . .

This is my paint routine (a bit messy from all the trial and error trying to fix the issue):这是我的绘画程序(尝试解决问题的所有尝试和错误有点混乱):

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

Notes: filter_string is the string searched for, find_ci is just a wrapper for std::string::find including case-insensitivity but not important here as this test case is fully lower-case and I use std::string for non-qt stuff.注意: filter_string是搜索的字符串, find_ci只是std::string::find的包装器,包括不区分大小写但在这里并不重要,因为这个测试用例是完全小写的,我使用std::string来表示非 qt东西。

Edit: For the width calculation I tried fm.tightBoundingRect().width() , fm.boundingRect.width() and fm.width() with different but never correct results.编辑:对于宽度计算,我尝试fm.tightBoundingRect().width()fm.boundingRect.width()fm.width()具有不同但从未正确的结果。

I use Qt 5.2我使用 Qt 5.2

In my case I got the desired result with the following hack:就我而言,我通过以下 hack 获得了预期的结果:

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

It's not entirely clear why the other overload of boundingRect returns the correct result, but it may be just accidental, because as the documentation states:尚不完全清楚为什么boundingRect的其他重载会返回正确的结果,但这可能只是偶然的,因为正如文档所述:

The bounding rectangle returned by this function is somewhat larger than that calculated by the simpler boundingRect() function.此函数返回的边界矩形比更简单的boundingRect()函数计算的要大一些。 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.此外, fontHeight()lineSpacing()用于计算高度,而不是单个字符的高度。

The width method you propose also will return larger result, but it does not seem correct, as it should be used only when you need a position for a next word:您提出的width方法也将返回更大的结果,但它似乎不正确,因为它应该只在您需要下一个单词的位置时使用:

[...] width() returns the distance to where the next string should be drawn. [...] width()返回到应该绘制下一个字符串的距离。

Also, sometimes it matters whether you pass the result of painter.device() to QFontMetrics constructor.此外,有时是否将painter.device()的结果传递给QFontMetrics构造函数也很重要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM