Значок 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

Как я могу это исправить?


person Sid Verma    schedule 19.06.2013    source источник
comment
Какая это версия Qt? Вы пробовали последнюю версию (5.1.0-rc1)?   -  person peppe    schedule 20.06.2013


Ответы (2)


Я боюсь, что Qt5 не поддерживается sni-qt на данный момент, так что вам придется либо ждать нового релиза, который будет его поддерживать, либо кодировать его, используя 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 напрямую использует имя «сигналы», нам нужно отменить определение сигналов «ключевого слова» Qt по умолчанию, которые обычно переводятся в общедоступные. Затем, поскольку мы пишем код на 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();                                                                 
}
person stepanbujnak    schedule 06.07.2013
comment
Я не думаю, что объекты GTK+ хорошо сочетаются с циклом событий Qt. Этот пример приводит к эти ошибки. - person Nathan Osman; 23.06.2014

Просто хотел добавить, для тех, кто использует Qt и пытается показать индикатор приложения в Ubuntu 13+, поскольку другие упомянули, что sni-qt не работает, я смог использовать приведенный выше ответ, чтобы сделать приложение Qt, которое работает, все еще пытаюсь заставить значок измениться и показать всплывающие сообщения, но это отличное начало, как только я заставлю значок и сообщение работать, я могу опубликовать их на своем сайте Voidrealms.com:

Обязательно сделайте sudo apt-get install libappindicator-dev

Создайте новый проект с QDialog и измените его, как показано ниже:

Про файл:

#-------------------------------------------------
#
# 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/questions/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();
}
person Bryan    schedule 29.03.2014