Значок QT Systray появляется рядом с пусковой установкой на Ubuntu, а не на панели

Я новичок в QT и мне нужно создать приложение с индикатором приложения. Поскольку QT кажется проще, чем GTK +, я делаю это в QT.

Я бы упомянул, что у меня установлен sni-qt, а индикаторы vlc и skype отображаются нормально на панели. Я использую QT5 на Ubuntu 13.04 64-бит.

Я последовал этому руководству шаг за шагом: http://qt-project.org/doc/qt-4.8/desktop-systray.html

Но когда я запускаю его, вот как он появляется (Крест - это значок, который я использую):

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

Как это исправить?

Ответ 1

Я боюсь, что на данный момент Qt5 не поддерживается sni-qt, поэтому вам придется либо ждать нового релиза, который будет его поддерживать, либо использовать его с помощью gtk + и libappindicator, используя это руководство. Есть даже примеры для разных языков. Так как Qt5 также распространяет события GLib, это делает интеграцию намного проще. Сначала вам нужно выяснить, работаете ли вы на 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 напрямую использует имя "сигналы", нам нужно определить стандартные сигналы ключевого слова Qt, которые обычно переводится на общедоступные. Тогда, поскольку мы кодируем С++, а libappindicator закодирован в C, нам нужно использовать extern "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", поэтому не будет никакого поведения undefined.

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

Теперь прокси-функция:

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

  self->quit();                                                                 
}

Ответ 2

Просто хотел добавить, для тех, кто использует 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>

// http://stackoverflow.com/info/17193307/qt-systray-icon-appears-next-to-launcher-on-ubuntu-instead-of-on-the-panel
// 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();
}