对于 Qt 4.6.x,如何自动调整文本大小以适合指定的宽度?
在我的 QGraphicsRectItem::paint() 内部,我试图在其 rect() 内绘制项目的名称。然而,对于每个不同的项目,它们可以具有可变的宽度,并且类似地名称可以具有可变的长度。
目前,我从最大字体大小开始,检查它是否适合并减小它,直到找到适合的字体大小。到目前为止,我还没有找到一种快速简便的方法来做到这一点。有没有更好或更有效的方法来做到这一点?
谢谢!
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));
}
}
Inside of my QGraphicsRectItem::paint(), I am trying to draw the name of the item within its rect(). However, for each of the different items, they can be of variable width and similarly names can be of variable length.
Currently I am starting with a maximum font size, checking if it fits and decrementing it until I find a font size that fits. So far, I haven't been able to find a quick and easy way to do this. Is there a better, or more efficient way to do this?
Thanks!
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));
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
来自 qtcentre.org 的 Johannes 提供了以下解决方案:
我在我的程序中尝试了一下,到目前为止,它似乎工作得很好。我喜欢它,因为它一次性产生结果,但它假设字体宽度与其高度一样缩放。
Johannes from qtcentre.org offered the following solution:
I gave it a try in my program and so far, it seems to work quite well. I like it because it produces results in one pass, but it assumes that font width scales like its height.
http://www.qtcentre.org/threads/27839-For-Qt-4-6-x-how-to-auto-size-text-to-fit-in-a-specified-width
您可以将 QGraphicsTextItem 作为矩形项目的子项,测量文本项目的宽度,然后缩放文本项目 (setTransform()) 以适合矩形项目的宽度(和高度)。
You could have a QGraphicsTextItem as a child of the rect item, measure the text item's width and then scale the text item (setTransform()) to fit into the rect item's width (and height).
这是我的代码,适合(高度)文本,效果很好(我猜错误 <2%)
Here is my code the fit (in heigth) a text, works quite well (error < 2% I guess)
或更准确但贪婪
or more accurate but greedy
划分征服:
您可以减少暴力方法中的传递次数:
假设您的首选(最大)字体大小为 40,最小字体大小为 0
if(40 == false && 0 == true)
在哪些方面更好?
这需要 6 次猜测,而不是 13 次,即使 20、12 或 39 是正确答案,它也总是正确的进行大约 6 次猜测。因此,大多数情况下,它不仅减少了猜测,而且更加一致,这对于用户体验很重要。
我认为每次将整数除以一半所需的猜测次数是您正在查找的范围的平方根加一。 Math.sqroot(40-0) + 1 (这只是一个猜测,请随时纠正我。)
您的最小字体大小可能不是 0,因此增加此值会加快搜索答案的速度。
说明:
就像玩猜猜是谁一样,询问“你的名字有 A 吗”的玩家无论你回答什么,都会将可能性减半,通常比询问 1 个角色的玩家更快找到答案每个回合“你的名字是萨姆”“你的名字是亚历克斯”
替代方案:从一个好的猜测开始,然后测试准确性
我还会促进在某些逻辑中的工作,以使用 Daren 的答案提供的结果,使用 fontMetrics 作为一个好的开始猜测,然后测试它,如果它适合测试 +2,如果它不适合测试 -2;如果新测试适合测试您跳过的 1,您就会知道答案,如果不尝试移动另一个 2 等等,但理想情况下,fontMetrics 答案不超过 4...
我怀疑这会产生最快的结果实际用例的平均结果。
假设您想要一个 int 并假设字体指标的误差很小,这可能只需要 2 或 3 次猜测。
Divide an conquer:
You could reduce the number of passes in your brute force method:
lets say your preferred (maximum) font size is 40 and you have a minimum font size of 0
if(40 == false && 0 == true)
In what ways is this better?
this took 6 guesses instead of 13, and even if 20, 12, or 39 were the right answer it would always take about 6 guesses. so not only is it fewer guesses most of the time, it's more consistent which is important for user experience.
i think the number of guess it takes when dividing ints by half each time is the square root of the range you are looking in plus one. Math.sqroot(40-0) + 1 (That's just a guess, feel free to correct me.)
your minimum font size is probably not 0 so increasing this would speed up the search for an answer.
Illustration:
It's like playing Guess Who, players who ask "does your name have an A" and cuts the possibilities in half no matter what you answer typically finds the answer faster than the player who asks about 1 character each turn "is your name Sam" "is your name Alex"
Alternative: starting with a good guess, then testing for accuracy
I would also promote working in some logic to use the result provided by Daren's answer using fontMetrics as a good starting guess and then test it, if it fits test +2 if it doesn't fit test -2; if the new test fits test the 1 you skipped and you will know your answer, if not try moving another 2 and so on, but ideally the fontMetrics answer isn't more than 4 far off...
I suspect this will produce the fastest average results of actual use cases.
assuming you want an int and assuming the font metrics inaccuracies are minimal this will probably only take 2 or 3 guesses.
根据答案关注函数并对答案 允许优化字体大小以适合指定矩形中的文本:
Follow function based on the answer and comment to the answer allow optimizing font size to fit text in specified rectangle:
不幸的是,没有。对此没有简单的解决方案。从性能角度来看,最明显的改进是在文本更改时计算并缓存所需的字体大小,而不是在每个 PaintEvent 中重新计算。另一个改进是尝试根据边界矩形的比例来估计正确的大小。进行和测试估计应该可以让您比每次迭代将点大小简单地减少 1 更快地纠正大小。
Unfortunately, no. There's no easy solution to this. The most obvious improvement, performance-wise would be calculate and cache the needed font size when the text is changed instead of recalculating it in each paintEvent. Another improvement would be to try to estimate the correct size based on the proportions of the bounding rect. Making and testing estimates should get you to correct size much quicker than simply decrementing the point size by one each iteration.
这取决于您期望字体大小变化的范围。如果范围很大,加一可能需要很长时间。如果只是几个点大小的问题,速度可能不会成为问题。
如果范围很大,另一种方法是添加更大的间隔,而不是“1”。如果您在一个步骤中超出了所需的大小,请将间隔减少一半。每次你都会在最佳尺寸上来回弹跳,幅度越来越小;当连续两次间隔的差别很小时,就可以退出。
这类似于寻根中使用的方法。这可能有点矫枉过正,因为在给定应用程序中可以接受的显示字体大小可能相当窄,并且您已经使用的强力方法不会消耗太多时间。
This depends on the range over which you expect your font sizes to vary. If the range is large, incrementing by one may take a long time. If it's just a matter of several point sizes, speed probably won't be an issue.
If the range is large, another approach would be to add a larger interval, instead of '1'. If you exceed the desired size during one step, decrease the interval by, say, half. You'll bounce back and forth across the optimum size by smaller and smaller amounts each time; when the difference between two successive intervals is small, you can quit.
This is similar to the approach used in root finding. It may be overkill, since the size of fonts that will be acceptable to display in a given application is likely to be fairly narrow, and the brute force approach you're already using won't consume much time.