web-dev-qa-db-ja.com

動的な統一クイックリストのためにC ++でg_signal_connect()を使用する正しい方法は何ですか?

アプリケーションで動的な統一クイックリストを使用するようにします。アプリケーションを構築するために、C++とQtCreator IDEを使用しています。メニューアクションがトリガーされると、MainWindowクラスの非静的関数にアクセスできるようになり、「通常の」メインウィンドウの関数からアクセスできるグラフィカルユーザーインターフェイスを更新できるようになります。 。

だから、私はこのようなクイックリストを構築しています(mainwindow.cpp):

void MainWindow::enable_unity_quicklist(){
    Unity_Menu = dbusmenu_menuitem_new();

    dbusmenu_menuitem_property_set_bool (Unity_Menu, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);

    Unity_Stop = dbusmenu_menuitem_new();
    dbusmenu_menuitem_property_set(Unity_Stop, DBUSMENU_MENUITEM_PROP_LABEL, "Stop");

    dbusmenu_menuitem_child_append (Unity_Menu, Unity_Stop);

    g_signal_connect (Unity_Stop, DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(&fake_callback), (gpointer)this);

    if(!unity_entry)
        unity_entry = unity_launcher_entry_get_for_desktop_id("myapp.desktop");

    unity_launcher_entry_set_quicklist(unity_entry, Unity_Menu);

    dbusmenu_menuitem_property_set_bool(Unity_Menu, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
    dbusmenu_menuitem_property_set_bool(Unity_Stop, DBUSMENU_MENUITEM_PROP_VISIBLE, true);
}

void MainWindow::fake_callback(gpointer data){
    MainWindow* m = (MainWindow*)data;
    m->on_stopButton_clicked();
}

void MainWindow::on_stopButton_clicked(){
   //stopping the process...
}

mainwindow.h:

private slots:
   void enable_unity_quicklist();
   void on_stopButton_clicked();
public slots:
   static void fake_callback(gpointer data);

この提案は http://old.nabble.com/Using-g_signal_connect-in-class-td18461823.html から引用されました

Unityクイックリストから「停止」アクションを選択すると、プログラムがすぐにクラッシュします。プログラムをデバッグすると、クラッシュせずにon_stopButton_clicked()内の関連するMainWindowにアクセスできないことがわかります。たとえば、このチェックを実行するとクラッシュします(この関数内のコードの最初の2行です):

if (!ui->stopButton->isEnabled())
        return;

また、インターネットで見つけた他の多くのことをテストしましたが、どれも機能しませんでした。 1つの興味深い解決策は、gtkmmを使用することです( http://developer.gnome.org/gtkmm-tutorial/stable/sec-connecting-signal-handlers.html.en )が、私はで使用されていませんすべてがGTKアプリケーションで動作し(私はQtでのみ動作します)、これが私の機会に合うかどうかもわかりません。

6
hytromo

編集: OK、かなりの量の調査(valgrindの実行を含む)の後、私はついにここで何が起こっているのかを理解することができました。コールバックの署名が正しくありません。

静的メソッドの署名は次のとおりです。

void MainWindow::fake_callback(DbusmenuMenuitem *, guint, gpointer data)
{
    //...
}

DbusmenuMenuitem *およびguintが追加されていることに注意してください。 1つ目は、信号を発信するDBusメニュー項目へのポインタで、2つ目はタイムスタンプです。両方を使用しない場合でも、署名に存在する必要があります。

g_signal_connectは実行時に呼び出され、関数が受け入れるパラメーターを知る方法がなく、署名が一致すると仮定してスタックにパラメーターを盲目的にプッシュするだけです。 (これは、MOC(メタオブジェクトコンパイラ)が、互換性のないシグネチャを持つスロットに信号を接続しようとしていることを知るのに十分な情報を生成するQtでおそらく慣れているものとは異なります。)

3
Nathan Osman