6

QtMacアプリを開いています。アプリのアイコンをクリックしています

アプリでこれに関する通知を受け取る方法はありますか?

4

4 に答える 4

9

非推奨の警告(OS X 10.5以降)とタイプエラーのため、正しくコンパイルするための元の回答を取得できませんでした。いくつかの型名を変更してコンパイルしましたが、それでもコードは機能しませんでした。

新しいバージョンのQt(4.8.7+、5.xを含む;私は5.4.1を使用)は、追加したいメソッドを実装し、class_addMethodメソッドがすでに存在する場合は失敗することがわかりました。この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, "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

また、applicationShouldHandleReopen:hasVisibleWindows:メソッドに関するAppleのドキュメントも参照してください。

これをコンパイルするには、いくつかの追加のフレームワークとリンクする必要もあります。
qmakeを使用して、.proファイルに次を追加しました。

LIBS += -framework CoreFoundation -framework Carbon -lobjc

もちろん、これらのフラグは、手動でコンパイルする場合、c++またはclang++コマンドラインに追加する必要があるものとまったく同じです。
それが必要なすべてであるはずです。

于 2015-03-02T20:17:50.943 に答える
6

それはクレイジーですが、私はそれを手に入れました、そして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,"B@:");

        if (!test)
        {
            // failed to register handler...
        }
    }

#endif

この単純なメソッドをアプリケーションクラスに追加しました(回答の上部にあるハンドラーから参照されていることに注意してください)

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

チャームのように機能します。

于 2013-03-12T14:17:36.330 に答える
1

QEvent :: ApplicationActivateの問題は、アクティベーションごとに発行されることです。たとえば、ApplicationSwitcherでアプリに切り替えた場合でも同様です。ネイティブの動作では、cmd + tabで切り替えているときではなく、Dockアイコンをクリックしたときにのみアプリが表示されます。

ただし、少なくともQt5.9.1で機能するハックがあります。Dockアイコンをクリックすると、2つの連続したQEvent :: ApplicationStateChangeEventイベントが生成されますが、cmd+tabは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);
}
于 2017-09-29T12:08:34.890 に答える
0

Qt5.4.0以降、ドックのクリックに関連するQEventを処理できます:QEvent::ApplicationActivate。

https://bugreports.qt.io/browse/QTBUG-10899

https://doc.qt.io/qt-5/qevent.html

于 2016-09-07T11:34:45.340 に答える