Russian Qt Forum
Ноябрь 26, 2024, 16:29 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Зависает интерфейс программы нужна помощь....  (Прочитано 13136 раз)
AntonUfo
Гость
« : Декабрь 21, 2009, 15:31 »

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

Код:
//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();
        }
    }
}

« Последнее редактирование: Декабрь 22, 2009, 10:49 от AntonUfo » Записан
niXman
Гость
« Ответ #1 : Декабрь 21, 2009, 15:49 »

методы напутал Подмигивающий
тот метод, в котором выполняются вычисления, не является субклассом QThread
Записан
AntonUfo
Гость
« Ответ #2 : Декабрь 21, 2009, 15:52 »

методы напутал Подмигивающий
тот метод, в котором выполняются вычисления, не является субклассом QThread

во блин, а где будет правильно выполнять ? я не очень шарю пока в программирование воообще, учусь Грустный
Записан
niXman
Гость
« Ответ #3 : Декабрь 21, 2009, 15:56 »

ты же по книжке учишься? а там написано - в виртуальном защищенном методе void run(), в классе потомке, производном от QThread
Записан
AntonUfo
Гость
« Ответ #4 : Декабрь 21, 2009, 16:03 »

ты же по книжке учишься? а там написано - в виртуальном защищенном методе void run(), в классе потомке, производном от QThread

спасибо понял..., до меня как то с трудом все доходит.... Плачущий
Записан
SASA
Гость
« Ответ #5 : Декабрь 21, 2009, 16:13 »

QtConcurrent. Спецом для таких вещей.
Записан
AntonUfo
Гость
« Ответ #6 : Декабрь 21, 2009, 17:54 »

ты же по книжке учишься? а там написано - в виртуальном защищенном методе void run(), в классе потомке, производном от QThread

черт все равно виснет, я перенес вычисления в защищенный метод void run(),

добавил в mythread.cpp
Код:
    connect(&thread, SIGNAL(transactionStarted(const QString &)),
            statusBar(), SLOT(showMessage(const QString &)));

Код:
Run::Run()
{
//теперь пустой
}


void TransactionThread::run() //теперь вот такой
{
    Transaction *transact = 0;
    forever {
        {
            QMutexLocker locker(&mutex);

            if (transactions.isEmpty())
                transactionAdded.wait(&mutex);
            transact = transactions.dequeue();
            if (transact == EndTransaction)
                break;

 //           oldImage = currentImage;
        }

        emit transactionStarted(transact->message());
///////////////////// положил вот сюда////////////////

//в этой функции будем выполнять долгие расчеты, при этом интерфейс приложения зависать не должен, а он зависает....!!!
    int i=1;
int a = 10;
while (a !=i){
a=a/i;
i++;
}

//вывожу на интерфейс значения счетчика//
QString str;
str = QString::number(i,10);
emit transactionRun(str)

        delete transact;

        {
            QMutexLocker locker(&mutex);
//           currentImage = newImage;
            if (transactions.isEmpty())
                emit allTransactionsDone();
        }
    }
}



значения счетчика на интерфейс выводятся, но сдвинуть его никуда немогу.....
Записан
Vass
Гость
« Ответ #7 : Декабрь 21, 2009, 20:40 »

Вот вы пишите:

Код:
//вывожу на интерфейс значения счетчика//
.....
emit transactionRun(str)

а я вообще в коде у Вас такого сигнала не нахожу, к чему он подключен?
Записан
AntonUfo
Гость
« Ответ #8 : Декабрь 22, 2009, 10:51 »

Вот вы пишите:

Код:
//вывожу на интерфейс значения счетчика//
.....
emit transactionRun(str)

а я вообще в коде у Вас такого сигнала не нахожу, к чему он подключен?

подправил, но проблема осталась, мне необходимо выводить промежуточные значения при долгих расчетах на интерфейс без его залипания..
Записан
Vass
Гость
« Ответ #9 : Декабрь 22, 2009, 11:41 »

Читаем Assistant, а там написано:

Код:
void QThread::run ()   [virtual protected]

The starting point for the thread. After calling start(), the newly created thread calls this function. The default implementation simply calls exec().

You can reimplemented this function to do other useful work. Returning from this method will end the execution of the thread.

---------

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.

See also quit() and exit().

А это значит, что чтобы все работало, Вам просто необходимо где-то вызвать exec();
Но вот где я чего-то не пойму никак.

Дело в том что из exec(); он не выйдет пока не будет вызван слот quit();

------

О! кажется сообразил. в общем Вам надо ваш цикл вынести в отдельный слот, который будет вызываться по сигналу started(); соответственно когда будете выходить из цикла вызывайте слот quit();
« Последнее редактирование: Декабрь 22, 2009, 11:45 от Vass » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Декабрь 22, 2009, 17:44 »

Код:
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);
}
Смотрим:
a = 10, i = 1
a = 10, i = 2
a = 5, i = 3
a = 1, i = 4
a = 0, i = 5
a = 0, i = 6
Бесконечный цикл поскольку (a !=i)  всегда. Поэтому что имеем то и имеем - да, интерфейс не  виснет, я могу двигать и сайзить главное окно. Но вычисления (и нитка) никогда не кончатся

Примечание: не беда если много исходников но пожалуйста в следующий раз прикрепляйте их zip файлом компилябельного примера (выдирать через copy/paste никому не хочется  Улыбающийся)
 
Записан
AntonUfo
Гость
« Ответ #11 : Декабрь 23, 2009, 11:22 »

Код:
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);
}
Бесконечный цикл поскольку (a !=i)  всегда. Поэтому что имеем то и имеем - да, интерфейс не  виснет, я могу двигать и сайзить главное окно. Но вычисления (и нитка) никогда не кончатся

я понимаю что цикл бесконечный это не важно, у меня не получается послать сигнал на форму из (QString Run::apply(const QString &str)), как это можно сделать.....
сейчас программа посылает сигнал только из потока (void TransactionThread::run() ), но мне необходимо посылать на форму значения ну к примеру I
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Декабрь 23, 2009, 15:42 »

я понимаю что цикл бесконечный это не важно, у меня не получается послать сигнал на форму из (QString Run::apply(const QString &str)), как это можно сделать.....
сейчас программа посылает сигнал только из потока (void TransactionThread::run() ), но мне необходимо посылать на форму значения ну к примеру I
В нитке у Вас 2 цикла и оба бесконечные. Поэтому строка во внешнем цикле
Код:
emit allTransactionDone();
не получит управления никогда т.к. она стоит после вложенного цикла а он никогда не кончится
Записан
AntonUfo
Гость
« Ответ #13 : Декабрь 23, 2009, 16:04 »

я понимаю что цикл бесконечный это не важно, у меня не получается послать сигнал на форму из (QString Run::apply(const QString &str)), как это можно сделать.....
сейчас программа посылает сигнал только из потока (void TransactionThread::run() ), но мне необходимо посылать на форму значения ну к примеру I
В нитке у Вас 2 цикла и оба бесконечные. Поэтому строка во внешнем цикле
Код:
emit allTransactionDone();
не получит управления никогда т.к. она стоит после вложенного цикла а он никогда не кончится

прикрипил все исходники,  с ними будет более понятно. После запуска нитки выполняется QString Run::apply(const QString &str)), я знаю что он бесконечен в цикле, мне это не важно, я так сделал специально, мне нужно понять каким образом я могу передать из QString Run::apply(const QString &str)) сигнал в статус бар формы во время каждой итерации бесконечного цикла и каким образом этот сигнал принять в форме
ЗЫ: из void TransactionThread::run() сигнал в статус бар формы приходит нормально, я не знаю как его послать именно из QString Run::apply(const QString &str))
« Последнее редактирование: Декабрь 23, 2009, 16:08 от AntonUfo » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Декабрь 23, 2009, 17:35 »

прикрипил все исходники,  с ними будет более понятно. После запуска нитки выполняется QString Run::apply(const QString &str)), я знаю что он бесконечен в цикле, мне это не важно, я так сделал специально, мне нужно понять каким образом я могу передать из QString Run::apply(const QString &str)) сигнал в статус бар формы во время каждой итерации бесконечного цикла и каким образом этот сигнал принять в форме
ЗЫ: из void TransactionThread::run() сигнал в статус бар формы приходит нормально, я не знаю как его послать именно из QString Run::apply(const QString &str))
Это легко сделать "технически" (см. attachment). Но это идет вразрез с логикой примера, с именами переменных и.т.п. Подразумевается что "transaction" (класс Run) - это неделимая единица вычислений, которая не должна ничего знать об UI, не должна посылать сигналов и.т.п. Всем этим занимается класс TransactionThread.

Поэтому посмотрите как но не используйте, уберите бесконечность в Run но оставьте ее в TransactionThread
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.117 секунд. Запросов: 23.