当我在 Spyder 中运行它以及直接在终端中运行它时,HIGH DPI Tkinter 重新缩放

Posted

技术标签:

【中文标题】当我在 Spyder 中运行它以及直接在终端中运行它时,HIGH DPI Tkinter 重新缩放【英文标题】:HIGH DPI Tkinter re scaling when I run it in Spyder and when I run it direct in terminal 【发布时间】:2020-10-28 20:55:56 【问题描述】:

这可能不是一个编码问题。

我在 Tkinter 中开发了一个应用程序,它几乎包含在我加载图像的画布(matplots)中。

当我从 Spyder 或 Jupyter 笔记本运行时,我获得 143 DPI,而当我直接在终端中运行时,我获得 95 DPI。

最奇怪的是,一旦我从终端运行它,它就显示为 143 DPI 应用程序,但是当我加载图像时,应用程序决定完全调整大小,然后更改我屏幕的 DPI。所以整个事情都会调整大小,按钮,弹出框等等......

我可以从终端运行它对我来说非常重要,因为之后我会将它转换为 .exe 应用程序。

我的第一个方法是使用 tkinter 方法 .winfo_fpixel() 并尝试对 DPI 进行比率化并将其与应用程序中的每个维度相乘。

后来我试图找到python.exe和pythonw.exe以改变与HIGH DPI Scale的兼容性。

你觉得有没有办法在不调整所有大小的情况下解决这个问题?

我想坚持我 100% 确定这与代码无关,因此我可能不会发布任何编码示例。

谢谢。

obs:我使用的是 Windows 10 ps:我尝试用两个屏幕运行应用程序,发生的事情真的很有趣,当我在足够的屏幕上使用它时它运行正常,但是当我将它滑动到另一个屏幕并进行任何操作/事件时,它会自动调整它的大小.

【问题讨论】:

【参考方案1】:

DPI 很大程度上受 PC 分辨率设置的影响,尤其是“缩放和布局”设置。 100% 是 96 DPI,150% 是 144 DPI。我猜这只是您的应用程序显示 95 和 143 的舍入错误。笔记本电脑往往具有更高分辨率的屏幕,因此 OEM 的默认设置为 >100%,这样您就不必眯着眼睛查看您的应用程序。而您的典型 1080p 显示器默认为 100% DPI。但是当您将“远程桌面”“远程”到 PC 中时,如果其 DPI 和分辨率不同,Windows 可能会重新调整和重新拉伸 DPI 设置以匹配本地显示。

Windows 将自动缩放大多数尚未在操作系统中明确设置其“DPI 感知”的应用程序。这对于大多数应用程序来说通常都很好(尽管它们可能看起来“模糊”)。应用程序可以编译为 dpi 感知,除非在某些多显示器情况下,否则不会拉伸。这尤其适用于图形应用程序。这就是您所看到的错误往往会出现的地方。您通常可以通过右键单击 EXE、单击属性并找到设置兼容性选项卡来更改此行为:

最奇怪的是,一旦我从终端运行它,它就显示为 143 DPI 应用程序,但是当我加载图像时,应用程序决定完全调整大小,然后更改我屏幕的 DPI。所以整个事情都会调整大小,按钮,弹出框等等......

当您远程访问您的 PC 时,系统 DPI 发生了变化。应用程序可能会感到困惑——尤其是当它们不适应不断变化的 DPI 设置时。或者更糟糕的是,应用程序向 Windows 注册它可以识别 DPI,但不处理显示器被换出的极端情况——这实际上是当你远程进入它时发生的情况。但是,您可以通过上面的“属性”对话框和可用 API 的某种组合来覆盖此行为以控制 dpi 感知。

我不太了解 TKinter(它是使用 Python 进程还是它自己的 exe?)。如果您可以自己编译,则可以使用各种 Windows API 和清单设置来获得您想要的 DPI 行为。我在黑暗中猜测是 TKinter( 声明自己是每个监视器 dpi 感知的,但有一个错误不能解释 DPI 动态变化。这种情况的典型解决方法是重新启动应用程序

您需要在以下链接中了解的所有信息:

https://docs.microsoft.com/en-us/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows

https://docs.microsoft.com/en-us/windows/desktop/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness

https://msdn.microsoft.com/en-us/C9488338-D863-45DF-B5CB-7ED9B869A5E2

您还可以阅读我之前关于 Windows 应用程序中 DPI 意识的回答:

https://***.com/search?q=user%3A104458+dpi

【讨论】:

我想这就是我一直在寻找的东西,我会在今天和明天尝试并给你一些反馈。无论如何,谢谢你的努力! 它在大部分情况下都有效,在代码中进行了一些调整(与图形大小不匹配),我愿意使用 py-to-exe 将这个应用程序转换为可执行文件。问题是,我可能必须将我安装的每台笔记本电脑的比例从 150% 更改为 100%。您对此有何意见/建议?再次感谢你!!! 在我们的应用程序中,很早在 WinMain 进程启动时,我们为系统感知 DPI 配置了进程,可以调用 GevDeviceCaps(LOGPIXELSX) 然后除以 96 以获得“比例因子”。所有后续的窗口创建、字体大小和这些窗口中的元素都被调整大小以匹配我们之前计算的比例。所以它“正常工作”并且在 99% 的情况下看起来都不错。当显示器交换发生时,由于插入投影仪或“远程桌面”插入其中,Windows 会很高兴地重新调整我们的比例,而进程不会意识到这是一个 dpi 更改。 这就是我喜欢system-aware DPI的原因,它基本上意味着你只需要注意进程启动时的DPI设置,但不必担心它以后会改变。每个显示器的 dpi 意识要困难得多。我不确定 Python 和 Tkinter 设置了什么(如果有的话),但是像 Qt 这样的一些框架默认为每个监视器。我们覆盖它。最后一点 - Windows 10 的最新更新显着改进了应用行为,以监控和 dpi 变化。 太好了,我可能会在 Qt 中为下一个版本重新创建应用程序。我真的很高兴你帮了我!【参考方案2】:

selbie 的回答是正确的。

另外,您可以使用winapi 直接在python 中设置DPI 感知(这可以在tkinter 中使用):

import ctypes, tkinter
try: # >= win 8.1
    ctypes.windll.shcore.SetProcessDpiAwareness(2)
except: # win 8.0 or less
    ctypes.windll.user32.SetProcessDPIAware()

root = tkinter.Tk()
....

MSDN doc: SetProcessDpiAwareness, MSDN doc: SetProcessDPIAware

这是another answer,它提到了 DPI 意识。

【讨论】:

它工作得很好,现在我不必更改我安装它的每台计算机的配置!非常感谢!!! 你能解释一下为什么论点 2 吗?我在文档中找不到。谢谢 @LucasTonon 您可以在此页面中使用check it。2 表示"Per monitor DPI aware. This app checks for the DPI when it is created and adjusts the scale factor whenever the DPI changes. These applications are not automatically scaled by the system." 现在的问题如下:如果我在插入第二个屏幕的情况下启动笔记本电脑,它就可以正常工作。但是如果我只启动我的笔记本电脑,它会适应笔记本电脑并变形,即使我插入第二个屏幕,它也会继续这样,直到我完全重新启动我的电脑。 @LucasTonon 我曾经用 pyinstaller 打包它们。它在很多设备上都可以正常工作。

以上是关于当我在 Spyder 中运行它以及直接在终端中运行它时,HIGH DPI Tkinter 重新缩放的主要内容,如果未能解决你的问题,请参考以下文章

为啥我在终端上安装的软件包不能在 Spyder 上运行

尽管安装了 Spyder-Terminal,但 Spyder 5 中没有终端

我无法在 pycharm 和 spyder 上运行 streamlit。我在窗口上运行最新的 python 版本。当我尝试代码时,它说语法无效

Spyder 控制台显示带有运行文件的文件路径

如果我有 Anaconda,如何通过双击运行 .py 文件?

请问我在spyder上可以直接运行程序,为啥保存为python程序后一运行就自动弹出