2010-02-04 91 views
14

在我的QGraphicsRectItem :: paint()中,我試圖在它的rect()中繪製該項目的名稱。但是,對於每個不同的項目,它們可以具有可變的寬度,並且類似的名稱可以具有可變的長度。對於Qt 4.6.x,如何自動調整文本大小以適應指定的寬度?

目前我以最大字體大小開始,檢查它是否適合並遞減,直到找到適合的字體大小爲止。到目前爲止,我還沒有找到一個快速簡單的方法來做到這一點。有沒有更好或更有效的方法來做到這一點?

謝謝!

void checkFontSize(QPainter *painter, const QString& name) { 
// check the font size - need a better algorithm... this could take awhile 
while (painter->fontMetrics().width(name) > rect().width()) { 
    int newsize = painter->font().pointSize() - 1; 
    painter->setFont(QFont(painter->font().family(), newsize)); 
} 
} 
+0

參見[這個問題](http://stackoverflow.com/q /1329652分之36575192)。 – 2016-11-29 14:28:53

回答

14

約翰內斯提供了以下解決方案:

float factor = rect().width()/painter->fontMetrics().width(name); 
if ((factor < 1) || (factor > 1.25)) 
{ 
    QFont f = painter->font(); 
    f.setPointSizeF(f.pointSizeF()*factor); 
    painter->setFont(f); 
} 

我給它一個嘗試在我的計劃,到目前爲止,似乎工作得很好。我喜歡它,因爲它一次就會產生結果,但它假定字體寬度與其高度一樣。

http://www.qtcentre.org/threads/27839-For-Qt-4-6-x-how-to-auto-size-text-to-fit-in-a-specified-width

+1

爲什麼是1.25? 10個字符 – marmistrz 2013-08-27 14:02:35

+1

我試過這個,發現它是不準確的,至少對於一些字體。 OP的方法是準確的,但它是一種強力。 – Isaac 2015-05-29 11:48:42

+0

整數除法,(浮點)類型轉換丟失。否則,如果小於1,則因子將爲0. – ragnarius 2017-06-29 10:40:49

0

不幸的是,沒有。對此沒有簡單的解決方案。最明顯的改進是性能明智的計算,並且在文本改變時緩存所需的字體大小,而不是在每個paintEvent中重新計算它。另一個改進是嘗試根據邊界矩的比例來估計正確的大小。製作和測試評估應該讓您更準確地調整大小,而不僅僅是每次迭代減少一次點大小。從qtcentre.org

2

你可以有一個QGraphicsTextItem作爲RECT項目的孩子,測量文本項目的寬度,然後縮放文本項目(一個setTransform())以適合RECT項目的寬度(和高度)。

0

這取決於您期望字體大小變化的範圍。如果範圍很大,則遞增1可能需要很長時間。如果只是幾個點數的問題,速度可能不會成爲問題。

如果範圍很大,另一種方法是添加較大的區間,而不是「1」。如果您在一個步驟中超出了所需的尺寸,請將間隔減少一半。你會在每次越來越小的數量上來回穿越最佳尺寸;當兩個連續間隔之間的差異很小時,您可以退出。

這與根發現中使用的方法類似。這可能是矯枉過正的,因爲在給定的應用程序中可以接受的字體大小可能相當狹窄,而且您已經使用的暴力方法不會浪費太多時間。

1
void myClass::adaptFontSize(QPainter * painter, int flags, QRectF drawRect, QString text){ 
    int flags = Qt::TextDontClip|Qt::TextWordWrap; //more flags if needed 
    QRect fontBoundRect = 
      painter->fontMetrics().boundingRect(drawRect.toRect(),flags, text); 
    float xFactor = drawRect.width()/fontBoundRect.width(); 
    float yFactor = drawRect.height()/fontBoundRect.height(); 
    float factor = xFactor < yFactor ? xFactor : yFactor; 
    QFont f = painter->font(); 
    f.setPointSizeF(f.pointSizeF()*factor); 
    painter->setFont(f); 

} 

或更準確,但貪婪

void myClass::adaptFontSize(QPainter * painter, int flags, QRectF rect, QString text, QFont font){ 
    QRect fontBoundRect; 
    fontBoundRect = painter->fontMetrics().boundingRect(rect.toRect(),flags, text); 
    while(rect.width() < fontBoundRect.width() || rect.height() < fontBoundRect.height()){ 
     font.setPointSizeF(font.pointSizeF()*0.95); 
     painter->setFont(font); 
     fontBoundRect = painter->fontMetrics().boundingRect(rect.toRect(),flags, text); 
    } 
} 
1

鴻溝的征服:

你可以減少你的蠻力方法的遍數: 讓我們說你的首選(最大值)字體大小是40,你有0

如果(40 ==假最小字體大小& 0 == TRUE)

  • 20 =真//劃分可能性在一半與每個猜
  • 30 =假
  • 25 =真
  • 27 =真
  • 28 =假
  • 所以27勝

在哪些方面改進?

這花了6次猜測而不是13次,即使20,12或39是正確的答案,它總是需要大約6次猜測。所以不僅在大多數時候更少的猜測,而且對於用戶體驗來說更加一致。

我覺得除以整數一半每次當它需要猜測的數量範圍的平方根您正在尋找在加一。 Math.sqroot(40-0)+ 1(這只是一個猜測,隨時糾正我。) 您的最小字體大小可能不是0,所以增加這將加快搜索答案。

插圖:

這就像玩猜猜我是誰,球員誰問:「你的名字有一個A」,並削減了一半的可能性不管你通常怎麼回答找到了答案不是誰詢問玩家更快約1個字符每回合「你的名字是山姆」,「你的名字是亞歷克斯」

備選:開始有很好的猜測,然後準確性 我也將促進一些邏輯工作使用所提供的結果測試達仁的答案使用fontMetrics作爲一個很好的開始猜測然後te如果它適合測試+2,如果它不適合測試-2;如果新測試符合測試你跳過1,你會知道你的答案,如果不嘗試移動另一個2等,但理想情況下fontMetrics答案是不超過4遠...

我懷疑這個將產生實際使用案例的最快平均結果。

假設你想要一個int和假定字體規格不準確之處是最小的,這將可能只需要2周或3的猜測。

+0

[牛頓的方法](https://en.wikipedia.org/wiki/Newton%27s_method)是一種類似的方法,並不是人爲地限制它的速度收斂。二進制除法決定了每次迭代只有一個結果位。假設字體大小關係單調遞增,牛頓的字典大小通常比字體大小這樣的簡單問題快得多,就像字體大小的浮點字體一樣。 – 2016-11-29 14:34:13

1

這裏是我的代碼配合(在heigth)一文中,工作得非常好(誤差< 2%我猜)

void scalePainterFontSizeToFit(QPainter &painter, QFont &r_font, float _heightToFitIn) 
{ 
    float oldFontSize, newFontSize, oldHeight; 

    // Init 
    oldFontSize=r_font.pointSizeF(); 

    // Loop 
    for (int i=0 ; i<3 ; i++) 
    { 
     oldHeight = painter.fontMetrics().boundingRect('D').height(); 
     newFontSize = (_heightToFitIn/oldHeight) * oldFontSize; 
     r_font.setPointSizeF(newFontSize); 
     painter.setFont(r_font); 
     oldFontSize = newFontSize; 
     //qDebug() << "OldFontSize=" << oldFontSize << "HtoFitIn=" << _heightToFitIn << " fontHeight=" << oldHeight << " newFontSize=" << newFontSize; 
    } 

    // End 
    r_font.setPointSizeF(newFontSize); 
    painter.setFont(r_font); 
} 
相關問題