Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
QT在OS X上,如何检测单击应用程序停靠图标_Qt - Fatal编程技术网

QT在OS X上,如何检测单击应用程序停靠图标

QT在OS X上,如何检测单击应用程序停靠图标,qt,Qt,我有一个开放的Qt Mac应用程序。 我正在单击应用程序图标 有没有办法在应用程序中获得此通知?这很疯狂,但我得到了,而且没有任何Objective-C编码: 我导出了QApplication。在派生类的*.cpp部分,我将: #ifdef Q_OS_MAC #include <objc/objc.h> #include <objc/message.h> bool dockClickHandler(id self,SEL _cmd,...) { Q_UNUSE

我有一个开放的Qt Mac应用程序。 我正在单击应用程序图标


有没有办法在应用程序中获得此通知?

这很疯狂,但我得到了,而且没有任何Objective-C编码:

我导出了QApplication。在派生类的*.cpp部分,我将:

#ifdef Q_OS_MAC

#include <objc/objc.h>
#include <objc/message.h>

bool dockClickHandler(id self,SEL _cmd,...)
{
    Q_UNUSED(self)
    Q_UNUSED(_cmd)
   ((MyApplictionClass*)qApp)->onClickOnDock();
     return true;
}

#endif
将这个简单的方法添加到我的应用程序类中(注意,它是从我答案顶部的处理程序中引用的)


工作起来很有魅力

由于弃用警告(post OS X 10.5)和类型错误,我无法获得正确编译的原始答案;我更改了一些类型名并将其编译,但代码仍然不起作用

事实证明,较新版本的Qt(4.8.7+,包括5.x;我使用5.4.1)实现了我们想要添加的方法,如果该方法已经存在,
class\u addMethod
将失败。请参阅。
注意:上面的bug报告包含一个稍微不同的解决方案(我是在自己解决问题后发现的)

一个对我有效的解决方案是检查该方法是否存在。如果有,我们就更换它。如果没有,我们只需添加它。
我没有在较旧的Qt版本上测试过这段代码,但它使用OPs逻辑,所以应该可以工作

这是我的密码。与OPs一样,所有代码都在QApplication子类的.cpp文件中

#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
void setupDockClickHandler();
bool dockClickHandler(id self,SEL _cmd,...);
#endif
最后,在同一个文件中的某个地方(在我的例子中,在底部):

当然,如果您手工编译,这些标志当然是应该添加到C++或CLAN+++命令行中的。


这就是所需的一切。

从Qt5.4.0开始,您可以处理QEvent,它与单击dock:QEvent::ApplicationActivate相关


QEvent::ApplicationActivate的问题在于每次激活时都会发出它-例如,即使您切换到应用程序切换器上的应用程序。本机行为是仅在停靠图标单击时显示应用程序,而不是在按cmd+tab切换时显示

但是,至少Qt5.9.1中有一种破解方法是有效的。Dock图标单击会产生两个连续的QEvent::ApplicationStateChangeEvent事件,同时cmd+tab-仅一个。 因此,该代码将非常准确地发出停靠点击信号。App类是从QApplication继承的应用程序类,也是其自身的事件筛选器

bool App::eventFilter(QObject* watched, QEvent* event)
{
#ifdef Q_OS_MACOS
    if (watched == this && event->type() == QEvent::ApplicationStateChange) {
        auto ev = static_cast<QApplicationStateChangeEvent*>(event);
        if (_prevAppState == Qt::ApplicationActive
                && ev->applicationState() == Qt::ApplicationActive) {
            emit clickedOnDock();
        }
        _prevAppState = ev->applicationState();
    }
#endif // Q_OS_MACOS
    return QApplication::eventFilter(watched, event);
}
bool应用程序::事件过滤器(QObject*监视,QEvent*事件)
{
#ifdef Q_OS_MACOS
if(wasted==this&&event->type()==QEvent::ApplicationStateChange){
自动ev=静态施法(事件);
如果(_prevAppState==Qt::ApplicationActive
&&ev->applicationState()==Qt::ApplicationActive){
发出ClickedDock();
}
_prevAppState=ev->applicationState();
}
#endif//Q_OS_MACOS
返回QApplication::eventFilter(监视的,事件);
}

谢谢您!显然,这段代码在Qt4.8.7中停止工作,但我设法使它工作(在Qt5.4.1上),所以我发布了一个更新版本的答案。谢谢Jason!是的,在Cpp中,调用msgSend似乎是与Objective-C能力交互的唯一方式。非常感谢你的工作!这是一个很好的答案,但是,顺便说一句,我认为没有必要避免使用objective C。qmake处理它,当从
.mm
文件中包含Qt头时,它是有效的。这可以简单地用obj-C++在
.mm
文件中编写,并且在不显式调用objc运行时的情况下可读性会更好。mac上的Qt项目可以包含.m和.mm文件,您可以从.mm文件中使用Qt。错误:没有匹配的函数用于调用“objc_msgSend”注意:候选函数不可行:需要0个参数,但提供了2个参数
#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
void setupDockClickHandler();
bool dockClickHandler(id self,SEL _cmd,...);
#endif
#ifdef Q_OS_MAC
    setupDockClickHandler();
#endif
#ifdef Q_OS_MAC
void setupDockClickHandler() {
    Class cls = objc_getClass("NSApplication");
    objc_object *appInst = objc_msgSend((objc_object*)cls, sel_registerName("sharedApplication"));

    if(appInst != NULL) {
        objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
        Class delClass = (Class)objc_msgSend(delegate,  sel_registerName("class"));
        SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");
        if (class_getInstanceMethod(delClass, shouldHandle)) {
            if (class_replaceMethod(delClass, shouldHandle, (IMP)dockClickHandler, "B@:"))
                qDebug() << "Registered dock click handler (replaced original method)";
            else
                qWarning() << "Failed to replace method for dock click handler";
        }
        else {
            if (class_addMethod(delClass, shouldHandle, (IMP)dockClickHandler,"B@:"))
                qDebug() << "Registered dock click handler";
            else
                qWarning() << "Failed to register dock click handler";
        }
    }
}

bool dockClickHandler(id self,SEL _cmd,...) {
    Q_UNUSED(self)
    Q_UNUSED(_cmd)
    // Do something fun here!
    qDebug() << "Dock icon clicked!";

    // Return NO (false) to suppress the default OS X actions
    return false;
}
#endif
LIBS += -framework CoreFoundation -framework Carbon -lobjc
bool App::eventFilter(QObject* watched, QEvent* event)
{
#ifdef Q_OS_MACOS
    if (watched == this && event->type() == QEvent::ApplicationStateChange) {
        auto ev = static_cast<QApplicationStateChangeEvent*>(event);
        if (_prevAppState == Qt::ApplicationActive
                && ev->applicationState() == Qt::ApplicationActive) {
            emit clickedOnDock();
        }
        _prevAppState = ev->applicationState();
    }
#endif // Q_OS_MACOS
    return QApplication::eventFilter(watched, event);
}