Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.135.201.209] |
|
Страницы: (6) « Первая ... 3 4 [5] 6 все ( Перейти к последнему сообщению ) |
Сообщ.
#61
,
|
|
|
Цитата Flex Ferrum @ Зачем? Это сообщение может отобразить сам диалог. Зачем мессаджбокс еще показывать? бр.... я совсем запутался. диалог вообще ничего ни о чем не знает. его задача - просто например крутить часики. Да и к тому же если он отобразит его, то поверх себя. А зачем - для того. чтобы GUI-поток отобразил строку ошибки. Ведь для этого нужен был ThreadError ? Цитата Flex Ferrum @ В таком случае, у тебя: 1) Функция не завершится до тех пор, пока не отработает поток. 2) Во время работы потока будет висеть диалог и ждать его завершения. Собственно, это именно то, что тебе нужно, на сколько я смог понять. так - нужен перерыв для обмозгования я окончательно запутался. Попробую что-нибудь сделать а там будет видно |
Сообщ.
#62
,
|
|
|
Цитата zss @ я совсем запутался. диалог вообще ничего ни о чем не знает. его задача - просто например крутить часики. Да и к тому же если он отобразит его, то поверх себя. Ну а теперь предположи, что он знает о том, что запущен поток. И его задача - не только крутить часики, но и дожидаться, пока поток завершится. И либо отобразить ошибку, возникшую в процессе работы потока, либо сказать, что все в порядке и схлопнуться. Тогда все получается достаточно стройно. |
Сообщ.
#63
,
|
|
|
Цитата Flex Ferrum @ Ну а теперь предположи, что он знает о том, что запущен поток. И его задача - не только крутить часики, но и дожидаться, пока поток завершится. И либо отобразить ошибку, возникшую в процессе работы потока, либо сказать, что все в порядке и схлопнуться. Тогда все получается достаточно стройно. Ва запутались в показаниях . сначала Вы говорили, что нужно диалог создавать в отдельном потоке. После что нужно в потоке обрабатывать данные. А на последнем допросе - диалог должен знать обо всем Шутка... Ну я так понял что сигналы нужны только диалогу для того. чтобы прихлопнуться или сообщить об ошибке ? Принципе логично. Попробую и скажу что получилось. Спасибо за долго общение |
Сообщ.
#64
,
|
|
|
Если функцию можно выполнить в другом потоке, т.е. она, например, не работает напрямую с gui, то тогда лучше так и сделать. О завершении другого потока можно узнать по его сигналу finished () (если это наследник QThread) По этому сигналу можно закрыть диалог. Если диалогу нужно знать что-то о вычиляющем потоке, то тогда можно сделать дополнительный сигнал в вычисляющем потоке, который будет информировать gui-поток (в частности - наш диалог) о текущем состоянии дел. |
Сообщ.
#65
,
|
|
|
Цитата gryz @ Если функцию можно выполнить в другом потоке, т.е. она, например, не работает напрямую с gui, то тогда лучше так и сделать. О завершении другого потока можно узнать по его сигналу finished () (если это наследник QThread) По этому сигналу можно закрыть диалог. Если диалогу нужно знать что-то о выполняемом процессе, то тогда можно сделать дополнительный сигнал в вычисляющем потоке, который будет информировать gui-поток (в частности - наш диалог) о текущем состоянии дел. я долго размышлял, но пока руки не дошли до этого. Если не сложно - простейший работающий пример со Sleep можно ? |
Сообщ.
#66
,
|
|
|
Цитата zss @ я долго размышлял, но пока руки не дошли до этого. Если не сложно - простейший работающий пример со Sleep можно ? Что за Sleep, зачем он? |
Сообщ.
#67
,
|
|
|
Цитата gryz @ Что за Sleep, зачем он? эмитация долгой функции. пусть например Sleep (50000) - 50 сек. |
Сообщ.
#68
,
|
|
|
диалог запускаем методом exec(), перед его запуском стартуем вычисляющий поток
Добавлено завтра попробую пример написать. сейчас домой - на работе засиделся. |
Сообщ.
#69
,
|
|
|
Цитата gryz @ диалог запускаем методом exec(), перед его запуском стартуем вычисляющий поток а слот диалога вешаем на сигнал завершения потока как сказал Flex Ferrum ? |
Сообщ.
#70
,
|
|
|
я имел в виду это:
#include <QApplication> #include <QThread> #include <QMessageBox> #include <QtDebug> class MyThread : public QThread { public: void run() { qDebug() << "thread started"; sleep(5); qDebug() << "thread finished"; } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); QMessageBox * d = new QMessageBox; QThread * th = new MyThread; QObject::connect(th, SIGNAL(finished()), d, SLOT(accept())); th->start(); d->exec(); th->wait();//если нажали ок, то надо дождаться завершения выполнения потока } |
Сообщ.
#71
,
|
|
|
я про это понял. Тут еще возникла сложность, что нужно создавать для каждого метода свой потоковый класс и свой слот обработки.
Много кода лишнего получается ... |
Сообщ.
#72
,
|
|
|
Цитата zss @ Тут еще возникла сложность, что нужно создавать для каждого метода свой потоковый класс и свой слот обработки. Зачем? Можно же поместить объект в поток (если объект наследник QObject), сделать его методы слотами и асинхронно вызывать их при помощи QMetaObject::invokeMethod(). Только тут надо учесть, что возвращаемыми значениями воспользоваться неполучится. Прийдется использовать сигналы для сообщении о результате, если он нужен. при старте каждого метода испускать сигнал methodStarted(QString methodName), при завершении метода испускать сигнал methodFinished(). Можно сделать сигнал methodFinished(QVarinat rez), в rez будет храниться результат выполнения метода. |
Сообщ.
#73
,
|
|
|
Цитата gryz @ Можно же поместить объект в поток (если объект наследник QObject), не наследник, но никто не мешает его хранить внутри объекта-потока. Цитата gryz @ сделать его методы слотами и асинхронно вызывать их при помощи QMetaObject::invokeMethod(). хорошая идея... Цитата gryz @ Только тут надо учесть, что возвращаемыми значениями воспользоваться неполучится. Прийдется использовать сигналы для сообщении о результате, если он нужен. Почему ? Цитата gryz @ при старте каждого метода испускать сигнал methodStarted(QString methodName), при завершении метода испускать сигнал methodFinished(). Можно сделать сигнал methodFinished(QVarinat rez), в rez будет храниться результат выполнения метода. а можно примерчик - мне кажется интересная идея. З.Ы. Только не понятно что должен делать слот потока ? |
Сообщ.
#74
,
|
|
|
Цитата zss @ Почему ? Потому что это асинхронный вызов. Он происходит не сразу, а при возврате в цикл обработки сообщений. Так что сразу результата никакого нет. А нам нужно продолжить выполнение. В Qt 4.3 появился тип вызова (точнее, это тип соединения) Qt::BlockingQueuedConnection, но он не подойдет для вызова из gui потока. Добавлено Вот примерчик //client.h #ifndef CLIENT_H #define CLIENT_H #include <QObject> #include <QVariant> #include <QPushButton> #include <QThread> #include <QMessageBox> #include <QtDebug> class Client: public QObject { Q_OBJECT public slots: bool start()const { qDebug() << "start() started"; emit methodStarted("start()"); int sum = 0;//сложнейшие вычисления for(int i = 0; i < 100000; ++i) for(int j = 0; j < 10000; ++j) sum += j * i; bool rez = true; qDebug() << "start() finished"; emit methodFinished(QByteArray("true"));//всегда последняя перед return операция. //оказалось, что QVariant нельзя передавать в //в соединениях типа Qt::QueuedConnection (qt4.2.2). //Можно упаковывать результат в QByteArray используя QDataStream. //туда же можно запихнуть имя метода start(). //Еще как вариант можно использовать различные синалы //для различных типов возвращаемых значений. return rez; } //... signals: void methodStarted(QString methodName)const; void methodFinished(QByteArray rez)const; }; class RunnableThread: public QThread { public: void run()//в QThread этот метод не определен, поэтому приходится наследоваться { exec(); } }; class DummyMainWindow: public QWidget { Q_OBJECT public: DummyMainWindow() { QPushButton * startBtn = new QPushButton(tr("Start"), this); theClient = new Client; theWorkerThread = new RunnableThread; theWorkerThread->start(); theClient->moveToThread(theWorkerThread); connect(startBtn, SIGNAL(pressed()), SLOT(invokeStart())); connect(theClient, SIGNAL(methodStarted(QString)), SLOT(showDialog(QString))); connect(theClient, SIGNAL(methodFinished(QByteArray)), SLOT(processResult(QByteArray))); theInfoDialog = new QMessageBox(this); theInfoDialog->setStandardButtons(QMessageBox::NoButton); } ~DummyMainWindow() { theWorkerThread->quit(); theWorkerThread->wait(); delete theWorkerThread; delete theClient; } private slots: void invokeStart() { //можем запомнить текущий вызываемый метод в члене класса, //тогда в методе processResult будем знать, какой метод был вызван, //чтобы правильно интепретировать результат QMetaObject::invokeMethod(theClient, "start"); } void showDialog(QString text) { theInfoDialog->setText(text + tr(" is running now")); theInfoDialog->exec(); } void processResult(QByteArray rez) { theInfoDialog->accept(); //делаем, что хотим с rez } private: Client * theClient; RunnableThread * theWorkerThread; QMessageBox * theInfoDialog; }; #endif //main.cpp #include <QtGui/QApplication> #include "client.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); DummyMainWindow mw; mw.show(); return a.exec(); } Добавлено В данной реализации в программе всегда запущено 2 потока: gui и вычисляющий. В принципе, можно сделать так, чтобы вычисляющий запускался при необходимости вычислений, а после - завершался. |
Сообщ.
#75
,
|
|
|
gryz, спасибо за код, но не все подойдет
в #49 описано почему. Разные методы, разные сигнатуры и разные возвращаемые значения... |