2010-02-04 32 views
14

Bên trong QGraphicsRectItem :: paint(), tôi đang cố gắng vẽ tên của mục trong rect của nó(). Tuy nhiên, đối với mỗi mục khác nhau, chúng có thể có chiều rộng thay đổi và các tên tương tự có thể có độ dài thay đổi.Đối với Qt 4.6.x, cách tự động định kích thước văn bản cho vừa với chiều rộng được chỉ định?

Hiện tại tôi đang bắt đầu với kích thước phông chữ tối đa, kiểm tra xem nó có phù hợp và giảm kích cỡ cho đến khi tôi tìm thấy kích thước phông chữ phù hợp hay không. Cho đến nay, tôi đã không thể tìm thấy một cách nhanh chóng và dễ dàng để làm điều này. Có cách nào tốt hơn, hiệu quả hơn để thực hiện việc này không?

Cảm ơn!

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

Xem thêm [câu hỏi này] (http://stackoverflow.com/q/36575192/1329652). –

Trả lời

14

Johannes từ qtcentre.org cung cấp các giải pháp sau đây:

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

Tôi đưa cho nó một thử trong chương trình của tôi và cho đến nay, có vẻ như để làm việc khá tốt. Tôi thích nó bởi vì nó tạo ra các kết quả trong một lần truyền, nhưng nó giả định rằng chiều rộng phông chữ có chiều rộng như chiều cao của nó.

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

+1

Tại sao lại là 1.25? 10 ký tự – marmistrz

+1

Tôi đã thử điều này và thấy nó không chính xác, ít nhất là đối với một số phông chữ. Phương pháp của OP là chính xác, trong khi đó là một sức mạnh vũ phu. – Isaac

+0

Phân tách số nguyên, một dàn diễn viên loại (phao) bị thiếu. Nếu không thì hệ số sẽ là 0 nếu nó nhỏ hơn 1. – ragnarius

0

Thật không may, không. Không có giải pháp dễ dàng cho việc này. Cải tiến rõ ràng nhất, hiệu suất-khôn ngoan sẽ được tính toán và bộ nhớ cache kích thước phông chữ cần thiết khi văn bản được thay đổi thay vì tính toán lại nó trong mỗi paintEvent. Một cải tiến khác sẽ là cố gắng ước tính kích thước chính xác dựa trên tỷ lệ của đường biên giới hạn. Việc thực hiện và thử nghiệm các ước tính sẽ giúp bạn chỉnh sửa kích thước nhanh hơn nhiều so với việc đơn giản giảm kích thước điểm của mỗi lần lặp lại.

2

Bạn có thể có một QGraphicsTextItem như một đứa trẻ của mặt hàng đó rect, đo chiều rộng mục văn bản và sau đó mở rộng các mục văn bản (setTransform()) để phù hợp với chiều rộng mặt hàng rect (và chiều cao).

0

Điều này tùy thuộc vào phạm vi mà bạn mong đợi kích thước phông chữ thay đổi. Nếu phạm vi là lớn, tăng thêm bởi một trong những có thể mất một thời gian dài. Nếu nó chỉ là vấn đề của một số kích thước điểm, tốc độ có thể sẽ không là một vấn đề.

Nếu phạm vi lớn, cách tiếp cận khác sẽ là thêm khoảng thời gian lớn hơn, thay vì '1'. Nếu bạn vượt quá kích thước mong muốn trong một bước, hãy giảm khoảng thời gian bằng một nửa. Bạn sẽ bị trả lại qua kích thước tối ưu bởi số lượng nhỏ hơn và nhỏ hơn mỗi lần; khi sự khác biệt giữa hai khoảng kế tiếp là nhỏ, bạn có thể thoát.

Điều này tương tự như cách tiếp cận được sử dụng trong tìm kiếm gốc. Nó có thể là quá mức cần thiết, vì kích thước phông chữ sẽ được chấp nhận để hiển thị trong một ứng dụng nhất định có thể khá hẹp và cách tiếp cận vũ lực bạn đang sử dụng sẽ không tốn nhiều thời gian.

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

} 

hoặc chính xác hơn nhưng tham lam

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

Divide một chinh phục:

Bạn có thể làm giảm số lượng đi trong phương pháp brute force của bạn: phép nói ưa thích của bạn (tối đa) kích thước phông chữ là 40 và bạn có kích thước phông chữ tối thiểu là 0

nếu (40 == false & & 0 == true)

  • 20 = true khả // chia làm đôi với nhau đoán
  • 30 = false
  • 25 = true
  • 27 = true
  • 28 = false
  • vì vậy 27 thắng

Bằng cách nào tốt hơn?

điều này mất 6 dự đoán thay vì 13 và thậm chí nếu 20, 12 hoặc 39 là câu trả lời đúng thì sẽ luôn mất khoảng 6 lần đoán. do đó, không chỉ có ít lần dự đoán hầu hết thời gian, nó nhất quán hơn, quan trọng đối với trải nghiệm người dùng.

tôi nghĩ rằng số lần đoán được thực hiện khi chia ints bằng một nửa mỗi lần là căn bậc hai của phạm vi bạn đang tìm kiếm cộng một. Math.sqroot (40-0) + 1 (Đó chỉ là phỏng đoán, cảm thấy tự do để sửa tôi.) kích thước phông chữ tối thiểu của bạn có lẽ không phải 0 để tăng tốc độ này sẽ giúp tìm kiếm câu trả lời nhanh hơn.

Minh họa:

Nó giống như chơi Đoán ai, cầu thủ đã hỏi "làm tên của bạn có một A" và cắt giảm các khả năng trong một nửa không có vấn đề gì bạn trả lời thường thấy câu trả lời nhanh hơn so với các cầu thủ người hỏi khoảng 1 nhân vật mỗi lượt "là tên của bạn Sam" "là tên của bạn Alex"

Alternative: bắt đầu với một đoán tốt, sau đó kiểm tra cho chính xác tôi cũng sẽ thúc đẩy làm việc trong một số logic để sử dụng kết quả được cung cấp bởi Câu trả lời của Daren bằng cách sử dụng fontMetrics như một dự đoán bắt đầu tốt và sau đó là te st nó, nếu nó phù hợp với thử nghiệm +2 nếu nó không phù hợp với thử nghiệm -2; nếu thử nghiệm mới phù hợp với kiểm tra 1 bạn bỏ qua và bạn sẽ biết câu trả lời của bạn, nếu không thử di chuyển một số khác ... v.v. sẽ tạo ra kết quả trung bình nhanh nhất của các ca sử dụng thực tế.

giả sử bạn muốn một int và giả định các số liệu phông chữ không chính xác là tối thiểu này có lẽ sẽ chỉ mất 2 hoặc 3 dự đoán.

+0

Phương pháp [Newton] (https://en.wikipedia.org/wiki/Newton%27s_method) là một cách tiếp cận tương tự, và không bị giới hạn giả tạo về tốc độ của nó hội tụ. Phân chia và conquer nhị phân chỉ xác định một bit kết quả cho mỗi lần lặp. Newton thường sẽ hội tụ nhanh hơn nhiều so với các vấn đề đơn giản như kích thước phông chữ, giả sử rằng kích thước phông chữ cho mối quan hệ chiều rộng là đơn điệu tăng, vì nó sẽ cho các phông chữ có kích thước nổi. –

1

Đây là mã của tôi phù hợp (trong heigth) một văn bản, hoạt động khá tốt (lỗi < 2% tôi đoán)

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