Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Нужен совет (QWidget в отдельном QThread)

5.7K
30 августа 2011 года
Lindemann66
193 / / 21.07.2011
Всем привет

Хочу спросить совета по следующему вопросу

У меня есть приложение, которое работает в трее
У него должно быть меню настроек
Оно будет вызываться по нажатию на элемент контекстного меню иконки

Вот код конструктора основного класса
Код:
SystemTray::SystemTray(QWidget* pwgt /*=0*/) : QLabel(tr("<h1>Settings</h1>"), pwgt) {
    //заголовок окна настроек
    setWindowTitle("System tray");

    //таймер на 3 секунды
    startTimer(3000);

    QAction* pactShowHide = new QAction(tr("Settings"), this);
    connect(pactShowHide, SIGNAL(triggered()),
            this,         SLOT(slotShowHide())
            );

    QAction* pactQuit = new QAction(tr("Quit"), this);
    connect(pactQuit, SIGNAL(triggered()), qApp, SLOT(quit()));

    m_ptrayIconMenu = new QMenu(this);
    m_ptrayIconMenu->addAction(pactShowHide);
    m_ptrayIconMenu->addAction(pactQuit);

    m_ptrayIcon = new QSystemTrayIcon(this);
    m_ptrayIcon->setContextMenu(m_ptrayIconMenu);
    m_ptrayIcon->setToolTip(tr("Update Scanner"));
    m_ptrayIcon->setIcon(QPixmap("img1.bmp"));

    m_ptrayIcon->show();
}



Пока, как видите, я наследуюсь от QLabel, то есть, при нажатии на Settings появляется окошко с меткой

Думаю сделать так, чтобы по нажатию на Settings появлялось полноценное окно QWidget с опциями настройки

Создавал новый класс формы, наследовался от него
Всё норм, правда вызов окна настроек сильно тормозит (видимо, за счёт того, что я каждые 3 секунды выполняю определённые действия)

Очевидно, работать с окном настроек надо в отдельном потоке
Почитал в книжках про потоки, примерно понял, что к чему, но знаний пока не хватает

Насколько реально это сделать, и как бы вы решали данную проблему?
277
30 августа 2011 года
arrjj
1.7K / / 26.01.2011
Цитата: Lindemann66

Очевидно, работать с окном настроек надо в отдельном потоке



Неа. Очевидно что всю работу нужно делать в отдельном потоке.

Да в Qt предельно просто с потоками работать: в .pro добавляем CONFIG += thread. наследуемся от QThread переопределяем run(), добавляем своих членов, в конструкторе вызываем moveToThread(this) . Для членов в конструкторе указываем parent'a this или вызываем сначала moveToThread(this) потом setParent(this). Связь с другими объектами ведём только через сигналы, слоты.

run() можно сделать двумя способами (Для твоего примера чтото делать каждых 3 секунды)1. если поток будет делать чтото всё время то run() примерно такой конструкции:

 
Код:
void run()
{
while(true)
{
   //Чтото делаем
sleep(3);//отдыхаем 3 сек
}
}

2. если поток должен чтото делать по сигналу (в твоём примере у потока член QTimer, приконнекчен к onTimer())
 
Код:
void run()
{
exec();
}

И стартуем поток из приложения start()
Выход из потока - exit(int).
Ну и чтиво для досуга: http://doc.qt.nokia.com/latest/qthread.html
5.7K
30 августа 2011 года
Lindemann66
193 / / 21.07.2011
Хм, это ... как
Вот смотри, у меня main.cpp
 
Код:
int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    SystemTray st;

    QApplication::setQuitOnLastWindowClosed(false);

    return app.exec();
}


Файл SystemTray.cpp (приведу только актуальное)
Код:
SystemTray::SystemTray(QWidget* pwgt /*=0*/) : QLabel(tr("<h1>Settings</h1>"), pwgt) {
    //таймер на 3 секунды
    startTimer(3000);

    QAction* pactShowHide = new QAction(tr("Settings"), this);
    connect(pactShowHide, SIGNAL(triggered()),
            this,         SLOT(slotShowHide())
            );
}

void SystemTray::slotShowHide() {
    //setVisible(!isVisible());
    //вот сюда то и нужно, как я думал, впихнуть вызов, допустим, SettingsForm в отдельном потоке
}


Вот, надеюсь, понятно описал суть происходящего
277
30 августа 2011 года
arrjj
1.7K / / 26.01.2011
У тебяж выполняется действие в текущем потоке. И пока оно не выполнится сигнал до slotShowHide() не дойдёт.
5.7K
30 августа 2011 года
Lindemann66
193 / / 21.07.2011
То есть? Распиши поподробней свою мысль, пожалуйста:)
Так то действие у меня такое есть
 
Код:
void SystemTray::timerEvent(QTimerEvent *event)
{
    //здесь выполняется событие по таймеру
}


Ты его имеешь в виду?
Событие по таймеру, то бишь
277
30 августа 2011 года
arrjj
1.7K / / 26.01.2011
Вот это действие с этим таймером и вынеси в отдельный поток.
5.7K
30 августа 2011 года
Lindemann66
193 / / 21.07.2011
Спасибо, я так и попробую сделать
Просто верхний пост твой ток недавно заметил)
5.7K
30 августа 2011 года
Lindemann66
193 / / 21.07.2011
А ГУИ, получается, ты предлагаешь ни в какой поток не выносить?
Кстати, как можно сделать работу с ГУИ в моём случае

У меня то так - как нажали на настройки, появляется окно, нажали ещё раз - оно делается невидимым, то есть появление окна определеяется лишь видимостью

Собственно, этот код:
 
Код:
void SystemTray::slotShowHide() {
    setVisible(!isVisible());
}

Я, к сожалению, только такой вариант знаю
5.7K
30 августа 2011 года
Lindemann66
193 / / 21.07.2011
Цитата: arrjj
в .pro добавляем CONFIG += thread. наследуемся от QThread переопределяем run(), добавляем своих членов, в конструкторе вызываем moveToThread(this) . Для членов в конструкторе указываем parent'a this или вызываем сначала moveToThread(this) потом setParent(this).



Смысл CONFIG += и операций (moveToThread и SetParent), не очень понял, можешь объяснить вкратце, зачем они нужны?

5.7K
31 августа 2011 года
Lindemann66
193 / / 21.07.2011
Надеюсь ты ещё посмотришь эту тему)
Я, вобщем, как попробовал

main.cpp
Код:
int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    //поток работы трея
    TrayThread thread;
    //запускаем
    thread.start();

    QApplication::setQuitOnLastWindowClosed(false);

    return app.exec();
}


TrayThread.h
 
Код:
class TrayThread : public QThread {
Q_OBJECT

private:
    SystemTray st;
public:
    void run();
};


TrayThread.cpp
 
Код:
void TrayThread::run() {
    while(true) {
        //Что-то делаем
        st.Run();
        sleep(3);//отдыхаем 3 сек
    }
}


SystemTray.h
 
Код:
void SystemTray::Run() {
    //вот тут я что-то и делаю
}


То есть теперь ВЕСЬ трей выполняется в отдельном потоке
Я правильно понял твою идею?
К сожалению, теперь, если я захочу вызвать окно настроек
(а у меня, допустим, будет форма
Код:
class Menu : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Menu *ui;
};

)
и сам трей будет унаследован от этой формы
 
Код:
SystemTray::SystemTray(QWidget* pwgt /*=0*/) : Menu(pwgt)


То получится, что и ГУИ тоже будет вызываться в том же потоке, что и действие на run (потому что поток повешен на работу ВСЕГО Systemtray, как я понимаю)

Вот ты мне можешь подсказать, как бы сделать так, чтобы форма вызывалась как-то вне потока трея?
Надеюсь, я понятно выражаюсь)))
5.7K
31 августа 2011 года
Lindemann66
193 / / 21.07.2011
Я не силён в переваривании английской документации, написанной сложным языком...
Хотел спросить, если ты знаешь, вот moveToThread - перенаправляет весь цикл обработки событий объекта в отдельный поток?
То есть...Допустим, у меня у SystemTray есть тот же метод Run, и я, допустим, напишу ещё 10 методов (Run1, Run2, ..., Run10)
и если вызову moveThThread и SetParent, то эти методы Run будут выполняться в отдельном потоке?
Я правильно понял?
5.7K
31 августа 2011 года
Lindemann66
193 / / 21.07.2011
Просто если так, то смотри
У меня событие вызова ГУИ -
 
Код:
void SystemTray::slotShowHide() {
    setVisible(!isVisible());
}


Если я все события в ОДИН поток перенаправлю - у меня снова окажется так, что и Run, и вызов ГУИ будут в одном потоке, и опять будут тормоза

ВСЕ события нельзя в 1 поток перенаправлять...
А можно только определённое событие в поток направить?
5.7K
31 августа 2011 года
Lindemann66
193 / / 21.07.2011
А, всё, понял кажись идею:)
Нужно из класса трея вообще всю работу вынести в поток, а трей пусть только за ГУИ отвечает, и тогда не будет проблем!
277
31 августа 2011 года
arrjj
1.7K / / 26.01.2011
Цитата: Lindemann66
А, всё, понял кажись идею:)
Нужно из класса трея вообще всю работу вынести в поток, а трей пусть только за ГУИ отвечает, и тогда не будет проблем!



5+
Пример QThread: [ATTACH]5296[/ATTACH]
Статейка (правда ещё по Qt3 но общую инфу почерпнуть можна)

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог