为什么 Tkinter 中计算的字符串宽度和高度(以像素为单位)在不同平台上有所不同?

发布于 2024-09-03 04:50:50 字数 1689 浏览 2 评论 0原文

我有一个 Python 脚本,需要计算以任意字体显示的任意字符串的确切大小,以便生成简单的图表。我可以使用 Tkinter 轻松做到这一点。

import Tkinter as tk
import tkFont
root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=200)
canvas.pack()
(x,y) = (5,5)
text = "yellow world"
fonts = []
for (family,size) in [("times",12),("times",24)]:
    font = tkFont.Font(family=family, size=size)
    (w,h) = (font.measure(text),font.metrics("linespace"))
    print "%s %s: (%s,%s)" % (family,size,w,h)
    canvas.create_rectangle(x,y,x+w,y+h)
    canvas.create_text(x,y,text=text,font=font,anchor=tk.NW)
    fonts.append(font) # save object from garbage collecting
    y += h+5
tk.mainloop()

结果似乎取决于 Python 和/或系统的版本:

Python 2.5 Mac 0SX,乘以 12: (63,12),乘以 24:(128,24)。 Python 2.6 Mac OS X,乘以 12:(64,14),乘以 24:(127,27)。 Python 2.6 Windows XP, times 12: (78,19), times 24: (169,36) http://grab.by/grabs/d24a5035cce0d8032ea4e04cb8c85959.png

Ned Batchelder提到后,我发现大小不同平台的字体有所不同。只要您坚持使用 Tkinter,它可能不会破坏交易,因为它与自身保持一致。但我的完整程序并没有使用 Tkinter 来执行实际绘图:它只是依赖于其字体大小计算来生成输出(以 SVG 形式或作为要发送到 Nodebox 的 Python 脚本) )。事情就在那里变得非常错误:

mocodo 的输出 http://grab.by/grabs/f67b951d092dd1f4f490e1469a53bca2.png

(请查看实际尺寸的图像。请注意,使用的主要字体这些输出不是 Times,而是 Trebuchet MS。)

我现在怀疑 Tkinter 无法避免这种差异。您会推荐哪种其他跨平台解决方案?

I have a Python script which needs to calculate the exact size of arbitrary strings displayed in arbitrary fonts in order to generate simple diagrams. I can easily do it with Tkinter.

import Tkinter as tk
import tkFont
root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=200)
canvas.pack()
(x,y) = (5,5)
text = "yellow world"
fonts = []
for (family,size) in [("times",12),("times",24)]:
    font = tkFont.Font(family=family, size=size)
    (w,h) = (font.measure(text),font.metrics("linespace"))
    print "%s %s: (%s,%s)" % (family,size,w,h)
    canvas.create_rectangle(x,y,x+w,y+h)
    canvas.create_text(x,y,text=text,font=font,anchor=tk.NW)
    fonts.append(font) # save object from garbage collecting
    y += h+5
tk.mainloop()

The results seem to depend on the version of Python and/or the system:

Python 2.5 Mac 0S X, times 12: (63,12), times 24: (128,24). Python 2.6 Mac OS X, times 12: (64,14), times 24: (127,27). Python 2.6 Windows XP, times 12: (78,19), times 24: (169,36) http://grab.by/grabs/d24a5035cce0d8032ea4e04cb8c85959.png

After Ned Batchelder mentioned it, I discovered that the size of fonts differs from platform to platform. It may not be a deal breaker as long as you stick with Tkinter, which remains consistent with itself. But my complete program does not use Tkinter to perform the actual drawing: it just relies on its font size calculations to generate an output (in SVG or as a Python script to be sent to Nodebox). And it's there that things go really wrong:

Output of mocodo http://grab.by/grabs/f67b951d092dd1f4f490e1469a53bca2.png

(Please look at the image in real size. Note that the main font used for these outputs is not Times, but Trebuchet MS.)

I now suspect that such discrepancies can't be avoided with Tkinter. Which other cross-platform solution would you recommend?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

素食主义者 2024-09-10 04:50:50

你有两个问题。让我们一次一个地解决它们

1:同一平台上相同字体的 python 2.5 和 2.6 的区别

这两个版本的 python 使用不同版本的 tk。在我的 Mac 上,2.5 使用 tk 版本 8.4.19,2.6 使用 8.5.7。在 tk 8.5.2 版本中,对 tk 的字体测量功能进行了一些更改。假设这些更改是改进,我认为可以安全地假设从 python 2.6 获得的数字比从 2.5 获得的数字更准确。

2:mac上python 2.6和PC上2.6的区别。

显然,从您提供的屏幕截图来看,PC 使用更大的字体,因此您会得到更大的测量数字。问题是,为什么?您正在以磅(1/72 英寸)为单位指定字体大小。为了让 Tk(或任何渲染系统)渲染字体,它需要知道实际显示器上一英寸有多少个像素。这在不同的系统上会有所不同,并且底层操作系统并不总是为 Tk 提供准确的数字来进行计算。

从历史上看,无论实际显示如何,苹果和微软都对 72ppi 和 96ppi 进行了标准化,因此数字总是会有所不同。有关 Mac 和 Windows 计算像素密度的差异的详细信息,请参阅每英寸点数 维基百科上的文章。

您可以尝试通过以像素而不是点为单位指定字体来解决此问题。您可以通过使用负数作为字体大小来实现此目的。

最后,您可以在小示例代码中添加的一件事是打印 font.actual() 命令的结果 - 您可能会在 Windows 和 Mac 盒子之间看到一些不同的东西,这可以解释那里的差异。这会准确告诉您 Tk 使用的是哪种字体。

You have two problems. Let's tackle them one at a time

1: the difference between python 2.5 and 2.6 on the same platform with the same font

These two versions of python use different versions of tk. On my mac box, 2.5 uses tk version 8.4.19 and 2.6 uses 8.5.7. In version 8.5.2 of tk were some changes to the font measurement features of tk. Assuming that the changes were improvements, I think it's safe to assume that the numbers you get from python 2.6 are more accurate than the ones from 2.5.

2: the difference between python 2.6 on the mac and 2.6 on the PC.

Obviously, from the screenshots you include, the PC is using a larger font and thus you get larger numbers for the measurement. The question is, why? You are specifying the font size in points (1/72 of an inch). In order for Tk (or any rendering system) to render the font, it needs to know how many pixels are in an inch on the actual display. This will vary on different systems, and Tk isn't always given an accurate number by the underlying OS in order to do its calculations.

Historically, Apple and Microsoft have standardized on 72ppi and 96ppi regardless of the actual display, so the numbers are always going to be different. For more information about the differences in how the mac and windows calculate pixel density see the Dots Per Inch article on wikipedia.

You might try solving this by specifying a font in pixels rather than in points. You can do this by using negative numbers for the font size.

Finally, one thing you might add to your little example code is to print out the result of the font.actual() command -- you might see something different between your windows and mac boxes, which would explain the differences there. This tells you exactly which font is being used by Tk.

岁月蹉跎了容颜 2024-09-10 04:50:50

经过多年的搜索,我终于找到了一种方法来获取任何字体和大小的某些文本的宽度!

from tkinter import *

Window = Tk()
Window.geometry("500x500+80+80")

frame = Frame(Window) # this will hold the label
frame.pack(side = "top")

# CALCULATE:
measure = Label(frame, font = ("Purisa", 10), text = "The width of this in pixels is.....", bg = "yellow")
measure.grid(row = 0, column = 0) # put the label in
measure.update_idletasks() # this is VERY important, it makes python calculate the width
width = measure.winfo_width() # get the width

# PROOF IT WORKS:
canvas = Canvas(frame, width = 400, height = 200, bg = "light green")
canvas.grid(row = 1, column = 0, columnspan = 100) # columnspan is 100 so that the line lines up with the text
line = canvas.create_line(0, 10, width, 10, width = 4) # make a line the same length as the text
canvas.create_text(10, 20, font = ("Purisa", 10), text = "... "+str(width)+" Pixels", anchor = "nw")

我所做的行证明这适用于任何字体。

据我所知,我已经针对不同的字体和大小对其进行了测试。

这是输出的图片:
这是输出的图片

After searching for ages I finally found out a way to get the width of some text in any font and size!

from tkinter import *

Window = Tk()
Window.geometry("500x500+80+80")

frame = Frame(Window) # this will hold the label
frame.pack(side = "top")

# CALCULATE:
measure = Label(frame, font = ("Purisa", 10), text = "The width of this in pixels is.....", bg = "yellow")
measure.grid(row = 0, column = 0) # put the label in
measure.update_idletasks() # this is VERY important, it makes python calculate the width
width = measure.winfo_width() # get the width

# PROOF IT WORKS:
canvas = Canvas(frame, width = 400, height = 200, bg = "light green")
canvas.grid(row = 1, column = 0, columnspan = 100) # columnspan is 100 so that the line lines up with the text
line = canvas.create_line(0, 10, width, 10, width = 4) # make a line the same length as the text
canvas.create_text(10, 20, font = ("Purisa", 10), text = "... "+str(width)+" Pixels", anchor = "nw")

The line I make is proof that this works for any font.

I have tested this for different fonts and sizes, as far as I know it works.

This is a picture of the output:
This is a picture of the output

饮湿 2024-09-10 04:50:50

您没有做错任何事情:字体大小确实因平台而异。

我不确定为什么 Python 版本很重要,但差异只是一个像素,因此可能是不同的舍入或相同字体的不同渲染。

You haven't done anything wrong: the size of fonts does differ from platform to platform.

I'm not sure why the Python version matters, but the differences are only one pixel, so it could be different rounding or different rendering of the same font.

另类 2024-09-10 04:50:50

在 tkinter 中,如果字体大小为正数,则以磅为单位(1 磅(缩写 pt)等于 1/72 英寸)
如果字体大小以负值给出,则其单位为像素。

In tkinter if font size is positive it is in points(1 point (abbreviated pt) is equal to 1/72 of an inch)
if font size is given in negetive values it is in pixels.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文