Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Поток [Qt]


Автор: BIV 23.10.2010, 17:54
Всем доброе время суток!
У меня проект состоит из основного окна MainWindow и окна диалога Dialog. В оене диалога один компонент label.
Проблема в том, что в файле диалогового окна Dialog.cpp есть функция, которая очень долго выполняется. Получается такая ситуация, что при вызове из главного окна диалоговое окно, то диалоговое окно появиться не сразу, а спустя некоторое время. Пришел к выводу, что нужно создавать поток.
Идея такая: пусть запуститься сразу окно с просьбой подождать выполнение, и через некоторое время выводятся данные.
Вот возникает проблема передачи данных в label, так как Dialog и MyThread разные классы. Как это сделать?

Вот мои попытки реализовать свой замысел:
Заголовочный файл  dialog.h:
Код

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QThread>

namespace Ui {
    class Dialog;
    class MyThread;
}

class MyThread : public QThread
{
    Q_OBJECT

protected:
    void run();

public:
    explicit MyThread(QWidget *parent = 0);
    QString get();

private:
    Ui::Dialog *ui;
};

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    QString get();

private:
    Ui::Dialog *ui;
};

#endif // DIALOG_H


dialog.cpp:
Код

#include "dialog.h"
#include "ui_dialog.h"
#include <QtNetwork>

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);


}

void MyThread::run()
{
    QString str = get();
    if(str=="")ui->label->setText("Не определено");
    else ui->label->setText(str);
}



   QString MyThread::get()
    {
            QString strIP = "Выполнено соединение";
            return strIP;
    }

Dialog::~Dialog()
{
    delete ui;
}



Автор: null56 24.10.2010, 01:28
Цитата(BIV @  23.10.2010,  17:54 Найти цитируемый пост)
Вот возникает проблема передачи данных в label, так как Dialog и MyThread разные классы. Как это сделать?

что тебе мешает сделать MyThread переменной - членом класса Dialog
Код

class MyThread : public QThread
{
//...
signals:
    void sendSignal(QString newLabelText);
};

class Dialog
{
public:
//...

public slots:
   void changeLabelText(QString newLabelText)
   {
    // РЕАЛИЗАЦИЯ В *.cpp
       m_Label.setText(newLabelText);
   }


private:
    MyThread m_DialogThread;
    QLabel m_Label;
};

и передавать данные, как сообщения (customEvent) или через механизм сигналов/слотов от нити к диалогу
Код

// соедини сигнал от потока со слотом диалога (можно прямо в конструкторе класса Dialog)
connect(&m_DialogThread, SIGNAL(sendSignal(QString)), SLOT(changeLabelText(QString)));

генери новые значения в потоке в виде сингалов, когда тебе это нужно
Код

void MyThread :: run()
{
//...
   QString new_label("Hi");
   emit  sendSignal(new_label);
}


ЗЫ: у Qlabel есть слот на изменение текста
Код

void    setText ( const QString & )

но тут объект передается по ссылке и без дополнительных средств синхронизации объекта QString тут не обойтись

Автор: BIV 24.10.2010, 09:56
Ошибочки вылетают

Файл .h
Код

class Dialog : public QDialog
{
    ....

private:
    Ui::Dialog *ui;
    MyThread m_DialogThread;
};


Файл .cpp
Код

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog),
    m_DialogThread(new MyThread)
{
    ui->setupUi(this);
    connect(&m_DialogThread, SIGNAL(sendSignal(QString)), SLOT(changeLabelText(QString)));
}


Я наверно неправильно определяю ссылку на 4 строчке m_DialogThread(new MyThread)
Без этой записи тоже ругается. Как правильно задавать?

Автор: null56 24.10.2010, 14:44
оператор new нужен только для указателей на объекты. убери 4 строчку. если будут ошибки, опубликуй их сюда, мы не телепаты

Автор: BIV 24.10.2010, 15:14
Ошибка. Указывает на 3 строчку
undefined reference to 'MyThread::MyThread(QWidget*)'
collect2: Id returned 1 exit status

неопределенная ссылка на 'MyThread::MyThread(QWidget*)'
collect2: Идентификатор возвратил 1 статусу выхода

Автор: null56 24.10.2010, 16:14
нет тела конструктора или не компилится cpp файл в котором определен конструктор класса MyThread. у вас конструктор где - нибудь определен?
Код

MyThread::MyThread(QWidget*)
{
 //...
}

Автор: BIV 24.10.2010, 17:24
Точно, конструктора небыло. Я добавил пустой конструктор. Оши бок не стало, но и лучше тоже

Вот файл .h
Код

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QThread>

namespace Ui {
    class Dialog;
    class MyThread;
}

class MyThread : public QThread
{
    Q_OBJECT

protected:
    void run();

public:
    explicit MyThread(QWidget *parent = 0);
    QString get();

signals:
    void sendSignal(QString newLabelText);

};

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    QString get();

public slots:
   void changeLabelText(QString);

private:
    Ui::Dialog *ui;
    MyThread m_DialogThread;
};

#endif // DIALOG_H


Файл .cpp
Код

#include "dialog.h"
#include "ui_dialog.h"
#include <QtNetwork>

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(&m_DialogThread, SIGNAL(sendSignal(QString)), SLOT(changeLabelText(QString)));
}

MyThread::MyThread(QWidget*)
{
    //Конструктор который ничего не делает
}

void Dialog::changeLabelText(QString newLabelText)
{
     ui->label->setText(newLabelText);
}


void MyThread::run()
{
    //...
    QString str = get();
    //ui->label->setText(str);
    emit  sendSignal(str);
}

QString MyThread::get()
    {
        QString strIP;
        QNetworkAccessManager manager;
        QNetworkReply *reply = manager.get( QNetworkRequest( QUrl( "http://www.grio.ru/myip.php" ) ) );

        QEventLoop loop;
        QObject::connect( reply, SIGNAL( finished() ), &loop, SLOT( quit() ) );
        loop.exec();

        // Проверяем состояние ответа
        if( reply->error() != QNetworkReply::NoError )
            return strIP="Не определено";    // Ошибка

        // Читаем полученные данные в data
        QByteArray data = reply->readAll();

        // Разбираем полученные данные, находим свой ip и возвращаем его
        strIP = QString(data);
                return strIP;
    }

Dialog::~Dialog()
{
    delete ui;
}

Автор: null56 24.10.2010, 21:53
dialog.h (классы диалога и дочернего потока)
Код

#include <QDialog>
#include <QThread>

namespace Ui {
    class Dialog;
}

class MyThread : public QThread
{
    Q_OBJECT

public:
    MyThread() {}
    ~MyThread() {}
    QString get();
    void run();

signals:
    void sendSignal(QString newLabelText);

};

class Dialog : public QDialog {
    Q_OBJECT
public:
    Dialog(QWidget *parent = 0);
    ~Dialog();
    void show();

protected slots:
   void changeLabelText(QString);

private:
    Ui::Dialog *ui;
    MyThread m_MyThread;

};


dialog.cpp
Код

// тут делай свои действия
QString MyThread :: get()

    QString str("hi");
    return str;
}

void MyThread :: run()
{
    QString new_label_text = get();
    emit sendSignal(new_label_text);
}

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    connect(&m_MyThread, SIGNAL(sendSignal(QString)), SLOT(changeLabelText(QString)));
}

// перегрузим метод вызова диалога, предворив сам вызов запуском потока
void Dialog::show()
{
    m_MyThread.start();
    QDialog :: show();
}



Dialog::~Dialog()
{
    delete ui;
}

// обработка слота, присваиваем метке полученную из потока строку
void Dialog::changeLabelText(QString str)
{
    ui->label->setText(str);
}


main.cpp
Код

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();
    return a.exec();
}

Автор: BIV 24.10.2010, 23:05
Сделал все как Вы писали, но  проблема никак не решается: не срабатывает void MyThread :: run()
Я решил отправить мою заготовку, так как по нему, думаю, будет проще решать проблему. Значит основная проблема, это сразу при вызове открыть диалоговое окно, а уже как прога получит данные, тогда и внесет.
Моя программка еще разрабатывается, так что там еще много чего пока не работает.

http://file.qip.ru/file/WW-UCZc1/Admin1.html ( 33.31 Kb )

Запуск того диалогового окна через меню Сервис->Внешний IP

Автор: null56 24.10.2010, 23:14
вы диалог вызываете через exec, в моем примере я перегружал метод show
добавьте перегрузку метода exec в dialog
Код

// *.h
class Dialog
{
 ...
 int exec();
};

// *.cpp
int Dialog::exec()
{
    m_DialogThread.start();
    return QDialog :: exec();
}

Автор: BIV 24.10.2010, 23:33
Ууффф, что надоsmile
Спасибо, Вам большое за такую колосальную работу. Очень помогли

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)