最近在开发MacOS的qt应用,在做到最小化系统托盘功能时,发现关闭窗口后再次点击程序坞中的Dock图标不能将主界面再显示出来。查询里很多资料,发现是QT自身的问题,没有做相关的点击Dock图标的处理。
于是我参考了国内和国外的这两篇文章
国内:QT 实现Dock应用程序点击 ---Mac OS X_qt点击dock触发事件-CSDN博客
国外:https://stackoverflow.com/questions/15143369/qt-on-os-x-how-to-detect-clicking-the-app-dock-icon
使用他们的代码,编译不过,会报错
error: no matching function for call to 'objc_msgSend' note: candidate function not viable: requires 0 arguments, but 2 were provided
我的环境是qt6.7.2,在qtcreator中开发,还是会报error: no matching function for call to 'objc_msgSend'这个错误。经过一番折腾和问chatgpt,给出的结果是:
于是对代码进行改造
pro的配置不变
macx {LIBS += -framework CoreFoundationLIBS += -lobjcLIBS += -framework AppKitDEFINES += OBJC_OLD_DISPATCH_PROTOTYPES
}
代码作以下改动
#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
bool applicationShouldHandleReopen(id self,SEL _cmd,...);
#endif
void setupDockClickEvent();#ifdef Q_OS_MAC
bool applicationShouldHandleReopen(id self,SEL _cmd, ...)
{qDebug()<<__FUNCTION__;// Return NO (false) to suppress the default OS X actionsreturn false;
}
#endifvoid setupDockClickEvent()
{
#ifdef Q_OS_MACClass cls = objc_getClass("NSApplication");// 声明 objc_msgSend 的函数指针id (*objc_msgSend_id)(id, SEL) = (id(*)(id, SEL))objc_msgSend;id appInstance = objc_msgSend_id((id)cls, sel_registerName("sharedApplication"));if(appInstance != nullptr){id appDelegate = objc_msgSend_id(appInstance, sel_registerName("delegate"));Class delClass = (Class)objc_msgSend_id(appDelegate, sel_registerName("class"));SEL shouldHandle = sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:");if (class_getInstanceMethod(delClass, shouldHandle)){if (class_replaceMethod(delClass, shouldHandle, reinterpret_cast<IMP>(applicationShouldHandleReopen), "B@:"))qDebug() << "Registered dock click handler (replaced original method)";elseqWarning() << "Failed to replace method for dock click handler";}else{if (class_addMethod(delClass, shouldHandle, reinterpret_cast<IMP>(applicationShouldHandleReopen),"B@:"))qDebug() << "Registered dock click handler";elseqWarning() << "Failed to register dock click handler";}}
#endif
}
main.cpp中还是一样
int main(int argc, char *argv[])
{setupDockClickEvent();
}
至于国外论坛提到的第二种方法,本人并没有进行尝试,大家可以自行尝试一下