【问题标题】:How to prevent my app's window from going to another monitor (Electron + macOS)如何防止我的应用程序窗口转到另一台显示器(Electron + macOS)
【发布时间】:2020-07-20 09:09:33
【问题描述】:

我有一个应用程序以编程方式在用户屏幕周围移动其窗口。我的问题:

  1. 用户有两个物理监视器
  2. 用户在主监视器中启动应用程序
  3. 应用程序移动窗口,导致更多的“溢出”到辅助监视器而不是主监视器上
  4. 这会导致应用的窗口完全跳转到该辅助监视器并从主监视器中消失。

我希望窗口保留在主监视器中,除非我希望它转到辅助监视器,或者某个定义的点(例如中心)进入辅助监视器,或者如果窗口甚至可以被分割并显示在两者上。有什么办法可以防止在窗口与辅助监视器更多相交时发生这种跳跃?

重申一下,我正在以编程方式移动窗口并在 macOS 上使用 Electron。

另外,当我手动移动窗口时,这似乎不会发生,但我认为这是因为它没有使用它的百分比规则,而是继续鼠标点是否进入辅助监视器。

另外,我愿意接受任何类型的解决方案,包括 C/C++ 或 Swift。

编辑:这是我当前移动窗口的方式:

win.setPosition(x, y);

其中win 是Electron 的BrowserWindow 的一个实例。

所需的行为是将窗口移动到显示器上的任意位置。目前,如果某些窗口超出了当前显示的边缘,它会跳转到另一个显示。这是因为 Apple 的默认行为是自动将窗口移动到与其重叠最多的显示器上,并将其隐藏在所有其他显示器上。值得注意的是,这不是手动拖动窗口时的行为,而是以编程方式移动它时的行为。

【问题讨论】:

  • 您能展示如何以编程方式移动窗口的代码吗?我想这将是修复的地方。
  • 刚刚添加了代码sn-p。
  • 你使用的是什么版本的 Electron?
  • 版本为6.0.5
  • > 这是因为 Apple 的默认行为是自动将窗口移动到与其重叠最多的显示器上,并将其隐藏在所有其他显示器上。有谁知道作为用户如何以用户身份禁用此行为?

标签: c++ swift macos electron core-graphics


【解决方案1】:

我不知道你是如何移动这个窗口的,或者你希望窗口在它碰到边缘时如何动作,但我会尽力给你一些解决方案。

我的第一个想法是让您在程序启动时创建屏幕边界。 所以也许使用GetSystemMetrics()screen.getPrimaryDisplay(),或者这个伪代码可能会有所帮助:

var canvas = GetWindowSize()
var canvasWidth = canvas.width
var canvasHeight = canvas.height
if myWindow.x  + mywindow.width > canvasWidth
//if you want it to bounce off the edge
then myWindow.direction = oppositeDirection 
//if you want it to wrap to the other side of the screen
then myWindow.X -= canvasWidth

您应该查看Bouncing DVD Logo 的代码。 或者看看我的Asteroids game,看看飞船和小行星是如何在屏幕上移动的。

此外,您可以使用distance formula 让窗口在中心靠近时对边缘做出反应。 (不过,这也需要您获取屏幕边界 x 和 y。)

希望有帮助!

编辑: 我认为,如果您以某种方式使用整个屏幕,(两个显示器)您的窗口甚至都不会识别出有边缘。话虽如此,我仍然不知道您的代码实际上做了什么。

【讨论】:

  • 我不太想检测边缘。我试图能够将我的窗口移动到显示器上的任何位置。在我上传的图像中,我希望窗口能够在该场景中保持在主显示中。使用图像中的显示布局,A)我的窗口中心位于主显示器的右上角,B)窗口不跳转到辅助显示器是不可能的。这是因为 Apple 的默认行为是将一个窗口跳转到与它最相交的显示器,并将其隐藏(当以编程方式移动时)。
【解决方案2】:

由于 Mac 操作系统的行为,当您执行 win.setPosition(x, y); 时它不起作用。
(我也尝试了电子快速入门项目https://github.com/electron/electron-quick-start,即使使用相同的电子版本6.0.5)

我所做的是以编程方式模拟将您的应用程序鼠标拖动到屏幕右侧。为此,您可以使用robotjs。您不会看到拖动效果,这非常接近于执行 setPosition(x, y)
安装它时,启动应用程序时可能会遇到问题。然后你必须为你的电子版本重建 rebotJS。 https://github.com/octalmage/robotjs/wiki/Electron

所以你将尝试以编程方式做的是

工作代码

      // get your app bounds and screen bounds
      const windowBounds = mainWindow.getBounds()                         
      const displayBounds = electron.screen.getPrimaryDisplay().bounds   

      setTimeout(() => {                                                  
        // 1. move mouse upon the top left corner your app
        robot.moveMouse(windowBounds.x + 100, windowBounds.y + 5);        
        // 2. mouse left key, 'down'
        robot.mouseToggle("down", "left");                               
        // 3. drag window to (100, 100) from default 
        robot.dragMouse(displayBounds.width, 0);                         
        // 4. mouse left key toggle 'up'
        robot.mouseToggle("up", "left");                                 
      }, 100);

main.js 中的示例:https://playcode.io/electron

我使用那些版本:

  "devDependencies": {
    "electron": "^6.0.5"
  },
  "dependencies": {
    "robotjs": "^0.6.0"
  }

我的 nodejs 版本是 v10.20.0

【讨论】:

    【解决方案3】:

    也许这不是您所要求的,但这里有一个想法:为什么不调整窗口大小而不是让它“溢出”到其他屏幕?

    当您预测窗口将超出当前显示范围时,只需减小其大小。

    可以通过以下方式完成:

    const winWidth = 800;
    const winHeight = 600;
    
    const SAFETY_MARGINS = 10;
    
    let mainWindow;
    
    // setPosition //////////////////////////////////////////////////////////////////////////
    
    function setPosition(x, y) {
      const displayBounds = screen.getPrimaryDisplay().bounds
      const fixedX = Math.min(
        displayBounds.x + displayBounds.width,
        Math.max(x, displayBounds.x)
      );
      const fixedY = Math.min(
        displayBounds.y + displayBounds.height,
        Math.max(y, displayBounds.y)
      );
      mainWindow.setPosition(fixedX, fixedY);
    
      const fixedWidth = Math.max(SAFETY_MARGINS, Math.min(winWidth, displayBounds.width + displayBounds.x - x, winWidth - displayBounds.x + x));
      const fixedHeight = Math.max(SAFETY_MARGINS, Math.min(winHeight, displayBounds.height + displayBounds.y - y, winHeight - displayBounds.y + y));
      mainWindow.setSize(fixedWidth, fixedHeight);
    }
    

    此版本的setPosition 将始终调整您的窗口大小,使其不会超出显示范围。

    您可以修改/扩展它以允许窗口稍微超出范围并滚动窗口的内容(如果需要)。

    我相信,通过一些调整,对于大多数用户来说,调整窗口大小并将其稍微移出屏幕会看起来或多或少像实际将窗口移出屏幕。

    这是一个使用以下代码随机移动窗口的演示: https://github.com/yoava/so-61092503

    (我没有使用双屏进行测试,因为我现在只使用笔记本电脑。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多