Ho un'app Qt Mac aperta. Sto facendo clic sull'icona IconaQT su OS X, come rilevare facendo clic sull'app Icona Dock
C'è un modo per ottenere una notifica per questo nell'app?
Ho un'app Qt Mac aperta. Sto facendo clic sull'icona IconaQT su OS X, come rilevare facendo clic sull'app Icona Dock
C'è un modo per ottenere una notifica per questo nell'app?
E 'pazzesco, ma ho preso, e senza alcuna codifica Objective-C:
ho derivato QApplication. Nel * parte cpp della mia classe derivata ho messo:
#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
nel mio costruttore della classe di applicazione derivata ho messo:
#ifdef Q_OS_MAC
objc_object* cls = objc_getClass("NSApplication");
SEL sharedApplication = sel_registerName("sharedApplication");
objc_object* appInst = objc_msgSend(cls,sharedApplication);
if(appInst != NULL)
{
objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
objc_object* delClass = objc_msgSend(delegate, sel_registerName("class"));
const char* tst = class_getName(delClass->isa);
bool test = class_addMethod((objc_class*)delClass, sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"), (IMP)dockClickHandler,"[email protected]:");
if (!test)
{
// failed to register handler...
}
}
#endif
Aggiunto questo semplice metodo per la mia classe di applicazione (nota è indicato da il gestore in cima alla mia risposta)
void MyApplictionClass::onClickOnDock()
{
// do something...
}
Funziona come il fascino.
Non ho potuto ottenere la risposta originale per compilare correttamente a causa di avvertimenti di deprecazione (post-OS X 10.5) e errori di tipo; Ho cambiato alcuni nomi di tipo e l'ho compilato, ma il codice non funzionava ancora.
Si scopre che le versioni più recenti di Qt (4.8.7+, incluso 5.x; io uso 5.4.1) implementano il metodo che si desidera aggiungere e class_addMethod
non riesce se il metodo esiste già. Vedi this QTBUG.
Nota: il rapporto bug sopra riportato contiene una soluzione leggermente diversa (l'ho trovata dopo aver risolto il problema personalmente).
Una soluzione, che funziona per me, consiste nel verificare se il metodo esiste. Se lo fa, lo sostituiamo. In caso contrario, semplicemente lo aggiungiamo.
Non ho testato questo codice su versioni precedenti di Qt, ma utilizza la logica OP, quindi dovrebbe funzionare.
Ecco il mio codice. Come nel caso degli OP, tutto il codice si trova nel file .cpp di una sottoclasse QApplication.
#ifdef Q_OS_MAC
#include <objc/objc.h>
#include <objc/message.h>
void setupDockClickHandler();
bool dockClickHandler(id self,SEL _cmd,...);
#endif
mio costruttore QApplication sottoclasse contiene
#ifdef Q_OS_MAC
setupDockClickHandler();
#endif
E, infine, da qualche parte nello stesso file (in fondo, nel mio caso):
#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, "[email protected]:"))
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,"[email protected]:"))
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
vedere anche il Apple documentation on the applicationShouldHandleReopen:hasVisibleWindows: method.
Per poter essere compilato, è inoltre necessario creare un collegamento con alcuni framework aggiuntivi.
Utilizzando qmake, ho aggiunto il seguente al mio file .pro:
LIBS += -framework CoreFoundation -framework Carbon -lobjc
quelle bandiere sono naturalmente esattamente ciò che si dovrebbe aggiungere al C++ o clang ++ riga di comando, se si compila manualmente.
Questo dovrebbe essere tutto ciò che è richiesto.
E 'una bella risposta, ma, come un a parte, non credo che sia necessario evitare l'uso di Objective C. qmake maniglie, e le intestazioni Qt sono validi quando incluso da un file '.mm'. Questo potrebbe essere semplicemente scritto in obj-C++ in un file '.mm' e sarebbe un po 'più leggibile senza scali espliciti runtime objc. I progetti Qt su mac possono includere file .m e .mm e puoi usare Qt da un file .mm. –
A partire da Qt5.4.0 è possibile gestire QEvent, relativo al clic sul dock: QEvent :: ApplicationActivate.
Il problema con QEvent :: ApplicationActivate è che sarà emesso per ogni attivazione -. Per esempio, anche se si passa per l'applicazione su Application Switcher. Il comportamento nativo è quello di mostrare l'app solo sul clic sull'icona del Dock, non quando passi da cmd + tab.
Ma, c'è un hack che funziona, almeno per Qt 5.9.1. L'icona del Dock click produce 2 QEvent :: ApplicationStateChangeEvent eventi sequenziali, nel frattempo cmd + TAB - solo uno. Quindi, questo codice emetterà il segnale di clic del Dock in modo abbastanza accurato. La classe app è la classe dell'applicazione ereditata da QApplication e anche un filtro eventi per se stesso.
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);
}
Grazie per questo! A quanto pare, questo codice ha smesso di funzionare in Qt 4.8.7, ma sono riuscito a farlo funzionare (su Qt 5.4.1), così ho postato una risposta con una versione aggiornata. – exscape
Questo non funziona per me. La risposta di exscape funziona –