Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: HunteX от Май 17, 2011, 12:43



Название: GUI-thread и Child-threads
Отправлено: HunteX от Май 17, 2011, 12:43
Здравствуйте! Есть форма с парой кнопок. При нажатии на кнопку должен создаваться поток, в котором будет происходить загрузка большого изображения (впринципе, тип работы не особо важен, главное, что работать будет долго, именно поэтому не хотелось бы, чтобы основной поток зависал). Я новичек в Qt, на C# я без проблем напишу, а с кьюти пока не совсем разобрался ... Просьба такая: накидайте небольшой (как можно проще) шаблончик, который будет выполнять действия, описанные мною выше. Спасибо!

С Уважением, Андрей.

p.s. конечно же предполагается загрузка не одного изображения, а нескольких ... вообщем нужен шаблон использования некого аналога ThreadPool в .NET


Название: Re: GUI-thread и Child-threads
Отправлено: Пантер от Май 17, 2011, 13:02
Читай (http://doc.qt.nokia.com/4.7/threads.html)


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 17, 2011, 14:34
Читай (http://doc.qt.nokia.com/4.7/threads.html)

Не сомневался :)


Название: Re: GUI-thread и Child-threads
Отправлено: Авварон от Май 17, 2011, 15:09
Фигасе, 30 долларов за книжку по каким-то тредам...


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 17, 2011, 15:53
Просьба такая: накидайте небольшой (как можно проще) шаблончик, который будет выполнять действия, описанные мною выше. Спасибо!
Весьма меркантильное желание "использовать" - но поскольку Вы абсолютно вежливы/корректны - претензий быть не может  :)

По существу - "кидать" особо нечего. Запихиваете свою содержательную часть в run QThread (наследуетесь), толкаете его с помощью метода start, принимаете результаты по сигналу finished - ну или (если есть необходимость) ждете методом wait. То есть у Вас легкое/приятное "многопоточное программирование"


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 17, 2011, 16:28
Просьба такая: накидайте небольшой (как можно проще) шаблончик, который будет выполнять действия, описанные мною выше. Спасибо!
Весьма меркантильное желание "использовать" - но поскольку Вы абсолютно вежливы/корректны - претензий быть не может  :)

По существу - "кидать" особо нечего. Запихиваете свою содержательную часть в run QThread (наследуетесь), толкаете его с помощью метода start, принимаете результаты по сигналу finished - ну или (если есть необходимость) ждете методом wait. То есть у Вас легкое/приятное "многопоточное программирование"

Спасибо за совет! У меня пара вопросов:
Цитировать
Запихиваете свою содержательную часть в run QThread
Код:
void Thread::run(Object *myobject); // так можно ?

Цитировать
принимаете результаты по сигналу finished
А вот тут можно по подробнее?

Если я передаю Thread::run(...) некий НЕ глобальный параметр, как я могу получить результат? Если объект глобальный - тут все понятно: можно послать событие о завершении Thread::run() и потом обратися к этому глобальному объекту - результату работы Thread::run(). А как быть с локальным объектом ?


Название: Re: GUI-thread и Child-threads
Отправлено: ieroglif от Май 17, 2011, 16:31
создай свой класс, наследующий QThread, переопредели в нём run() метод, в котором опиши действия выполняемые потоком (загрузка картинок)
создай объект своего класса, вызови ему start()


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 17, 2011, 16:48
Код:
void Thread::run(Object *myobject); // так можно ?
Нет, т.к. run - virtual метод. Во многих случаях хороший выбор - вообще не трогать run (по умолчанию он запускает eventLoop) а посылать ему сигналы (типа "нитка - а сделай мне то-то"). В сигналах можно указывать любые параметры  

А вот тут можно по подробнее?

Если я передаю Thread::run(...) некий НЕ глобальный параметр, как я могу получить результат? Если объект глобальный - тут все понятно: можно послать событие о завершении Thread::run() и потом обратися к этому глобальному объекту - результату работы Thread::run(). А как быть с локальным объектом ?
Выберите стратегию/метод что Вам нравится. Типичные случаи

- нитка запускается для решения одной/конкретной задачи. Перекрываете run и заряжаете параметры напр в конструкторе нитки

- нитка принимает события (может быть использована для решения одной или многих (разных) задач) - подаете параметры в сигнале

Как получить результат. Самое простое - по сигналу который испустит сама нитка когда сделает все что нужно. Если от нее ничего больше не требуется - задействовать стандартный сигнал finished


Название: Re: GUI-thread и Child-threads
Отправлено: Пантер от Май 17, 2011, 16:51
Есть еще QtConcurrent, можешь его заюзать.


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 17, 2011, 18:55
Есть еще QtConcurrent, можешь его заюзать.
Я с него начал, даже сделал то, что надо наполовину, но показалось слишком сложно и я удалил код :)

Вот, набросал класс (не ругайте сильно, так как я новичек не только в Qt, но и в C++, да и про ООП все позабывал, сейчас вспоминаю):

header
Код:
#include <QThread>
#include "cv.h"
#include "highgui.h"
#include <Magick++.h>

using namespace Magick;

class ThreadClass : QThread
{
Q_OBJECT

public:
ThreadClass(char *in_imagePath, int in_scaleWidth, int in_scaleHeight);

private slots:
// тут тоже что-то должно быть ...

protected:
void run(); // запуск потока

public:
volatile bool isLoadingDone;
volatile bool isScaledDone;

QGraphicsScene *scene;

private:
void OpenImage(); // открытие изображения
void ScaleImage(); // масштабирование изображения

char* imagePath;
Magick::Image *imImage;

int scaleWidth, scaleHeight;
};

source
Код:
#include "megatransformer.h"
#include "HunteXThreadClass.h"
#include "IplImageToQImage.h"
#include "OpenCVMagickPP.h"

ThreadClass::ThreadClass(char *in_imagePath, int in_scaleWidth, int in_scaleHeight)
{
imagePath = in_imagePath;
scaleWidth = in_scaleWidth;
scaleHeight = in_scaleHeight;

// вообщем-то флаги по умолчанию равны false
// дурная привычка задавать все поля в конструкторе :)
isLoadingDone = false;
isScaledDone = false;
}

void ThreadClass::run()
{
OpenImage();

//

ScaleImage();
}

void ThreadClass::OpenImage()
{
imImage->read(imagePath);

isLoadingDone = true;
// тут видимо надо отправить
}

void ThreadClass::ScaleImage()
{
Magick::Image *scaledImage(imImage);

scaledImage->resize(Magick::Geometry(scaleWidth, scaleHeight));
scaledImage->profile("*", Blob());

QImage *qi = IplImageToQImage(MagickImageToIplImage(scaledImage), 0);

QPixmap pixmap = QPixmap::fromImage(*qi);
QPixmap sized = pixmap.scaled(this->scaleWidth, this->scaleHeight);

scene->clear();
scene->addPixmap(sized);

delete qi;

isScaledDone = true;
}

К примеру, у меня есть функция (пускай будет foo()), в которой я получаю пути всех картинок (при помощи QFileDialog::getOpenFileNames()), как мне юзать мой класс? Догадываюсь, что для каждой картинки придется создавать объект ThreadClass и засовывать его в пул потоков ... я правильно понял? И еще помогите разобраться с сигналами и слотами ... Вопросы такие:
1. Где именно надо вызывать connect? (думаю, что в функции foo(), после создания объекта ThreadClass?)
2. Как получить событие, что функция ThreadClass::OpenImage() закончила свою работу? (наверное я зря их сделал private?)

Спасибо!


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 18, 2011, 06:52
1. Где именно надо вызывать connect? (думаю, что в функции foo(), после создания объекта ThreadClass?)
Да
2. Как получить событие, что функция ThreadClass::OpenImage() закончила свою работу? (наверное я зря их сделал private?)
Просто посылаете сигнал из run в главную нитку (connect с типом QueuedConnection)

Догадываюсь, что для каждой картинки придется создавать объект ThreadClass и засовывать его в пул потоков ... я правильно понял?
Я бы не связывался с пулом а сделал бы простую очередь. Создаете структуру/класс с теми полями что Вы сделали для ThreadClass, допустим CTask. Толкаете N ниток (idealThreadCount), run выглядит примерно так

Код
C++ (Qt)
void ThreadClass::run( void )
{
 while (true) {
  theSemaphore.acquire(); // ждем заданий от главной нитки
  theMutex.lock();            // извлекаем задание
  CTask task = theTaskList.takeAt(0);
  theMutex.unlock();
 
  if (task.imagePath == NULL)  break;  // пустое имя значит завершить нитку
  task.OpenImage();  // занимаемся имеджем
  emit signalLoad(task.imagePath); // сообщаем что загрузили
  task.ScaleImage();  // масштабим
  emit signalScaled(task.imImage); // сообщаем что готово
 }  
}
 
А главная нитка помещает в очередь
Код
C++ (Qt)
void AddImage2Process( const CTask & task )
{
 QMutexLocker locker(&theMutex);
 theTaskList.push_back(task);
 theSemaphore.release();   // есть работа для ниток-загрузчиков
}
 
И еще
scene->clear();
scene->addPixmap(sized);
Убедитесь что эти вызовы "потокобезопасны" иначе перенесите их в главную нитку


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 18, 2011, 09:25
То есть в начале из GUI-потока вызывается функция ThreadClass::AddImage2Process(), после чего выполняется ThreadClass::run() ?

Код:
CMutexLocker locker(&theMutex);
А вот насчет этого я не совсем понял: нужно отдельный класс создавать для хранения мьютекса ? То есть не совсем понятно, зачем это нужно и что выполняет этот класс и как он выглядит ... возможно имелся ввиду QMutexLocker ?

p.s. Спасибо за код! Я только начинал разбираться и хотелось бы с начала написать правильный велосипед :)


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 18, 2011, 10:10
То есть в начале из GUI-потока вызывается функция ThreadClass::AddImage2Process(), после чего выполняется ThreadClass::run() ?
Необов'язково. Если у run нет работы - он будет ждать на семафоре. AddImage2Process делает главная нитка (а не ThreadClass)

А вот насчет этого я не совсем понял: нужно отдельный класс создавать для хранения мьютекса ? То есть не совсем понятно, зачем это нужно и что выполняет этот класс и как он выглядит ... возможно имелся ввиду QMutexLocker ?
Да, "очепятка", подправил  :)


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 18, 2011, 11:01
То есть в начале из GUI-потока вызывается функция ThreadClass::AddImage2Process(), после чего выполняется ThreadClass::run() ?
Необов'язково. Если у run нет работы - он будет ждать на семафоре. AddImage2Process делает главная нитка (а не ThreadClass)

А вот насчет этого я не совсем понял: нужно отдельный класс создавать для хранения мьютекса ? То есть не совсем понятно, зачем это нужно и что выполняет этот класс и как он выглядит ... возможно имелся ввиду QMutexLocker ?
Да, "очепятка", подправил  :)

А значит, необходимо передавать в класс ThreadClass семафор и мьютекс ... скажем в конструкторе ThreadClass() ?


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 18, 2011, 11:18
А значит, необходимо передавать в класс ThreadClass семафор и мьютекс ... скажем в конструкторе ThreadClass() ?
Просто сделать их static членами ThreadClass, т.к. они должны использоваться всеми нитками которые грузят имеджи


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 18, 2011, 13:05
А значит, необходимо передавать в класс ThreadClass семафор и мьютекс ... скажем в конструкторе ThreadClass() ?
Просто сделать их static членами ThreadClass, т.к. они должны использоваться всеми нитками которые грузят имеджи

Что за ошибка не пойму? Вроде сделал:
Код:
#include <QSemaphore>
#include <QList>
#include <QMutex>

p.s. Причем, если убираю static, то все отлично компилируется

(http://img856.imageshack.us/img856/6393/errorsz.png)

код такой:
Код:
public:
    explicit MegaTransformer(QWidget *parent = 0);
~MegaTransformer();

static QSemaphore semaphore;
static QMutex mutex;
static QList<TaskClass> taskList;


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 18, 2011, 13:49
Забыли объявить сами static члены - помимо их описания в классе они должны быть в одном из cpp файлов

QSemaphore megaTransgormer::semaphore;
и.т.п


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 18, 2011, 13:57
Забыли объявить сами static члены - помимо их описания в классе они должны быть в одном из cpp файлов

QSemaphore megaTransgormer::semaphore;
и.т.п
Ура! Спасибо, а то я совсем забыл про это :( Тяжело с C# на C++ переходить


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 18, 2011, 15:07
Теперь еще одна проблема (((
У меня получилось 3 класса:
1. MegaTransformer (megatransformer.h)
2. ThreadClass (HunteXThreadClass.h)
3. TaskClass (HunteXTaskClass.h)

Хидер MegaTransformer.h:
Код:
#define QT_THREAD_SUPPORT
...
...
#include "ui_megatransformer.h"
#include "HunteXTaskClass.h" // ссылаемся на TaskClass

namespace Ui
{
    class MegaTransformer;
}

class MegaTransformer : public QMainWindow
{
Q_OBJECT

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

static QSemaphore semaphore;
static QMutex mutex;
static QList<TaskClass> taskList;

private slots:
void loadImages(); // слот, который открывает QFileDialog
void timerUpdate(); // UI
void loadingAllDone(); // пока не юзается

private:
    Ui::MegaTransformer *ui;

QTimer *timer;

void InitObjects();
void AddImageToProcess(char* imagePath);
};

Мне надо добавить объект класса ThreadClass в класс MegaTransformer, но для этого нужно добавить инклуд на файл ThreadClass (HunteXThreadClass.h)

Если я добавляю в инклуд хидер класса ThreadClass, то получаю следующую ошибку:
error C2011: ThreadClass: переопределение типа "class" ... HunteXThreadClass.h MegaTransformer

Возможно проблема в том, что у меня в файле
Код:
#include "HunteXThreadClass.h"
#include "megatransformer.h" // возможно поэтому такая ошибка, но без этого хидера никак, так как юзаются MegaTransformer::semaphore|mutex

void ThreadClass::run()
{
while (true)
{
MegaTransformer::semaphore.acquire(); // ждем заданий от главной нитки
MegaTransformer::mutex.lock();            // извлекаем задание


Тогда пробую добавить объект класса ThreadClass в файл megatransformer.cpp (главный поток).
Код:
...
#include "megatransformer.h"
#include "HunteXThreadClass.h"

QSemaphore MegaTransformer::semaphore;
QMutex MegaTransformer::mutex;
QList<TaskClass> MegaTransformer::taskList;

ThreadClass *threads;

void MegaTransformer::InitObjects()
{
     threads = new ThreadClass();
}

void MegaTransformer::loadImages()
{
     threads->run(); // а вот тут получаю ошибку (см. ниже)
}

error C2248: ThreadClass::run: невозможно обратиться к protected член, объявленному в классе "ThreadClass" MegaTransformer


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 18, 2011, 15:32
error C2248: ThreadClass::run: невозможно обратиться к protected член, объявленному в классе "ThreadClass" MegaTransformer
Правильно, для запуска надо вызывать start() который сам позовет run() (а не звать run() напрямую). Assistant-то открывайте, с такими вопросами беспокоить форум не гуд  :)


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 21, 2011, 13:52
Всё отлично! Получилось сделать программу ... реализация работает в 2-х потоках: GUI и в потоке, в котором ведется работа с изображением:

1. Загрузка (read-only)
2. Операция А (read-only)
3. Операция B (read-only)
4. Операция трансформации (write)
5. Запись результатов

Пока все делается последовательно ... Хотелось бы таким образом:
После загрузки изображения (п. 1) нужно вынести операции из п. 2, 3 (А, В) в отдельные потоки, причем запустить одновременно и дожидаться окончания этих операций. После чего выполнить последовательно операции 4, 5.

Я предполагаю сделать следующее:

Код
C++ (Qt)
void ThreadClass::run()
{
while (true)
{
MegaTransformer::semaphore.acquire(); // ждем заданий от главной нитки
MegaTransformer::mutex.lock();            // извлекаем задание
 
TaskClass task = MegaTransformer::taskList.takeAt(0);
MegaTransformer::mutex.unlock();
 
if (task.imagePath == NULL)  break;  // пустое имя значит завершить нитку
 
task.OpenImage(); // загрузка изображения
emit signalLoad(task.numberOfImage, task.imagePath); // сообщаем что загрузили
 
// ==========================================================================================
// ВИДИМО ВОТ ЭТУ ЧАСТЬ ЛУЧШЕ ВСЕГО ВЫДЕЛИТЬ В ОТДЕЛЬНЫЙ ПОТОК ? ТОЧНЕЕ ПО ПОТОКУ НА ОПЕРАЦИИ А, В
task.OperationA();  // Операция А
task.OperationВ();  // Операция В
// ==========================================================================================
 
                 emit AllOperationsFinished(...); // ждем выполнения операций А, В
 
... выполнение операции 4 + ожидание выполнения
 
... выполнение операции 5 + ожидание выполнения
}
}

Получается, что надо создавать подобный класс, наследовать от QThread и переопределять метод run(), который будет выполнять операции А, В, а также создавать объекты Mutex, Semaphore ? Причем надо дождаться выполнениях обеих операций А и В ... а уже потом начинать п. 4


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 21, 2011, 15:52
Получается, что надо создавать подобный класс, наследовать от QThread и переопределять метод run(), который будет выполнять операции А, В, а также создавать объекты Mutex, Semaphore ? Причем надо дождаться выполнениях обеих операций А и В ... а уже потом начинать п. 4
Достоинство "очереди" в том что она универсальна. Вместо того чтобы делать новый класс от QThread  (который по существу будет отличаться только обработчиком) проще расширить TaskClass. напр
Код
C++ (Qt)
bool TaskClass::Process( void )
{
 switch (mCommand) {
  case cmd_OpenImage:
    OpenImage():    // выполняем команду
    ...
    AddImage2Process(CTask(cmd_ScaleImage, ...);  // помещаем новую команду в очередь
    break;
 
  case cmd_ScaleImage:
   ...
   break;
 
  case cmd_EndOfJob:   // специальная команда - выйти
    return false;
 }
 return true;
}
 


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 21, 2011, 16:42
Достоинство "очереди" в том что она универсальна. Вместо того чтобы делать новый класс от QThread  (который по существу будет отличаться только обработчиком) проще расширить TaskClass. напр

Да, действительно, я не подумал, ведь это намного удобнее ...

Вопросик по поводу кода:
Код:
case cmd_OpenImage:
     OpenImage():    // выполняем команду
     ...
     AddImage2Process(CTask(cmd_ScaleImage, ...);  // помещаем новую команду в очередь
     break;

Так как у меня функция AddImage2Process() находится в другом классе, наверное стоит просто добавить задание в тасклист вручную при помощи push_back()?

В данный момент мое приложение осуществляет последовательную работу (загрузка, обработка, сохранение) с изображением, правильным ли будет выбрать очередь? Сейчас все операции производятся только с одним изображением, потом с другим ...
А что если мне надо реализовать последовательную загрузку изображений, но их параллельную обработку? То есть загрузили изображение - запускаем его обработку и одновременно открываем следующее изображение ... (распараллеливать загрузку изображений в моем случае не имеет смысла, так как винчестер один, получится только хуже)

У меня возник вопрос по коду, который Вы мне посоветовали использовать ранее:

Код
C++ (Qt)
QList<TaskClass> MegaTransformer::taskList;
 
void MegaTransformer::loadImages()
{
QStringList imagesPath = QFileDialog::getOpenFileNames(...)
 
for(int i=0; i<imagesPath.length();i++)
{
AddImageToProcess(imagesPath[i]);
}
 
threads->start();
}
 
void MegaTransformer::AddImageToProcess(QString imagePath)
{
QMutexLocker locker(&mutex);
 
TaskClass task; // создание объекта TaskClass
          // ... и последующее заполнение ...
 
taskList.push_back(task); // добавление задачи в очередь
semaphore.release();   // есть работа для ниток-загрузчиков
}
 
void ThreadClass::run()
{
while (true)
{
MegaTransformer::semaphore.acquire(); // ждем заданий от главной нитки
MegaTransformer::mutex.lock();        // извлекаем задание
 
TaskClass task = MegaTransformer::taskList.takeAt(0);
MegaTransformer::mutex.unlock();
 
task.OpenImage(); // загрузка изображения
emit signalLoad(task.numberOfImage, task.imagePath); // сообщаем что загрузили
// .....
}
}

1. Там ли я запускаю фунцию threads->start(); Может стоит вызывать её ранее, скажем в конструкторе MegaTransformer ?
2. Обязательно ли блокировка мьютекса ( QMutexLocker locker(&mutex); ) в функции AddImageToProcess() ? Собственно, именно это меня интересует больше всего.


Название: Re: GUI-thread и Child-threads
Отправлено: Igors от Май 21, 2011, 17:13
Так как у меня функция AddImage2Process() находится в другом классе, наверное стоит просто добавить задание в тасклист вручную при помощи push_back()?
push_back рухнет без мутекса если др. нитка в этот момент делает takeAt (или тот же push_back) - ведь контейнеры НЕ "потокобезопасны". Не стоит делать ф-цию членом класса только потому что она в нем вызывается - важнее данные какого класса ф-ция использует. Неплохо напр сделать AddImage2Process static ф-цией TaskClass

В данный момент мое приложение осуществляет последовательную работу (загрузка, обработка, сохранение) с изображением, правильным ли будет выбрать очередь? Сейчас все операции производятся только с одним изображением, потом с другим ...
А что если мне надо реализовать последовательную загрузку изображений, но их параллельную обработку? То есть загрузили изображение - запускаем его обработку и одновременно открываем следующее изображение ... (распараллеливать загрузку изображений в моем случае не имеет смысла, так как винчестер один, получится только хуже)
Явно "преждевременная оптимизация" (как говорит наш модератор). "Загрузка" - это не столько "чтение с винта" сколько распаковка считанных данных - и это имеет смысл параллелить. Так что пока "не берите в голову". А (если) надо будет - хорошо переставить задачи в очереди (т.е. очередь с приоритетом).

1. Там ли я запускаю фунцию threads->start(); Может стоит вызывать её ранее, скажем в конструкторе MegaTransformer ?
Ну работать будет и так и так, но если бороться "за чистоту рядов" - то чего это MegaTransformer сам решает толкать нитки или нет? На мой взгляд это дело того кто им управляет (главной нитки)

2. Обязательно ли блокировка мьютекса ( QMutexLocker locker(&mutex); ) в функции AddImageToProcess() ? Собственно, именно это меня интересует больше всего.
Совершенно обязательно (см. ответ на первый вопрос)


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 22, 2011, 18:10
Вот еще странная вещь ...
инициирую сигнал при помощи emit, передаю в слот double[] | std::list | QList, любое на выбор ...
Но слот сигнал не ловит ... меняю тип к примеру на int - все работает ...

Код
C++ (Qt)
class ThreadClass : public QThread
{
  ...
  signals:
    void signalHomo(std::list<double>);
}
 
ThreadClass::run()
{
 ....
 std::list<double> matrix;
 ...
 emit signalHomo(matrix);
}
 
class MegaTransformer : public QMainWindow
{
   ...
   private slots:
     void homoDone(std::list<double>);
}
 
connect(threads, SIGNAL(signalHomo(std::list<double>)), this, SLOT(homoDone(std::list<double>)), Qt::QueuedConnection);
 
void MegaTransformer::homoDone(std::list<double> matrix)
{
  // сигнал не поступает :(
}


Название: Re: GUI-thread и Child-threads
Отправлено: LisandreL от Май 22, 2011, 19:50
Но слот сигнал не ловит ... меняю тип к примеру на int - все работает ...
А в консоль приложения мы принципиально не смотрим?
Цитировать
QObject::connect: Cannot queue arguments of type 'QList<double>'
(Make sure 'QList<double>' is registered using qRegisterMetaType().)
Где угодно до первого такого connect'а:
Код
C++ (Qt)
qRegisterMetaType< QList<double> >( "QList<double>" );


Название: Re: GUI-thread и Child-threads
Отправлено: HunteX от Май 22, 2011, 20:33
Спасибо! Я на студии пишу, там 100500+ строк кода в вывод вываливает, но впредь буду туда поглядывать