【问题标题】:QWidget on Mac OS X not focusing in Qt 5.xMac OS X 上的 QWidget 不专注于 Qt 5.x
【发布时间】:2013-06-28 12:25:14
【问题描述】:

我有带有 QAction 的 QSystemTrayIcon,可以打开 QWebView 类型的新窗口。当窗口失去焦点并且我再次选择 QAction 时,窗口应该重新获得焦点。它在 Linux 上可以,但在 Mac OS X 上不行。问题是,当我打开另一个窗口并处于活动状态时,比如说 Google Chrome,当我在我试图打开的窗口上调用 show() 时,它总是在谷歌浏览器下打开,所以我看不到它。聚焦也是如此,当我打开多个窗口时,我的 QWebView 可能是顺序中的最后一个,当我单击 QAction 聚焦窗口时,它将始终位于 Google Chrome 窗口下。我的猜测是,当我单击 QAction(这是我的应用程序进程的一部分)时,它会尝试打开/聚焦窗口,但在操作过程中,Google Chrome 窗口会被安排并获得焦点,因为 QSystemTrayIcon无法保持焦点。因此,当窗口打开/获得焦点时,它不会从谷歌浏览器中窃取焦点,因为操作系统不允许这样做,所以它将被放置在当前焦点窗口下。

这里我如何创建/聚焦窗口:

// ...
QPointer<QWebView> view;
// ...

void TrayIcon::webView() {
  if (!this->view) {
    this->view = new QWebView();
    this->view->load("http://example.com");
    this->view->show();
  } else {
    this->view->activateWindow();
    this->view->raise();
  }
}

是我做错了什么还是有任何已知的解决方法?

【问题讨论】:

    标签: c++ macos qt qt5 qwidget


    【解决方案1】:

    所以我设法解决了依赖于平台的代码的问题。我使用 .mm 文件中的代码创建了 Focuser 类,其中包含称为 Cocoa 的 Objective-C 代码。

    focuser.h

    #ifndef FOCUSER_H
    #define FOCUSER_H
    
    #include <QWidget>
    
    class Focuser {
      QWidget *widget;
    public:
      Focuser(QWidget *);
      void show();
      void focus();
    };
    
    #endif // FOCUSER_H
    

    focuser_mac.mm

    #include "focuser.h"
    #import <Cocoa/Cocoa.h>
    
    Focuser::Focuser(QWidget *w) {
      this->widget = w;
    }
    
    void Focuser::show() {
      this->widget->show();
      this->focus();
    }
    
    void Focuser::focus() {
      [NSApp activateIgnoringOtherApps:YES];
      this->widget->activateWindow();
      this->widget->raise();
    }
    

    focuser.cpp

    #include "focuser.h"
    
    Focuser::Focuser(QWidget *w) {
      this->widget = w;
    }
    
    void Focuser::show() {
      this->widget->show();
      this->focus();
    }
    
    void Focuser::focus() {
      this->widget->activateWindow();
      this->widget->raise();
    }
    

    所以我们有一个类在构造函数中使用 QWidget 并有两个公共方法,一个显示小部件和聚焦小部件的焦点。然后我们有两个类的定义,一个在 focuser_mac.mm 中用于 Mac OS X,另一个在 focuser.cpp 中用于任何其他操作系统。 mac版另外调用

    [NSApp activateIgnoringOtherApps:YES];
    

    现在,为了让它能够编译,它应该将它添加到您的 .pro 文件中:

    HEADERS += focuser.h
    
    mac {
      OBJECTIVE_SOURCES += focuser_mac.mm
    }
    
    linux|win32 {
      SOURCES += focuser.cpp
    }
    

    当我们完成后,只需将此代码添加到您需要关注您的应用程序的位置:

    QWidget *w = new QWidget();
    // ...
    Focuser f(w);
    w.show(); // The widget will now be shown and focused by default.
    

    【讨论】:

      【解决方案2】:

      有点离题,但可能对某些用户有用:

      我的建议是创建依赖于平台的代码来强制提升窗口。在 Windows 平台上也有同样的问题,所以我正在使用下一个 hack:

          void Utils::forceForegroundWindow( WId winId )
          {
      #ifdef Q_OS_WIN
              HWND hWnd = winId;
      
              if ( ::IsWindow( hWnd ) )
              {
                  HWND hCurrWnd;
                  int iMyTID;
                  int iCurrTID;
      
                  hCurrWnd = ::GetForegroundWindow();
                  iMyTID   = ::GetCurrentThreadId();
                  iCurrTID = ::GetWindowThreadProcessId( hCurrWnd, 0 );
      
                  ::AttachThreadInput( iMyTID, iCurrTID, TRUE );
      
                  ::ShowWindow( hWnd, SW_SHOWNORMAL );
                  ::SetForegroundWindow( hWnd );
      
                  ::AttachThreadInput( iMyTID, iCurrTID, FALSE );
              }
      
      #endif
          }
      

      我仍然没有在我的项目中提供 Mac OS 兼容性,所以这段代码对非 win 平台没有功能。

      另一个想法:你应该始终保持焦点可见的窗口。尝试使用 WA_TranslucentBackground | 做一个WA_TransparentForMouseEvents 属性 + FramelessWindowHint 标志。所以你的应用程序永远不会失去焦点。

      【讨论】:

        猜你喜欢
        • 2013-07-20
        • 1970-01-01
        • 2016-03-04
        • 1970-01-01
        • 2013-11-05
        • 1970-01-01
        • 2013-09-09
        • 1970-01-01
        • 2012-02-08
        相关资源
        最近更新 更多