Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Как передать сообщения из потока в форму ? 
V
    Опции темы
AntonTatu
Дата 22.12.2009, 10:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 30
Регистрация: 12.4.2008

Репутация: нет
Всего: нет



Всем привет. Заранее извеняюсь что выложил много кода, хочется что бы при выполнении длительных расчетов не замирал интерфейс пользователя. В книге по QT "Бланшет,Саммерфилд - QT4 Программирование GUI на С++.2ed.2008.djvu" нашел примерчик, вроде все вычисления проводятся в отдельном потоке, но мне нужно записывать в статус бар значений счетчика после каждой итерации (функция Run::apply(const QString &str)), как это можно сделать в моем случае ?

Код

//main.cpp

#include <QApplication>

#include "mythread.h"
#include <QTextCodec>

int main(int argc, char *argv[])
{
    QTextCodec *codec = QTextCodec::codecForName("CP1251");
    QTextCodec::setCodecForTr(codec);
    QApplication app(argc, argv);
    Program ProgramWin;
    ProgramWin.resize(400, 300);
    ProgramWin.show();
    return app.exec();
}





Код

//mythread.h

#ifndef Program_H
#define Program_H

#include <QMainWindow>

#include "transactionthread.h"

class QAction;
class QLabel;
class QMenu;

class Program : public QMainWindow
{
    Q_OBJECT

public:
    Program();

protected:
        void closeEvent(QCloseEvent *event);

private slots:
    void run();
    void allTransactionsDone();

private:
    void createActions();
    void createMenus();
    void addTransaction(Transaction *transact);

    TransactionThread thread;
    QLabel *imageLabel;

    QMenu *fileMenu;
    QAction *runAction;
};

#endif





Код

//mythread.cpp

#include <QtGui>

#include "mythread.h"
#include "ui_resizedialog.h"

Program::Program()
{
    imageLabel = new QLabel;
    imageLabel->setBackgroundRole(QPalette::Dark);
    imageLabel->setAutoFillBackground(true);
    imageLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    setCentralWidget(imageLabel);

    createActions();
    createMenus();

    statusBar()->showMessage(tr("Ready"), 2000);

    connect(&thread, SIGNAL(transactionStarted(const QString &)),
            statusBar(), SLOT(showMessage(const QString &)));
    connect(&thread, SIGNAL(transactionRun(const QString &)),
            statusBar(), SLOT(showMessage(const QString &)));

    connect(&thread, SIGNAL(allTransactionsDone()),
            this, SLOT(allTransactionsDone()));

}
void Program::closeEvent(QCloseEvent *event)
{
 event->accept();
}

void Program::run()
{
        addTransaction(new Run());
}


void Program::addTransaction(Transaction *transact)
{
    thread.addTransaction(transact);
    runAction->setEnabled(false);
}

void Program::allTransactionsDone()
{
    runAction->setEnabled(true);
    setWindowModified(true);
    statusBar()->showMessage(tr("Ready"), 2000);
}

void Program::createActions()
{
    runAction = new QAction(tr("&Run.."), this);
    runAction->setStatusTip(tr("Запуск"));
    connect(runAction, SIGNAL(triggered()), this, SLOT(run()));
}

void Program::createMenus()
{
    fileMenu = menuBar()->addMenu(tr("&Run"));
    fileMenu->addAction(runAction);
}






Код

//transactionthread.h

#ifndef TRANSACTIONTHREAD_H
#define TRANSACTIONTHREAD_H

#include <QMutex>
#include <QQueue>
#include <QThread>
#include <QWaitCondition>
#include <QString>

class Transaction
{
public:
    virtual ~Transaction() { }
    virtual QString apply(const QString &str) = 0;
    virtual QString message() = 0;
};


class Run : public Transaction
{
public:
    Run();
    QString apply(const QString &str)
    QString message();

private:
    int i;

};

class TransactionThread : public QThread
{
    Q_OBJECT

public:
    TransactionThread();
    ~TransactionThread();

    void addTransaction(Transaction *transact);

signals:
    void transactionStarted(const QString &message);
    void transactionRun(const QString &message);
    void allTransactionsDone();

protected:
    void run();

private:
    QQueue<Transaction *> transactions;
    QWaitCondition transactionAdded;
    QMutex mutex;

};

#endif



Код

//transactionthread.h

#include <QtGui>

#include "transactionthread.h"

Transaction * const EndTransaction = 0;

Run::Run()
{



}

QString Run::apply(const QString &str){
    QString str2;
    //непосредственно расчеты
           int i=1;
    int a = 10;
    while (a !=i){
    a=a/i;
    i++;
    str2 = QString::number(i,10);
    }
return (str2);
}

QString Run::message()
{
   return QObject::tr("Выполняю расчет...");

}

TransactionThread::TransactionThread()
{
    start();
}

TransactionThread::~TransactionThread()
{
    {
        QMutexLocker locker(&mutex);
        while (!transactions.isEmpty())
            delete transactions.dequeue();
        transactions.enqueue(EndTransaction);
        transactionAdded.wakeOne();
    }

    wait();
}

void TransactionThread::addTransaction(Transaction *transact)
{
    QMutexLocker locker(&mutex);
    transactions.enqueue(transact);
    transactionAdded.wakeOne();
}

void TransactionThread::run()//в этой функции будем выполнять долгие расчеты, при этом интерфейс приложения зависать не должен
{
    Transaction *transact = 0;
    forever {
        {
            QMutexLocker locker(&mutex);
            if (transactions.isEmpty())
                transactionAdded.wait(&mutex);
            transact = transactions.dequeue();
            if (transact == EndTransaction)
                break;
        }

        emit transactionStarted(transact->message()); //выводим надпись для статусбара 
        QString str = transact->apply(str); //выполняем необходимые расчеты в зависимости от выбранного типа расчетов с использованием интерфейса

        delete transact;
        {
            QMutexLocker locker(&mutex);
            if (transactions.isEmpty())
                emit allTransactionsDone();
        }
    }
}



PM MAIL   Вверх
chaos
Дата 22.12.2009, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 5
Всего: 44



извини, в коде копаться некогда да и не охото.

вот те пища для ....
Код

class WorkerThread : public QThread
{
Q_OBJECT
public:
    ...

protected:
    void run()
    {
        ....
        emit progressChange(value);
        ....
    }

signals:
    void progressChange(int percent);
}

class View : public QWidget
{
Q_OBJECT
public:
    View(QWidget *parent)
        : QWidget(parent)
    {
        WorkerThread *thread = ....
        connect(thread, SIGNAL(progressChange(int)), SLOT(progressChange(int)));
        ....
    }

private slots:
    void progressChange(int percent)
    {
        ui->progressBar->setValue(percent);
    }
}



Это сообщение отредактировал(а) chaos - 22.12.2009, 11:36
PM WWW   Вверх
AntonTatu
Дата 22.12.2009, 11:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 30
Регистрация: 12.4.2008

Репутация: нет
Всего: нет



Цитата(chaos @ 22.12.2009,  11:34)
извини, в коде копаться некогда да и не охото.

вот те пища для ....

мне к сожалению такой вариант не подходит....
PM MAIL   Вверх
chaos
Дата 22.12.2009, 11:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 5
Всего: 44



AntonTatu

ну вот вполне рабочий пример, выдуманный правда
Код

#include <QtGui/QApplication>
#include <QtGui/QProgressBar>
#include <QtGui/QWidget>

#include <QtCore/QThread>

class WorkThread : public QThread
{
Q_OBJECT
public:
    WorkThread(QObject *parent)
        : QThread(parent)
    {
    }

signals:
    void calcStageChange(int);

protected:
    void run()
    {
        while (true) {
            for (int i = 0; i < 100; i++) {
                emit calcStageChange(i);
                QThread::usleep(10000);
            }

            for (int i = 99; i >= 0; i--) {
                emit calcStageChange(i);
                QThread::usleep(10000);
            }
        }
    }
};

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

    QProgressBar view;
    WorkThread *thread = new WorkThread(&view);

    view.connect(thread, SIGNAL(calcStageChange(int)), SLOT(setValue(int)));
    view.show();
    thread->start();


    return app.exec();
}

#include "GeneratedFiles/Debug/main.moc"


upd: чот я запарился: перепутал статус бар с прогрес

Это сообщение отредактировал(а) chaos - 22.12.2009, 11:58
PM WWW   Вверх
AntonTatu
Дата 22.12.2009, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 30
Регистрация: 12.4.2008

Репутация: нет
Всего: нет



Цитата(chaos @ 22.12.2009,  11:56)
ну вот вполне рабочий пример, выдуманный правда

У меня засада в том что после вызова потока, вызывается "мояфункция," записанная в "мояфункция.цпп", и при ее выполнении мне нужно каким то образом делать emit calcStageChange(i),
как ей передать этот сигнал ?


protected:
    void run()
    {
        while (true) {
            for (int i = 0; i < 100; i++) {
                emit calcStageChange(i);
                QThread::usleep(10000);
            }

            мояфункция(int,int)

            for (int i = 99; i >= 0; i--) {
                emit calcStageChange(i);
                QThread::usleep(10000);
            }
        }
    }
};


PM MAIL   Вверх
chaos
Дата 24.12.2009, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Серийный программист
****


Профиль
Группа: Завсегдатай
Сообщений: 2979
Регистрация: 7.7.2004
Где: Екатеринбург

Репутация: 5
Всего: 44



AntonTatu, для функционирования сигналов и слотов необходимо быть QObject.
PM WWW   Вверх
W4FhLF
Дата 24.12.2009, 11:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 4
Всего: 121



У меня похожая ситуация. Вычислительное ядро ничего не знает о UI. Сделал так.
Есть синглтон TaskManager, в нём хранятся более простые объекты классов TaskProgress, каждый из которых хранит текущее значения завершённости какого-либо задания. Соответственно перед началоми каких-то долгих расчётов я создаю объект 

Код

TaskProgress taskpr(0); 


и добавляю его в объект класса TaskManager: 

Код

TaskMngr::Instance().add_task("MyTask", taskpr). 


Потом, в процессе расчётов просто изменяю состояние прогресса: 

Код

taskpr.set_progress(n);


К синглтону можно получить доступ из любой части приложения. Соответственно в UI есть отдельный виджет, который отображает состояние менеджера заданий и обновляет его при необходимости. 


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
Madonna
Дата 15.2.2010, 01:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Forbidden love...
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 22.1.2009
Где: Москва

Репутация: 3
Всего: 4



Синглтон...

Какую реализацию синглтона использовать?  Я в них совсем запуталась...

Постановка задачи как у топикстратера.
--------------------
Best regards, Madonna
PM   Вверх
borisbn
Дата 15.2.2010, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Создай интерфейс:
Код

class Listener
{
public:
    virtual void set( const QString & str ) = 0;
}
 
Наследуй от него свой TransactionThread:
Код

class TransactionThread : public QThread, public Listener
{
...
void set( const QString & str )
{
    emit то-что-нужно-эмитать;
}

Введи в Transaction функцию setListener
Код

void Run::setListener( Listener * listener )
{
    m_listener = listener;
}

и перед запуском apply вызывай её
Код

transaction->setListener( this );

В функции apply вызывай
Код

if ( m_listener )
{
    m_listener->set( "чо хочешь" );
}


Это сообщение отредактировал(а) borisbn - 15.2.2010, 15:28


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
W4FhLF
Дата 15.2.2010, 15:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


found myself
****


Профиль
Группа: Участник Клуба
Сообщений: 2831
Регистрация: 2.12.2006

Репутация: 4
Всего: 121



Цитата(Madonna @  15.2.2010,  01:40 Найти цитируемый пост)
Какую реализацию синглтона использовать?  Я в них совсем запуталась...



Можешь использовать реализацию из библиотеки Loki:

Код

// Singleton 
typedef Loki::SingletonHolder<YourClass, CreateUsingNew, DefaultLifetime, ClassLevelLockable> Log;


Про то, что всё это значит можно почитать у автора библиотеки Александреску. 


Это сообщение отредактировал(а) W4FhLF - 15.2.2010, 15:35


--------------------
"Бог умер" © Ницше
"Ницше умер" © Бог
PM ICQ   Вверх
Madonna
Дата 15.2.2010, 22:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Forbidden love...
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 22.1.2009
Где: Москва

Репутация: 3
Всего: 4



borisbn, спасибо. 


W4FhLF, прочитала 30 страниц ...Александреску, мною плохо воспринимается. Гамма, которого я  почему-то называю беттой  smile , на порядок проще.

Синглтон Loki, я так понимаю потокобезопасный.
--------------------
Best regards, Madonna
PM   Вверх
SABROG
Дата 15.2.2010, 23:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Hacker
****


Профиль
Группа: Завсегдатай
Сообщений: 2481
Регистрация: 18.9.2006

Репутация: 81
Всего: 91



Тема конечно свалилась уже в другое русло, но везде пишут, что синглтоны зло, одновременно и паттерн и анти-паттерн, о недостатках синглтона можно почитать в гугле.

Цитата

У меня засада в том что после вызова потока, вызывается "мояфункция," записанная в "мояфункция.цпп", и при ее выполнении мне нужно каким то образом делать emit calcStageChange(i),
как ей передать этот сигнал ?


Я так понимаю твоя проблема в том, что ты хочешь абстрагироваться от Qt и использовать некий код, который бы не зависел от других библиотек и легко внедрялся в любую другую среду. Тогда я вижу вариант с калбэками. Нужно только изменить прототип твоей функции, чтобы можно было передать в неё указатель на каллбэк функцию. Тогда ты сможешь независимо от среды передавать состояние. Тут - 
http://www.newty.de/fpt/callback.html есть пример как можно реализовать статическую каллбэк функцию являющуюся членом класса, нужно будет только модифицировать твой класс на базе QThread. Добавить метод, который будет эмитить сигнал.

Код

void MyThread::stateChanged()
{
    emit signalStateChanged();
}


Принцип простой - передаешь в свою функцию указатель на статический метод в QThread, а в этом методе делаешь свой emit через вызов метода класса:

Код

void MyThread::myCallbackWrapper(void* object)
{
    MyThread* thread = static_cast<MyThread*>(object);
    thread->stateChanged();
}


Соответственно внутри твоей функции:

Код

void myCoolFunction(void* object, void (*objectFunction)(void* object))
{
   objectFunction(object);
}


Ну и вызов твоей функции можно таким сделать:

Код

myCoolFunction(static_cast<void*>(this), MyThread::myCallbackWrapper);

---

Хотя думаю borisbn прав, тебе нужен паттерн Observer (наблюдатель). Listener более простой вариант.

Это сообщение отредактировал(а) SABROG - 15.2.2010, 23:46


--------------------
Национальная группа Russian Federation на QtCentre.
PM MAIL   Вверх
Madonna
Дата 15.2.2010, 23:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Forbidden love...
*


Профиль
Группа: Участник
Сообщений: 107
Регистрация: 22.1.2009
Где: Москва

Репутация: 3
Всего: 4



Сразу я с шаблонами проектирования не знакома, но рано или поздно с ними приходится сталкиваться...

Есть куча вычислений в разных потоках, мне надо их отобразить в QProgressBar'ах.
Есть 2 класса. MyThread и QMainWindow.
В MyThread1 итерационные вычисления, их ход отображаются в ProgressBar1. Несколько таких пар.


Цитата(SABROG @  15.2.2010,  21:29 Найти цитируемый пост)
Я так понимаю твоя проблема в том, что ты хочешь абстрагироваться от Qt и использовать некий код, который бы не зависел от других библиотек и легко внедрялся в любую другую среду. 

Это замечательно, но у меня более простые цели. Более того, я переписываю/пишу заново код с дибилдера....там они просто добавляют аналог QProgressBar как член класса например NewThread. 


Это сообщение отредактировал(а) Madonna - 16.2.2010, 00:55
--------------------
Best regards, Madonna
PM   Вверх
borisbn
Дата 16.2.2010, 09:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 4875
Регистрация: 6.2.2010
Где: Ростов-на-Дону

Репутация: 48
Всего: 135



Madonna, если в дебилдере добавить TProgressBar* в поток, то его функции (свойства) всё равно нельзя вызывать из потока. там используется механизм передачи сообщений SendMessage, правда скрытый за функцией TThread::Synchronize. В QT лучший способ - это механизм signal/slot.
Типа:
Код

MyThread::run()
{
...
    emit progressValueChanged( value );
}

MainWindow::MainWindow()
{
    connect( &m_thread
                ,  SIGNAL( progressValueChanged( int ) )
                , ui.progressBar
                , SLOT( setValue( int ) )
                );
}

И только если необходимо сгенерить сигнал из объекта НЕ Q_OBJECT, тогда можно воспользоваться паттерном Observer (thx to 
SABROG, ) или callback'ом.


P.S. синглтоны - реально зло. кучу раз на это наталкивался при поддержке чужого кода :(

Это сообщение отредактировал(а) borisbn - 16.2.2010, 09:14


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.1417 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.