Russian Qt Forum

Qt => Вопросы новичков => Тема начата: KsenZ от Апрель 14, 2013, 06:49



Название: Приложение System Tray only
Отправлено: KsenZ от Апрель 14, 2013, 06:49
Собственно вопрос. Как написать приложение состоящее только из трея? Т.е. не будет не каких окон, только уведомления, и небольшое меню.
Я пробовал написать, трей работает, но выходит и совершенно пустое окно, хотя в проекте нет файла ui.
Собственно вот код:
tray.cpp
Код:
#include "tray.h"

Tray::Tray(QWidget *parent) :
    QWidget(parent)
{
    createActions();
    createTrayIcon();
    setIcon();

    trayIcon->show();
}

void Tray::createActions()
{
    open = new QAction(tr("&Open"), this);
    connect(open, SIGNAL(triggered()), this, SLOT(show()));


    close = new QAction(tr("&Quit"), this);
    connect(close, SIGNAL(triggered()), qApp, SLOT(quit()));
}

void Tray::createTrayIcon()
{
    trayIconMenu = new QMenu(this);


    trayIconMenu->addAction(open);
    trayIconMenu->addSeparator();
    trayIconMenu->addAction(close);


    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setContextMenu(trayIconMenu);


    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconClicked(QSystemTrayIcon::ActivationReason)));
}

void Tray::setIcon()
{
    trayIcon->setIcon(QIcon(":/tray.ico"));
}

void Tray::trayIconClicked(QSystemTrayIcon::ActivationReason reason)
{
    if(reason == QSystemTrayIcon::Trigger)
        this->show();
}

void Tray::closeEvent(QCloseEvent *event)
{
    if (trayIcon->isVisible()) {
        trayIcon->showMessage(tr("Still here!!!"),
                              tr("This application is still running. To quit please click this icon and select Quit"));
        hide();


        event->ignore();
    }
}

Tray::~Tray()
{
    delete trayIcon;
    delete trayIconMenu;
    delete open;
    delete close;
}
tray.h
Код:
#ifndef TRAY_H
#define TRAY_H

#include <QtGui>
#include <QWidget>
#include <QSystemTrayIcon>
#include <QCloseEvent>


class QMenu;

class Tray : public QWidget
{
    Q_OBJECT

public:
    explicit Tray(QWidget *parent = 0);
    ~Tray();

private:
    void createActions();
    void createTrayIcon();
    void setIcon();
    void closeEvent(QCloseEvent *);

    QSystemTrayIcon *trayIcon;
    QMenu *trayIconMenu;

    QAction *open;
    QAction *close;

private slots:
    void trayIconClicked(QSystemTrayIcon::ActivationReason);
};

#endif // TRAY_H
main.cpp
Код:
#include "tray.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (!QSystemTrayIcon::isSystemTrayAvailable())
    {
        QMessageBox::critical(0, QObject::tr("Tray"),
                              QObject::tr("I couldn't detect any system tray "
                                          "on this system."));
        return 1;
    }

    QApplication::setQuitOnLastWindowClosed(false);

    Tray w;
    w.show();
   
    return a.exec();
}


Название: Re: Приложение System Tray only
Отправлено: Serr500 от Апрель 14, 2013, 08:57
То, что ui нет, здесь не имеет значения - у Вас есть потомок QWidget, который и будет главным окном. Убирайте QWidget, оставляя только QTrayIcon. Если надо ловить сигналы, создайте класс-потомок QObject.


Название: Re: Приложение System Tray only
Отправлено: KsenZ от Апрель 14, 2013, 11:42
То, что ui нет, здесь не имеет значения - у Вас есть потомок QWidget, который и будет главным окном. Убирайте QWidget, оставляя только QTrayIcon. Если надо ловить сигналы, создайте класс-потомок QObject.
Не совсем понял...
Если класс будет наследоваться от QObject, то у него не будет метода show(), как тогда трей "отобразить"? Т.е. в main.cpp:
Код:
Tray w;
w.show();

Не будет отрабатывать.


Название: Re: Приложение System Tray only
Отправлено: sergek от Апрель 14, 2013, 12:35
я бы сделал так:
Код:
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    if(onlyTray)
        w.showTray();
    else
        w.show();
   
    return a.exec();
}
Код:
#include "ui_mainwindow.h"

class QSystemTrayIcon;
class QAction;
class QMenu;

class MainWindow : public QMainWindow, private Ui::MainWindow
{
    Q_OBJECT

private:
    QSystemTrayIcon *trayIcon;
    QAction *quitAction;
    QMenu *trayIconMenu;
public:
    explicit MainWindow(QWidget *parent = 0);

    void showTray();
};

const bool onlyTray=true;
Код:
#include "mainwindow.h"
#include <QSystemTrayIcon>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setupUi(this);
}

void MainWindow::showTray(){
    // создание иконки
    trayIconMenu = new QMenu(this);
    quitAction = new QAction(tr("Выход"), this);
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
    trayIconMenu->addAction(quitAction);

    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setContextMenu(trayIconMenu);
    trayIcon->setIcon(QIcon(":/blueflag.png"));
    trayIcon->setToolTip(this->windowTitle());
    trayIcon->show();
}


Название: Re: Приложение System Tray only
Отправлено: VPS от Апрель 14, 2013, 12:39
А что мешает отнаследоваться только от "QSystemTrayIcon"?


Название: Re: Приложение System Tray only
Отправлено: KsenZ от Апрель 14, 2013, 12:50
А что мешает отнаследоваться только от "QSystemTrayIcon"?
А сигналы как ловить без QObject?


Название: Re: Приложение System Tray only
Отправлено: VPS от Апрель 14, 2013, 13:00
А сигналы как ловить без QObject?

QSystemTrayIcon Class Reference

The QSystemTrayIcon class provides an icon for an application in the system tray. More...
 #include <QSystemTrayIcon>

Inherits: QObject.


Название: Re: Приложение System Tray only
Отправлено: Serr500 от Апрель 14, 2013, 13:31
Вот Вам простенький примерчик.


Название: Re: Приложение System Tray only
Отправлено: KsenZ от Апрель 14, 2013, 14:14
Спасибо всем за ответы. Попробую завтра разобраться.


Название: Re: Приложение System Tray only
Отправлено: KsenZ от Апрель 15, 2013, 04:07
Попробовал, спасибо все работает.
Вот только есть один вопрос, он конечно к теме не относится, но все же.

Если в хидере я объявляю
Код:
QSystemTrayIcon *tray;
QMenu *trayMenu;

приложение собирается, но при запуске segmentation fault

а если
Код:
QSystemTrayIcon tray;
QMenu trayMenu;

то все нормально.


Название: Re: Приложение System Tray only
Отправлено: Serr500 от Апрель 15, 2013, 08:28
А new и delete для них вызываете? Сдаётся мне, что нет. ;)


Название: Re: Приложение System Tray only
Отправлено: Bepec от Апрель 15, 2013, 12:03
КсенZ, надо учить плюсы (С++).

int *b - это создание указателя на объект. Пока ты объект не создашь, то указатель при обращении будет посылать всех в жо лес.

Почитай про указатели и ссылки.


Название: Re: Приложение System Tray only
Отправлено: Serr500 от Апрель 15, 2013, 13:51
Пока ты объект не создашь, то указатель при обращении будет посылать всех в жо лес.
Не обязательно. Можно случайно при инициализации получить валидный адрес и считать хрен знает что. Это гораздо хуже SEGFAULT - не валится, но результат работы непредсказуемый. Поэтому я всегда в конструкторах пихаю в указатели NULL - это лучше чем ошибка, проявившаяся через миллион строк совершенно в другом месте.

P.S. Вероятно, человек либо новичок в программировании, либо раньше писал на языках, где конструкции типа T* t автоматически создают объекты.


Название: Re: Приложение System Tray only
Отправлено: Bepec от Апрель 15, 2013, 14:15
Есть ещё вариант. Что он писал на языках без указателей :)


Название: Re: Приложение System Tray only
Отправлено: KsenZ от Апрель 16, 2013, 03:37
Я знаю, что int *b - это создание указателя на объект.
Вопрос у меня вот какой. Как лучше делать?
Код:
QMenu trayMenu;
trayMenu.addSeparator();
или же
Код:
QMenu *trayMenu;
trayMenu = new Qmenu;
trayMenu->addSeparator();


Название: Re: Приложение System Tray only
Отправлено: Bepec от Апрель 16, 2013, 06:53
Область видимости - знакомое вам понятие? :)

А так - особого различия нет, просто первый вариант будет существовать только в области видимости, а второй будет существовать вечно, пока вы его не удалите :)

Ещё упрощу.
Если в первом случае trayMenu будет членом класса, в котором используется - всё круто. Оно будет существовать пока существует класс. Но если вы создадите его в какой нибудь функции, то оно умрёт после завершения функции.

PS почитайте про динамическое и статическое создание переменных.


Название: Re: Приложение System Tray only
Отправлено: KsenZ от Апрель 16, 2013, 07:05
Да, знакомое :)
Ну теперь все понятно. Спасибо большое за пояснение.