QT系统托盘图标出现在Ubuntu启动器旁而不是面板上。

10

我刚接触QT,需要使用app-indicator构建一个应用程序。由于QT比GTK+更容易,所以我选择在QT中制作。

值得一提的是,我已经安装了sni-qt,并且VLC和Skype的应用程序指示器正常显示在面板上。我正在使用Ubuntu 13.04 64位的QT5。

我按照这个教程逐步操作:http://qt-project.org/doc/qt-4.8/desktop-systray.html

但是当我运行它时,它会出现以下情况(十字架是我使用的图标):

http://i.stack.imgur.com/4bT33.png

我该如何修复这个问题?


1
那是哪个版本的Qt?你尝试过最新版本(5.1.0-rc1)了吗? - peppe
2个回答

13

很抱歉,目前sni-qt不支持Qt5,因此您必须等待新版本支持它,或者按照这个指南使用gtk+和libappindicator编写代码。甚至有各种语言的示例可供参考。由于Qt5也分发GLib事件,因此使集成变得更加容易。首先,您需要找出自己是否在Unity上运行(以支持除Unity之外的更多桌面),可以通过检索XDG_CURRENT_DESKTOP环境变量并检查其是否返回Unity来实现,如果是,则创建appindicator,否则创建QSystemTrayIcon。

首先,您需要包含所需的头文件:

#undefine signals                                                  
extern "C" {                                                                 
  #include <libappindicator/app-indicator.h>                                 
  #include <gtk/gtk.h>                                                       
}                                                                            
#define signals public                                                       

由于app-indicator直接使用“signals”名称,我们需要取消定义默认的Qt“关键字”信号,该信号通常被翻译为public。然后,由于我们编写的是C++代码,而libappindicator是用C编写的,因此我们需要使用extern "C"来避免使用C++名称重整。

接下来根据我们所在的桌面环境创建AppIndicator/QSystemTrayIcon。

QString desktop;
bool is_unity;

desktop = getenv("XDG_CURRENT_DESKTOP");                                     
is_unity = (desktop.toLower() == "unity");                             

if (is_unity) { 
  AppIndicator *indicator;
  GtkWidget *menu, *item;                                                       

  menu = gtk_menu_new(); 

  item = gtk_menu_item_new_with_label("Quit");                             
  gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);                          
  g_signal_connect(item, "activate",                                          
               G_CALLBACK(quitIndicator), qApp);  // We cannot connect 
               // gtk signal and qt slot so we need to create proxy 
               // function later on, we pass qApp pointer as an argument. 
               // This is useful when we need to call signals on "this" 
               //object so external function can access current object                         
  gtk_widget_show(item);

  indicator = app_indicator_new(                                       
  "unique-application-name",                                                   
      "indicator-messages",                                                                  
    APP_INDICATOR_CATEGORY_APPLICATION_STATUS                                
  );                                                                         

  app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE); 
  app_indicator_set_menu(indicator, GTK_MENU(menu));   
} else {
  QSystemTrayIcon *icon;
  QMenu *m = new QMenu();                                                   

  m->addAction(tr("Quit"), qApp, SLOT(quit()));                      
}                                                                            

最后,我们创建了代理函数来调用Qt信号。为了声明该函数,我们需要使用extern "C",这样就不会有任何未定义的行为。

extern "C" {                                                                    
  void quitIndicator(GtkMenu *, gpointer);                                            
}                                                                               

现在是代理函数:

void quitIndicator(GtkMenu *menu, gpointer data) {                                    
  Q_UNUSED(menu);                                                               
  QApplication *self = static_cast<QApplication *>(data);                       

  self->quit();                                                                 
}

我认为GTK+对象与Qt的事件循环不兼容。这个示例会导致这些错误 - Nathan Osman

5

想要补充一点,对于使用Qt并试图在Ubuntu 13+中显示应用程序指示器的任何人,正如其他人所提到的,sni-qt不起作用,我能够使用上面的回复来制作一个工作的Qt应用程序,仍在努力让图标更改并显示弹出消息,但这是一个很好的开始,一旦我让图标和消息正常工作,我可能会将其发布在我的网站Voidrealms.com上:

确保执行sudo apt-get install libappindicator-dev

创建一个带有QDialog的新项目,并按照下面所示进行修改:

Pro文件:

#-------------------------------------------------
#
# Project created by QtCreator 2014-03-28T20:34:54
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = PluginServiceGUI
TEMPLATE = app

# includes for the libappindicator
# /usr/lib/x86_64-linux-gnu libglib-2.0.a

INCLUDEPATH += "/usr/include/libappindicator-0.1"
INCLUDEPATH += "/usr/include/gtk-2.0"
INCLUDEPATH += "/usr/include/glib-2.0"
INCLUDEPATH += "/usr/lib/x86_64-linux-gnu/glib-2.0/include"
INCLUDEPATH += "/usr/include/cairo"
INCLUDEPATH += "/usr/include/pango-1.0"
INCLUDEPATH += "/usr/lib/x86_64-linux-gnu/gtk-2.0/include"
INCLUDEPATH += "/usr/include/gdk-pixbuf-2.0"
INCLUDEPATH += "/usr/include/atk-1.0"

LIBS += -L/usr/lib/x86_64-linux-gnu -lgobject-2.0
LIBS += -L/usr/lib/x86_64-linux-gnu -lappindicator
LIBS += -L/usr/lib/x86_64-linux-gnu -lgtk-x11-2.0

#These seem to not be needed
#LIBS += -L/usr/lib/x86_64-linux-gnu -lcairo
#LIBS += -L/usr/lib/x86_64-linux-gnu -lpango-1.0
#LIBS += -L/usr/lib/x86_64-linux-gnu -lglib-2.0

# end incudes for libappindicator


SOURCES += main.cpp\
        dialog.cpp

HEADERS  += dialog.h

FORMS    += dialog.ui

RESOURCES += \
    resources.qrc

在 main.cpp 文件中。
#include "dialog.h"
#include <QApplication>
#include <QtGui>
#include <QSystemTrayIcon>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QMenu>

// https://dev59.com/kmQm5IYBdhLWcg3w-i9L
// requires libappindicator-dev
// sudo apt-get install libappindicator-dev
// installs the headers in: /usr/include/libappindicator-0.1/libappindicator

#undef signals
extern "C" {
  #include <libappindicator/app-indicator.h>
  #include <gtk/gtk.h>

  void quitIndicator(GtkMenu *, gpointer);

}
#define signals public

void quitIndicator(GtkMenu *menu, gpointer data) {
  Q_UNUSED(menu);
  QApplication *self = static_cast<QApplication *>(data);

  self->quit();
}

void ShowUnityAppIndicator()
{
    AppIndicator *indicator;
    GtkWidget *menu, *item;

    menu = gtk_menu_new();

    item = gtk_menu_item_new_with_label("Quit");
    gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
    g_signal_connect(item, "activate",
                 G_CALLBACK(quitIndicator), qApp);  // We cannot connect
                 // gtk signal and qt slot so we need to create proxy
                 // function later on, we pass qApp pointer as an argument.
                 // This is useful when we need to call signals on "this"
                 //object so external function can access current object
    gtk_widget_show(item);

    indicator = app_indicator_new(
    "unique-application-name",
        "indicator-messages",
      APP_INDICATOR_CATEGORY_APPLICATION_STATUS
    );

    app_indicator_set_status(indicator, APP_INDICATOR_STATUS_ACTIVE);
    app_indicator_set_menu(indicator, GTK_MENU(menu));
}



void ShowQtSysTray(QApplication* app, QDialog* dialog)
{

    Q_INIT_RESOURCE(resources);

    if (!QSystemTrayIcon::isSystemTrayAvailable()) {
        QMessageBox::critical(0, QObject::tr("Systray"),
                              QObject::tr("I couldn't detect any system tray "
                                          "on this system."));
    }
    QApplication::setQuitOnLastWindowClosed(false);


    QSystemTrayIcon* trayIcon = new QSystemTrayIcon(dialog);
    QAction* Action = new QAction("hello", dialog);
    QMenu* trayIconMenu = new QMenu(dialog);

    trayIconMenu->addAction("Quit", app, SLOT(quit()));

    trayIconMenu->addAction(Action);
    trayIcon->setContextMenu(trayIconMenu);
    trayIcon->setIcon(QIcon (":/icons/Icons/accept.png"));

    trayIcon->show();
    trayIcon->showMessage("Title","Message");
}



int main(int argc, char *argv[])
{



        QApplication a(argc, argv);
         Dialog w;

         //Determine the desktop type
         QString desktop;
         bool is_unity;

         desktop = getenv("XDG_CURRENT_DESKTOP");
         is_unity = (desktop.toLower() == "unity");

         if(is_unity)
         {
            ShowUnityAppIndicator();
         }
         else
         {
             //Show the SystemTrayIcon the Qt way
             ShowQtSysTray(&a, &w);
         }

   // w.show();

    return a.exec();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接