如何在多显示器设置中让无边框子窗口重新缩放到当前屏幕? [英] How can I get a borderless child window to re-scale to current screen in multi-monitor setup?

查看:41
本文介绍了如何在多显示器设置中让无边框子窗口重新缩放到当前屏幕?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用有一个主窗口,它使用 createObject() 创建并打开 QML Window {} 的子类实例.此窗口的 flags: 设置为无边框窗口(我已添加代码以便可以抓取和拖动它).

My app has a main window which creates and opens an instance of a subclass of a QML Window {} using createObject(). This window has its flags: set to be a borderless window (I've added code so that it can be grabbed and dragged around).

当我将显示器连接到笔记本电脑并将其字体比例因子设置为 125%(或 150%)时,当我将主窗口拖到第二台显示器时,您会看到它突然对齐"到更大的尺寸当它到达中点时.同样,当我将它拖回我的笔记本电脑屏幕时,它会在我走到一半时再次捕捉"到较小的尺寸(这种行为正是我想要的,所以这里没有问题).

When I attach a monitor to my laptop and set its font scale factor to 125% (or 150%), when I drag my main window over to the second monitor, you can see it suddenly "snap" to the larger size when it reaches the halfway point. Likewise, when I drag it back to my laptop screen it again "snaps" to the smaller size when I get halfway over (this behavior is what I want, so no problems here).

我的问题是,当我将创建的无边框窗口拖到显示器上时,它会保持原来的 100% 比例因子并且不会对齐"到更大的尺寸.如果我将主窗口拖到显示器上,它会变大,但无边框窗口仍保持较小的比例;只有当我抓住无边框窗口并稍微移动它时,它才会突然捕捉"到更大的尺寸.同样的事情反过来发生 - 如果我然后将无边框窗口拖回到笔记本电脑上,它会保持较大的尺寸,直到我将主窗口拖回来然后稍微移动无边框窗口(此时它突然捕捉"到较小的尺寸).

My problem is that when I drag my created borderless window over into the monitor, it keeps the original 100% scale factor and does not "snap" to a larger size. If I drag my main window over to the monitor, it gets larger but the borderless window remains at the smaller scale; only when I grab the borderless window and move it slightly does it suddenly "snap" to the larger scale size. The same thing happens in reverse - if I then drag the borderless window back onto the laptop, it remains at the larger size until I drag the main window back over and then move the borderless window slightly (at which point it suddenly "snaps" to the smaller size).

所以看起来这个创建的 Window 使用了创建它的 parent window 窗口当前所在屏幕的比例因子,即使它在不同的屏幕本身.

So it appears that this created Window uses the scale factor of the screen that the parent window window that created it is currently in, even if it is in a different screen itself.

这是因为 Window 是无边框的吗?(我即将测试这个,但我的构建过程非常慢)或者有什么方法可以设置这个无边框 Window 以便它检测到它正在进入一个新屏幕并重新缩放本身(和我的主窗口一样)?

Is this happening because the Window is borderless? (I'm about to test this but my build process is incredibly slow) Or is there any way to set this borderless Window up so that it detects that it is crossing into a new screen and re-scales itself (in the same way that my main window does)?

更新:我刚刚运行了一个测试,给我的 Window 一个原生标题栏,并且带有标题栏的窗口立即采用(捕捉到")任何一个的比例因子它恰好在屏幕上,就像我的主窗口一样(并且与主窗口的比例因子无关).

Update: I just ran a test giving my Window a native titlebar, and with a titlebar the window instantly adopts ("snaps to") the scale factor of whichever screen it happens to be in, just like my main window (and independent of the main window's scale factor).

那么有没有办法用无边框窗口复制这种自动缩放的窗口行为?我需要调用一些标志,或者我需要调用一些方法来让操作系统重新缩放窗口?

So is there any way to duplicate this auto-scaling window behavior with a borderless window? Some flag I need to call, or some method(s) I need to call to get the OS to rescale the window?

更新 2: 我尝试了 Felix 的 SetWindowPos 解决方案.它确实移动了窗口,但这并没有解决缩放问题 - 无框窗口的行为是相同的,它仍然没有正确地选择它所在屏幕的缩放因子.

Update 2: I tried out Felix's SetWindowPos solution. It does move the window, but this does not fix the scaling problem - the behavior of the frameless window is the same and it still does not correctly pick up the scaling factor of the screen it is in.

我正在使用 MoveWindow 而不是 SetWindowPos 运行测试,以查看是否会影响任何内容 [edit: MoveWindow> 也不起作用 - 同样的问题].然后我将尝试 SendMessagePostMessage 以及 NoBugz 对 WM_DPICHANGED 消息的建议.

I am running a test using MoveWindow instead of SetWindowPos to see if that affects anything [edit: MoveWindow does not work, either - same problem]. Then I'm going to try SendMessage or PostMessage along with NoBugz' suggestion of the WM_DPICHANGED message.

欢迎提出任何其他建议.

Any other suggestions are welcome.

更新 3: 我刚刚创建了一个快速的 C# 应用程序(winforms)来查看是否会出现同样的问题,但它没有 - 当 C# 应用程序中的无边框表单被拖过时进入另一个监视器,它会立即获取比例因子的变化.所以看起来这是一个 Qt 问题.

Update 3: I just created a quick C# app (winforms) to see if the same problem occurs with that, and it doesn't - when a borderless form in the C# app is dragged over into the other monitor, it immediately picks up the scale factor change. So it appears this is a Qt problem.

更新 4:有关此问题的有效解决方案,请参阅下面我的回答(如果有点麻烦).

Update 4: See my answer below for a working solution to this problem (if a bit of a hack).

推荐答案

我想出了一个相对简单的方法来解决这个问题.由于 Qt 中的无框窗口从创建它的窗口获取其缩放因子,所以诀窍是创建另一个窗口(具有标题栏但对用户不可见)并在那里创建无框窗口,然后将代码添加到无框窗口以在用户拖动时将隐藏窗口保持在其下方.当无框窗口被拖入另一个屏幕时,隐藏窗口会随之而来,选择新的比例因子(因为它有一个标题栏),然后无框窗口也会立即获得新屏幕的比例因子.

I figured out a relatively simple way to fix this problem. Since a frameless window in Qt gets its scaling factor from the window that created it, the trick is to create another window (that has a titlebar but is not visible to the user) and create the frameless window there, and then add code to the frameless window to keep the hidden window positioned underneath it as the user drags it. When the frameless window is dragged into another screen, the hidden window goes with it, picks up the new scale factor (since it has a titlebar) and then the frameless window immediately gets the new screen's scale factor as well.

这是示例解决方案代码:

Here is sample solution code:

// HiddenWindow.qml
Window {
    id: hiddenWindow

    // note: just making window visible: false does not work. 
    opacity: 0
    visible: true
    flags: Qt.Tool | Qt.WindowTitleHint | Qt.WindowTransparentForInput | 
           Qt.WindowStaysOnTopHint // Qt.Tool keeps this window out of the 
                 // taskbar

    function createVisibleWindow() {
        var component = Qt.createComponent("VisibleWindow.qml")
        if (component.status === Component.Ready) {
            var win = component.createObject(hiddenWindow)
            return win
        }
    }
}

// VisibleWindow.qml
Window {
    id: visibleWindow
    property var creatorWindow: undefined

    flags: Qt.FramelessWindowHint

    onXChanged: {
        creatorWindow.x = x
    }
    onYChanged: {
        creatorWindow.y = y
    }
    onWidthChanged: {
        creatorWindow.width = width
    }
    onHeightChanged: {
        creatorWindow.height = height
    }
}

然后从您的主窗口 QML 中使用这些类:

And then to use these classes from your main window QML:

property var hiddenWindow: undefined
property var visibleWindow: undefined

Component.onCompleted: {

    var component = Qt.createComponent("HiddenWindow.qml")
    if (component.status === Component.Ready) {
        hiddenWindow = component.createObject(null)
    }
    visibleWindow = hiddenWindow.createVisibleWindow()
    visibleWindow.creatorWindow = hiddenWindow

    visibleWindow.show()

}

这篇关于如何在多显示器设置中让无边框子窗口重新缩放到当前屏幕?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆