Название: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 27, 2009, 20:37 Извините если не в ту ветку написал. Ноги проблеммы растут из аплоада по фтп. Объясню проблему на примере. Есть кучка файлов, штук 200-300 т.е. много. Их надо залить на фтп по-одному. Т.е. я так понимаю надо отлавливать сигнал ftpCommandFinished и ftpCommandStarted. Причем делать это надо в отдельном потоке, иначе пока ждешь сигнала о завершении весь гуевый поток замораживается. Таким образом получается что саму заливку надо делать в отдельном потоке и по сигналам выставлять глобальную переменную в нужные значения. Примерно так:
Код: class UploadWorker : public QThread Код: ftpCommandStarted(int commandId) Название: Re: Сигналы в gui поток из дочернего Отправлено: lit-uriy от Апрель 27, 2009, 20:56 >>Вот так реализованы сигналы в главном gui потоке :
ты наверное хотел сказать слоты, а не сигналы. >> ибо сигналы "эмитируются" во вспомогательном потоке. неважно в каком потоке посылаются сигналы. Название: Re: Сигналы в gui поток из дочернего Отправлено: Rcus от Апрель 27, 2009, 20:58 Эм, а в чем проблема? сигналы работают и между потоками в двух режимах: очередь и блокировка.
А судя по постановке больше подходит что-то вроде Qt Concurrent/KDE ThreadWeaver Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 27, 2009, 21:10 да все верно - это слоты. Проблемма в том, что слоты не отрабатываются.
Т.е. они ставятся в очередь и блокируются? Название: Re: Сигналы в gui поток из дочернего Отправлено: lit-uriy от Апрель 28, 2009, 01:49 >>Проблемма в том, что слоты не отрабатываются.
Добавь себе в профайл строчку: CONFIG += console Тогда при запуске приложения у тебя консоль будет, Qt в неё сообщит если соединение сигналов неудалось. Так по крайней мере можно часть проблем отловить или отсеить. Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 28, 2009, 08:52 у меня за сборку отвечает cmake как добавить эту строку я не разумею, пока. Но я могу запустить софтину из консоли, и никаких мессаг о слотах не вываливается. Еще раз осмелюсь довести свое предположение. Новый поток => сигналы сыпятся в новом потоке и не отсылаются в главный.
ps А почему на форуме дефолтное время - Калининградское? Название: Re: Сигналы в gui поток из дочернего Отправлено: pastor от Апрель 28, 2009, 09:51 Новый поток => сигналы сыпятся в новом потоке и не отсылаются в главный. Тыкни меня носом в код, где в новом потоке испускаются сигналы? Покажи коннекты этих сигналов к слотам. Наконец, покажи больше кода. Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 28, 2009, 10:40 О! Вижу заинтересованность! Спасибо! Поехали:
Есть диалоговое окно: ftpdialog.h Код: class FtpDialog : public QDialog, private Ui::FtpFrame Код: void FtpDialog::ftpCommandStarted(int commandId) Код: UploadWorker::UploadWorker(FtpDialog *parent, QStringList *FileNameList, QFtp *ftp) Весьма признателен за желание наставить меня на путь истинный! =) вот что в консоль сыпится после запуска: Код: file opened. Transfer started Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Апрель 28, 2009, 13:52 Цитировать UploadWorker::UploadWorker(FtpDialog *parent, QStringList *FileNameList, QFtp *ftp) // упс // : QThread(parent) { this->parent=parent; // ы? this->FileNameList= new QStringList(*FileNameList); // хихи this->ftp=ftp; } void UploadWorker::run(){ int i; QFile *file; QFileInfo fi; ftp->setTransferMode(QFtp::Passive); for (i=0;i<FileNameList->count();i++){ // если закачка еще не завершилась то ждем while (parent->upl_started){ // я не знаю про межпотоковое блокирование и жду сто мс msleep(100); printf("while1"); } file = new QFile(FileNameList->at(i)); fi.setFile(FileNameList->at(i)); if (file->open(QIODevice::ReadOnly)){ printf("file opened. Transfer started\nFile is: %s\n",file->fileName().toLocal8Bit().constData()); printf("ftp state is: %d\n", ftp->state()); printf("ftp filename is: %s\n", fi.fileName().toLocal8Bit().constData()); ftp->put(file,fi.fileName()); } else { printf("file open error.\n"); } // ждем завершения закачки while (parent->upl_started){ msleep(100); printf("while2"); } file->close(); delete file; } } мои комментарии, конечно, не особо по существу, но архитектуру определённо требуется пересмотреть. глядишь, заработает :o Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 28, 2009, 14:52 Попробовал создать в новом потоке QFtp объект, и не удается законектится. Видимо QFtp как то сильно привязан к главному потоку :(
Константин, С удовольствием пересмотрю архитектуру, если вы предложите альтернативу. Суть такая: надо загружать на ftp по одному файлу из списка. Оповещание об окончании загрузки - сигнал ftpCommandFinished, ждать его в главном потоке = подвесить софтину. Загрузка из нового потока в силу архитектуры QT невозможна, есть варианты? Название: Re: Сигналы в gui поток из дочернего Отправлено: lit-uriy от Апрель 28, 2009, 17:19 >>Загрузка из нового потока в силу архитектуры QT невозможна, есть варианты?
прежде чем делать такие выводы, начни исправлять то, что Константин прописал (выделил жирным шрифтом). Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Апрель 28, 2009, 18:16 > Попробовал создать в новом потоке QFtp объект, и не удается законектится. Видимо QFtp как то сильно привязан к главному потоку
неправда > Оповещание об окончании загрузки - сигнал ftpCommandFinished, ждать его в главном потоке = подвесить софтину. ждать сигнал? это только извращенцы в qxt таким занимаются. налицо пробел в понимании механизма "сигнал-слот" > Загрузка из нового потока в силу архитектуры QT невозможна где такое сказано? не стОит делать громких заявлений, не ознакомившись как следует с документацией. а теперь самое грустное: отдельный поток не нужен, какие-то смешные глобальные переключатели не нужны, сон в цикле не нужен (и кому вообще нужен поток, который всё время спит?). а что же тогда нужно? стринглист, куфтп, слот и ассистант... ...который утверждает, что Цитировать int QFtp::put ( const QByteArray & data, const QString & file, TransferType type = Binary ) /* тут мысленно возвращаемся к первым трём цитатам */This is an overloaded member function, provided for convenience. Writes a copy of the given data to the file called file on the server. The progress of the upload is reported by the dataTransferProgress() signal. The data is transferred as Binary or Ascii depending on the value of type. The function does not block and returns immediately. The command is scheduled, and its execution is performed asynchronously. The function returns a unique identifier which is passed by commandStarted() and commandFinished(). When the command is started the commandStarted() signal is emitted. When it is finished the commandFinished() signal is emitted. и что же получается в итоге? Цитировать class FtpDialog : public QDialog, private Ui::FtpFrame { Q_OBJECT public: FtpDialog(QWidget *parent = 0); private slots: void ftpCommandFinished(int commandId, bool error); void ftpCommandStarted(int commandId); void upload(const QStringList& slFilesToUpload); private: QFtp* m_ftp; QStringList m_files; }; FtpDialog::FtpDialog(QWidget *parent) : QDialog(parent) { m_ftp = new QFtp(this); connect(m_ftp, SIGNAL(commandFinished(int, bool)), this, SLOT(ftpCommandFinished(int, bool))); connect(m_ftp, SIGNAL(commandStarted(int)), this, SLOT(ftpCommandStarted(int))); m_ftp->login(); m_ftp->setTransferMode(QFtp::Passive); // нужно ли это здесь или стОит вынести в слот начала аплоада? } void Dialog::upload(const QStringList& slFilesToUpload) { files += slFilesToUpload; commandFinished(0, false); } void FtpDialog::ftpCommandStarted(int commandId) { if(m_ftp->currentCommand() == QFtp::Put) printf("QFtp::Put Started\n"); } void FtpDialog::ftpCommandFinished(int commandId, bool error) { if(m_ftp->currentCommand() == QFtp::Put) { /* 200-300 мессэйджбоксов - это, конечно, круто! if (error) QMessageBox::information(this, tr("FTP"),"error upload"); // QString QFtp::errorString () const - а это для кого? else QMessageBox::information(this, tr("FTP"),"Downloaded file to the current ftp directory"); */ } delete m_ftp->currentDevice(); if(!m_files.isEmpty()) { QString fname = m_files.takeFirst(); QFile* file = new QFile(fname); if(file->open(QIODevice::ReadOnly)) { m_ftp->put(file, QFileInfo(fname).fileName()); } else { // можно приостановить передачу и спросить юзверя что делать // или переложить файл в конец очереди для повторной попытки, // или молча продолжить обход по списку delete *this; // интересно, будет так сиг11 или нет? :) } } } ну, примерно так. в качестве простенькой очереди сойдёт. а если делать хорошо, то нужно бы ещё использовать результат m_ftp->put(...), проверять что за m_ftp->currentDevice() собираемся удалить, добавить обработку ошибок и взаимодействите с пользователем. итого: архитектуру всё-таки следует пересмотреть. я бы вообще отделил весь этот код из диалога...диалог здесь явно ни к месту. пауза в очереди делается примитивно...надо только фантазии добавить. удачи Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 28, 2009, 18:19 >>Проблемма в том, что слоты не отрабатываются. А вот кстати интересно как эту функцию отключить? Что надо в CMakeList.txt прописать?Добавь себе в профайл строчку: CONFIG += console Название: Re: Сигналы в gui поток из дочернего Отправлено: Пантер от Апрель 28, 2009, 18:21 А вот кстати интересно как эту функцию отключить? Что надо в CMakeList.txt прописать? Аналогичная проблема.Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 28, 2009, 18:29 Спасибо за ответы, но на самом деле QFtp достаточно умен, что бы обрабатывать очередь загрузки самостоятельно. Ему можно наоткрывать кучу файлов и он будет их аплоадить по-очереди. Т.е. QFtp загружает только один файл. Объекты QFile потом удаляются через delete ftp->currentDevice(); Так что до 100 файлов можно одновременно открыть, а вот дальше, конечно могут начаться проблеммы, зависит от системы, сколько она позволяет открывать одновременно файлов.
ps Не стоит сильно придираться к коду, ясно же что в окончательном варианте QMessageBox и printf не будет. Но законектится по ftp не из главного потока пока не удалось. Попробую еще раз. Еще раз спасибо! Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Апрель 28, 2009, 18:48 про очередь QFtp я не забыл. десяток файлов я бы ещё согласился запустить одновременно, сотню - уже нет.
Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 28, 2009, 19:15 А вот кстати интересно как эту функцию отключить? Что надо в CMakeList.txt прописать? Аналогичная проблема.вроде надо поиграть с ключами gcc: -mwindows -mconsole про очередь QFtp я не забыл. десяток файлов я бы ещё согласился запустить одновременно, сотню - уже нет. Согласен. Спасибо за идею. Надеюсь, я тебя правильно понял. Попробую учесть все замечания.Название: Re: Сигналы в gui поток из дочернего Отправлено: Sergeich от Апрель 29, 2009, 23:53 Кстати, о птичках:
В нашем Родном и Незабвенном пишут Цитировать This class provides a direct interface to FTP that allows you to have more control over the requests. However, for new applications, it is recommended to use QNetworkAccessManager and QNetworkReply, as those classes possess a simpler, yet more powerful API. Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Апрель 30, 2009, 15:55 Во как! Только я начал в QFtp въезжать...
И все таки нифига не коннектится из нового треда к фтп серверу, полдня потратил. Код: class FtpWorker : public QThread В консоли глухо. Хотя и бывают такие чудеса - один раз из 20 конектится... p.s. Мне показалось, что QNetworkAccessManager больше для http подходит, или не? Название: Re: Сигналы в gui поток из дочернего Отправлено: Sergeich от Апрель 30, 2009, 21:20 А где вызов exec() в void FtpWorker::run()?
Цитировать p.s. Мне показалось, что QNetworkAccessManager больше для http подходит, или не? Если нет специфичной именно для FTP задачи, то лучше его.Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Апрель 30, 2009, 23:12 экзек не нужен :)
roginovicci, зачем поток для фтп? почему не читаешь документацию? и в чём экономия QUrl* в сравнении с const QUrl& ? Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Май 01, 2009, 09:59 Поток для фтп исключительно в качестве эксперимента. Или все таки нельзя работать с фтп из дочернего потока?
Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Май 01, 2009, 11:07 да можно же!
петлю в потоке создай. сейчас у тебя поток завершается сразу после старта... Название: Re: Сигналы в gui поток из дочернего Отправлено: roginovicci от Май 01, 2009, 14:35 Хм, не понимаю. Вообще-то поток живет. Я создавал объект QTimer который вызывает метод аля ping, который печатает в консоль сообщение о состоянии каждые 10 секунд. Сообщения исправно сыпятся. Надо внимательнее значит посмотреть. Спасибо, Константин за конструктивные ответы!
Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Май 01, 2009, 15:07 единственная причина, по которой "сообщения исправно сыпятся" - утечка памяти :)
это я заметил сразу, но промолчал...теперь вот и оно стало актуальным. посмотри на собственный код: ftp=new QFtp(); а где этот объект уничтожается? вот он и живёт себе, посылает мессаги тебе в консоль...а поток дохлый открой документацию, найди QThread и почитай про секцию методы run/start Название: Re: Сигналы в gui поток из дочернего Отправлено: Sergeich от Май 01, 2009, 21:17 Ахренеть, дайте две.
экзек не нужен :) Это стеб как я понял :)Цитировать Хм, не понимаю. Вообще-то поток живет. Вообще-то поток живет пока он не закончится, а у тебяКод: void FtpWorker::run(){ Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Май 01, 2009, 22:17 да, я это писал с саркастической ухмылкой...просто смайла такого нет :)
Название: Re: Сигналы в gui поток из дочернего Отправлено: SASA от Май 27, 2009, 10:14 да, я это писал с саркастической ухмылкой...просто смайла такого нет :) Вопрос не в тему. А зачем нужен экзек? Писал много потоков, обходился только циклами в ране.Название: Re: Сигналы в gui поток из дочернего Отправлено: pastor от Май 27, 2009, 11:59 Вопрос не в тему. А зачем нужен экзек? Писал много потоков, обходился только циклами в ране. Цитировать int QThread::exec () [protected] Enters the event loop and waits until exit() is called, returning the value that was passed to exit(). The value returned is 0 if exit() is called via quit(). It is necessary to call this function to start event handling. Название: Re: Сигналы в gui поток из дочернего Отправлено: SASA от Май 29, 2009, 18:16 А зачем нужен этот поток разбора сообщений? И как им пользоваться?
Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Июнь 03, 2009, 13:35 ивент/кастом ивент/сигнал-слот - всё это не сможет работать в потоке без петли...
Название: Re: Сигналы в gui поток из дочернего Отправлено: SASA от Июнь 03, 2009, 14:37 Что такое ивент/каст?
Если я правильно понял, то объекты, созданные в потоке, не смогут получать сообщения и у них не будут срабатывать асинхронные слоты? И ещё вопрос - а можно сделать и экзек и "вечный" цикл в одном потоке? Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Июнь 03, 2009, 15:29 И ещё вопрос - а можно сделать и экзек и "вечный" цикл в одном потоке? т.е.? чтобы работала и петля, и forever{} ?Название: Re: Сигналы в gui поток из дочернего Отправлено: SASA от Июнь 05, 2009, 15:30 И ещё вопрос - а можно сделать и экзек и "вечный" цикл в одном потоке? т.е.? чтобы работала и петля, и forever{} ?Название: Re: Сигналы в gui поток из дочернего Отправлено: pastor от Июнь 05, 2009, 15:33 Название: Re: Сигналы в gui поток из дочернего Отправлено: SASA от Июнь 05, 2009, 15:55 Нет. А как ты себе это представляешь? Да и зачем? Ну у меня есть разборщик некого сценария. Он создаёт объекты (в главном потоке). Но иногда хочется объект не в главном потоке, а в потоке разборщика.Название: Re: Сигналы в gui поток из дочернего Отправлено: ритт от Июнь 05, 2009, 16:52 и что мешает?
Название: Re: Сигналы в gui поток из дочернего Отправлено: kuzulis от Июнь 05, 2009, 18:57 Цитировать Цитата Цитата: SASA от Июнь 03, 2009, 14:37 И ещё вопрос - а можно сделать и экзек и "вечный" цикл в одном потоке? т.е.? чтобы работала и петля, и forever{} ? SASA, как вариант - сделать вечный цикл по таймеру! Тут на форусе поищи темы на слово "moveToThread" - там есть ответ. Я тоже заморачивался с этой задумкой.. И мне подсказали местные гуру (называть не буду имена :) а то буит им реклама ) .. так вот.. при таком раскладе и сигналы работают.. и "вечно" можно что - то делать... Респект и уважуха ГУРАМ! :) Название: Re: Сигналы в gui поток из дочернего Отправлено: BRE от Июнь 05, 2009, 19:39 И ещё вопрос - а можно сделать и экзек и "вечный" цикл в одном потоке? Попробуй примерно так:Код
|