2014-12-06 1105 views
4

如果用户搜索某些内容,我在我的QTableWidget中有一个自定义代理来高亮匹配。不幸的是,矩形位置往往不适合这发生在某些字符或短语上,或取决于匹配的数量或引导字符串的大小。我无法找到导致此问题的具体内容。这里有一个例子:ExampleQFontMetrics返回不准确的结果

这是我的油漆例程(位从所有的试验和错误试图解决这个问题杂乱):

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

+0

您是否尝试将'painter.device()'传递给'QFontMetrics'构造函数? – BartoszKP 2015-08-17 15:30:57

+0

@BartoszKP我没有,但不幸的是它没有改变任何东西。但它导致我尝试使用'QFontMetrics fm(painter-> font());'在任何情况下,哪个(与'fm.width()'而不是另外两个)一起处理的结果只有1px的常量偏移量!非常感谢我领导这一点,所以如果你想获得信贷,我会很乐意接受它 – Bowdzone 2015-08-18 16:36:35

回答

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构造函数有时很重要。