2012-11-13 41 views
1

我使用QPainter在QImage上繪製多行文本。但是,我還需要在每個角色的邊界框周圍顯示一個彩色矩形。QPainter :: drawText,獲取每個字符的包圍盒

所以我需要知道每個角色在繪製時的邊界框。

例如,對於

painter.drawText(QRect(100, 100, 200, 200), Qt::TextWordWrap, "line\nline2", &r); 

我需要得到10個矩形,考慮到換行,自動換行,製表符等

例如,第二'l'的矩形會低於第一個'l'的矩形,而不是在'e'的右側,因爲換行符。

有點像紅色矩形在這張照片上的座標(我已經把他們的手所以他們並不是真正正確的位置):

enter image description here

回答

2

這可能不是最好的解決辦法,但這是我能想到的最好的一個。我相信你將不得不「自己動手」。也就是說,不是繪製文本塊,而是一次繪製一個字符。然後,您可以使用QFontMetrics獲取每個字符的邊界框。

這是一個小小的工作,但不是太糟糕。像(僞代碼,而不是代碼)的東西:

QFontMetrics fm(myFont, paintDevice); 
int x = startX; 
int y = startY; 
for (unsigned int i = 0; i < numChars; i++) 
{ 
    char myChar = mystr[i]; // get character to print/bound 
    QRect rect = fm.boundingRect(myChar); // get that char's bounding box 
    painter.drawText(x, y, Qt::TextWordWrap, mystr[i], &r); // output char 
    painter.drawRect(...); // draw char's bounding box using 'rect' 
    x += rect.width();  // advance current position horizontally 

    // TODO: 
    // if y > lineLen  // handle cr 
    //  x = startX; 
    //  y += line height 

} 

退房QFontMetrics,它有越來越邊框,最小邊界框許多不同的方法等

QFontMetrics 4.7

唉唉。 ..我現在看到你正在使用的重載返回實際的邊界矩形。如果你喜歡,你可以使用它並跳過QFontMetrics - 否則整體算法是相同的。

+0

好的,謝謝,都試圖實現這一點。我正在考慮尋找'QPainter :: drawText'的[實際源代碼](http://qt.gitorious.org/qt/qt/blobs/4.8/src/gui/painting/qpainter.cpp),並使用那個,但事實證明它太複雜了,我甚至無法找到角色實際發生的地方。該圖由一個稱爲'qt_format_text'的非常大的函數處理,我認爲他們使用'QTextLine'作爲繪圖。 – sashoalm

1

您可以QFontMetrics::boundingRect(QChar)檢索單個字符的邊界框,但它們必須在一個偏移量(QFontMetrics::ascent從頂部和前面的字符QFontMetrics::width左一)被渲染,因爲它們相對於字體的基礎而不是整個字符串的邊界框的底部。
還需要分別處理幾條線。 QFontMetrics::lineSpacing給你他們的抵消。

QPainter painter(this); 
painter.setFont(QFont("Arial", 72)); 

auto pen = painter.pen(); 

QString text{"line\nline2\ngg\n`"}; 
QRect boundingRect; 
painter.drawText(rect(), Qt::AlignLeft | Qt::AlignTop, text, &boundingRect); 
painter.drawRect(boundingRect.adjusted(0, 0, -pen.width(), -pen.width())); 

pen.setColor(Qt::red); 
painter.setPen(pen); 
const auto lines = text.split('\n'); 
const auto fm = painter.fontMetrics(); 
for (int linei = 0; linei < lines.size(); ++linei) { 
    const auto & line = lines[linei]; 
    for (int chi = 0; chi < line.size(); ++chi) { 
     const auto bounds = fm.boundingRect(line[chi]); 
     const auto xoffset = bounds.x() + fm.width(line, chi); 
     const auto lineOffset = linei * fm.lineSpacing() + fm.ascent(); 
     const auto yoffset = lineOffset + bounds.y(); 
     painter.drawRect(QRect{xoffset, yoffset, bounds.width(), bounds.height()}); 
    } 
} 

結果

其中,遺憾的是 - 不是十全十美。