2013-02-28 5 views

答えて

5

それはクレイジーだが、私はそれを得た、と任意の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 

#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 

追加するこの単純な方法で自分のアプリケーションクラスに(注意それはから参照されます私の答えの先頭にあるハンドラ)

void MyApplictionClass::onClickOnDock() 
{ 
    // do something... 
} 

魅力的な作品です。

+0

ありがとうございました!明らかに、このコードはQt 4.8.7で動作しなくなりましたが、Qt 5.4.1で動作させることができたので、私は更新されたバージョンで答えを投稿しました。 – exscape

+0

これは私には役に立たない。エキスパートの答えは ' –

9

廃止の警告(post-OS X 10.5)とタイプエラーのため、元の回答が正しくコンパイルできませんでした。いくつかの型名を変更してコンパイルしましたが、コードはまだ機能しませんでした。

Qtの新しいバージョン(5.8を含​​む4.8.7+;私は5.4.1を使用しています)が追加したいメソッドを実装しており、メソッドがすでに存在する場合はclass_addMethodが失敗します。 this QTBUGを参照してください。
注:上記のバグレポートには少し異なる解決策が含まれています(問題を自分で解決した後に見つけました)。

私にとっては、方法が存在するかどうかを確認する1つの解決策です。そうであれば、それを置き換えます。そうでない場合は、単に追加します。
私は古いQtバージョンでこのコードをテストしていませんが、OPロジックを使用しているので動作するはずです。

ここに私のコードです。 OPの場合と同様に、すべてのコードはQApplicationサブクラスの.cppファイルにあります。

#ifdef Q_OS_MAC 
#include <objc/objc.h> 
#include <objc/message.h> 
void setupDockClickHandler(); 
bool dockClickHandler(id self,SEL _cmd,...); 
#endif 

私はQApplicationサブクラスのコンストラクタは

#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, "[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 

Apple documentation on the applicationShouldHandleReopen:hasVisibleWindows: methodを参照してください。

これをコンパイルするには、いくつかの余分なフレームワークもリンクする必要があります。これらのフラグは、手動でコンパイル場合は、C++または打ち鳴らす++コマンドラインに追加する必要があります正確に何もちろんです

LIBS += -framework CoreFoundation -framework Carbon -lobjc 

:qmakeのを使用して
は、私は私の.PROファイルに次を追加しました。
これはすべて必要なものです。

+1

です。それは良い答えですが、私はそれを客観的なC. qmakeの使用を避ける必要があるとは思いません。Qmakeは '.mm'ファイルからインクルードされたときに有効です。これは単にobj-C++で '.mm'ファイルで記述することができ、objcランタイムへの明示的な呼び出しがなくても少し読みやすくなります。 MacのQtプロジェクトには.mと.mmファイルを含めることができます。また、.mmファイルからQtを使用することもできます。 –

0

QEventに問題:: ApplicationActivateは、それがすべての活性化のために放出されることである - 例えば、あなたがアプリケーションスイッチャーのアプリに切り替えた場合でも。ネイティブの振る舞いは、Dockのアイコンをクリックするだけで、cmd +タブで切り替えるときではなく、アプリを表示することです。

しかし、少なくともQt 5.9.1では機能するハックがあります。 Dockアイコンをクリックすると、2つのシーケンシャルなQEvent :: ApplicationStateChangeEventイベントが生成されますが、cmd +タブは1つのみです。 このコードはDockのクリック信号を非常に正確に出力します。 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); 
} 
関連する問題