在 C++ 中,对于动态统一快速列表,使用 g_signal_connect() 的正确方法是什么?

在 C++ 中,对于动态统一快速列表,使用 g_signal_connect() 的正确方法是什么?

我想让我的应用程序使用动态统一快速列表。为了构建我的应用程序,我使用 C++ 和 QtCreator IDE。当触发菜单操作时,我希望能够访问我的MainWindow类的非静态函数,以便能够更新可以从“正常”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...
}

主窗口.h:

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

此建议来自http://old.nabble.com/使用-g_signal_connect-in-class-td18461823.html

我从 Unity Quicklist 中选择“停止”操作后,程序立即崩溃。调试程序显示,如果不崩溃,我无法访问 on_stopButton_clicked() 内的任何 MainWindow 相关内容。例如,它在执行此检查时崩溃(这是此函数内的前两行代码):

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

我也测试了在互联网上找到的许多其他东西,但都没有用。一个有趣的解决方案是使用 gtkmm (http://developer.gnome.org/gtkmm-tutorial/stable/sec-connecting-signal-handlers.html.en),但我根本不习惯使用 GTK 应用程序(我只使用 Qt),而且我不知道这是否适合我的场合。

答案1

编辑:好的,经过大量调查(包括运行valgrind),我终于弄清楚了这里发生了什么。您的回调签名不正确。

静态方法的签名应该是:

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

注意添加了DbusmenuMenuitem *guint。第一个是指向发出信号的 DBus 菜单项的指针,第二个是时间戳。即使您不使用它们,它们也必须存在于签名中。

g_signal_connect在运行时调用,无法知道函数接受哪些参数,只能盲目地将参数推送到堆栈上,假设签名匹配。(这与您可能在 Qt 中习惯的不同,在 Qt 中,MOC(元对象编译器)会生成足够的信息来知道您何时尝试将信号连接到具有不兼容签名的插槽。)

相关内容