QT在OS X上,如何检测单击应用程序停靠图标
我有一个开放的Qt Mac应用程序。 我正在单击应用程序图标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
有没有办法在应用程序中获得此通知?这很疯狂,但我得到了,而且没有任何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);
}