Russian Qt Forum

Qt => Многопоточное программирование, процессы => Тема начата: kadr от Август 27, 2010, 13:24



Название: QprogressBar в отдельном потоке!
Отправлено: kadr от Август 27, 2010, 13:24
Привет всем! Помогите разобраться с проблемой!
Мне надо что бы копировании файла,  прогрессбар отображал ход выполнения копирования!
Из найденого в интернете:
Создаю класс:
Код:
class MyThread : public QThread
{
public:
virtual void run();

};

Далее в программе создаю виджет с размещенными на нем метками и прогрессбарами:
Код:
void Linux_Comander::progress_bar(QString begin_path, QString end_path)
{
    MyThread run;


    QWidget *dialog_progress = new QWidget;
    progres = new QProgressBar(this);
    progres_all = new QProgressBar(this);

    QVBoxLayout *main_layt = new QVBoxLayout;
    QVBoxLayout *progress = new QVBoxLayout;
    QVBoxLayout *progress_all = new QVBoxLayout;
    QVBoxLayout *path_l = new QVBoxLayout;
    QVBoxLayout *path_r = new QVBoxLayout;
    QHBoxLayout *buttons = new QHBoxLayout;
    QLabel *path = new QLabel;
    QLabel *path_f = new QLabel;

    QPushButton *button_cancel = new QPushButton;

    button_cancel->setText("Закрыть");
    button_cancel->setFont(QFont("",8,72,false));

    buttons->addWidget(button_cancel);
    buttons->setContentsMargins(150,1,150,1);

    progres->setAlignment(Qt::AlignHCenter);
    progres_all->setAlignment(Qt::AlignHCenter);

    progress->addWidget(progres);
    progress_all->addWidget(progres_all);

    path_l->addWidget(path);
    path_r->addWidget(path_f);

    main_layt->addLayout(path_l);
    main_layt->addLayout(path_r);
    main_layt->addLayout(progress);
    main_layt->addLayout(progress_all);
    main_layt->addLayout(buttons);



    dialog_progress->setGeometry((x/2)-(450/2),(y/2)-(150/2),450,150);
    dialog_progress->setWindowModality(Qt::ApplicationModal);
    dialog_progress->setStyleSheet("background-color: #CCCCCF");
    dialog_progress->setWindowTitle("Копирование");
    dialog_progress->setFixedSize(450,150);
    dialog_progress->setLayout(main_layt);
    dialog_progress->show();


    path->setText(begin_path);
    path_f->setText(end_path);

    QFile file,f;

    file.setFileName(model_l->filePath(ui->left_pole->currentIndex()));
    file.open(QIODevice::ReadOnly);
    f.setFileName(line_finish->text()+"/"+model_l->fileName(ui->left_pole->currentIndex()));
    f.open(QIODevice::WriteOnly);

    progres->setMaximum(file.size());


    while (!file.atEnd())
    {
        f.write(file.readLine());
        run.start(QThread::HighPriority);
        run.wait();

    }
    connect(button_cancel,SIGNAL(clicked()),dialog_progress,SLOT(close()));

}
Здесь я построчно копирую файл, и вызываю новый поток!
Код:
void MyThread::run()
{
    qDebug() << "asdasd";

}
Так вот собствено проблема в том, что я не знаю как передовать в поток нужные мне переменные?
Мне надо что бы на прогрессбаре отображался ход копирования, и при этом не вешалось главное окно!


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kuzulis от Август 27, 2010, 13:57
На пример. В аттаче.

Процесс копирования ты должен делать в потоке Run! т.е. там где в примере цикл forever.


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kadr от Август 27, 2010, 14:37
На пример. В аттаче.

Процесс копирования ты должен делать в потоке Run! т.е. там где в примере цикл forever.
Все это хорошо, а как туда передовать параметры? Например что копировать и куда копировать.


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kuzulis от Август 27, 2010, 15:17

*.h
Код:
class Thread : public QThread
{
    Q_OBJECT

signals:
    void signalForProgressBar(int);
public:
    Thread(const QString &copyFrom, const QString &copyTo, QObject *parent = 0);
    ~Thread();
protected:
    void run();
private:
    QString m_from;
    QString m_to;
};

*.cpp
Код:
Thread::Thread(const QString &copyFrom, const QString &copyTo, QObject *parent)
    : QThread(parent), m_from(copyFrom), m_to(copyTo)
{
}

Thread::~Thread()
{

}

void Thread::run()
{
    //тут копируешь, у тебя есть откуда копировать m_from и куда m_to
    //по мере копирования эммитиш сигнал   emit signalForProgressBar(i);

}


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kadr от Сентябрь 01, 2010, 10:03
Впринципе файл копируется но окно в котором должен отображаться ход процесса копирования, то есть где прогресс бар, оно зависает на время копирования, на нем ничего не видно. Да и как мне передовать ход выполнения копирования на прогресс бар, то есть, что бы он заполнялся.
Получается что копирование запускается в отдельном потоке, а основной поток в котором создается диалоговое окно с барами оно ждет выполнения - завершения потока копирования

Код:
void Linux_Comander::progress_bar(QString begin_path, QString end_path)//функция отображения хода копирования
{


//динамическое создание диалога со всем небходимым
    QWidget *dialog_progress = new QWidget;//основной виджет
    QProgressBar *progres = new QProgressBar;//прогресс бар первый
    QProgressBar *progres_all = new QProgressBar;//прогресс бар общий

    QVBoxLayout *main_layt = new QVBoxLayout;//вертикальный лаут
    QVBoxLayout *progress = new QVBoxLayout;//вертикальный лаут
    QVBoxLayout *progress_all = new QVBoxLayout;//вертикальный лаут
    QVBoxLayout *path_l = new QVBoxLayout;//вертикальный лаут
    QVBoxLayout *path_r = new QVBoxLayout;//вертикальный лаут
    QHBoxLayout *buttons = new QHBoxLayout;//горизонтальный лаут
    QLabel *path = new QLabel;//лайблы
    QLabel *path_f = new QLabel;//

    QPushButton *button_cancel = new QPushButton;//кнопка

    button_cancel->setText("Закрыть");//текст на кнопке
    button_cancel->setFont(QFont("",8,72,false));//шрифт на кнопке

    buttons->addWidget(button_cancel);//присваеваем лауту виджет кнопки
    buttons->setContentsMargins(150,1,150,1);//установливаем поля

    progres->setAlignment(Qt::AlignHCenter);//выравниваем текст на прогресс баре посередине
    progres_all->setAlignment(Qt::AlignHCenter);//на втором тоже

    progress->addWidget(progres);//присваиваем лауту виджет пргресс бара
    progress_all->addWidget(progres_all);//и воторого то же

    path_l->addWidget(path);//присваиваем лауту виджет лабла
    path_r->addWidget(path_f);//и второго
    //присваиваем основному лауту все лауты
    main_layt->addLayout(path_l);
    main_layt->addLayout(path_r);
    main_layt->addLayout(progress);
    main_layt->addLayout(progress_all);
    main_layt->addLayout(buttons);



    dialog_progress->setGeometry((x/2)-(450/2),(y/2)-(150/2),450,150);//устанавливаем диалог в центре экрана
    dialog_progress->setWindowModality(Qt::ApplicationModal);//делаем окно модальным
    dialog_progress->setStyleSheet("background-color: #CCCCCF");//цвет диалога
    dialog_progress->setWindowTitle("Копирование");//заголовок
    dialog_progress->setFixedSize(450,150);//фиксированый размер
    dialog_progress->setLayout(main_layt);//ресайз основного лаута
    dialog_progress->show();//показываем его


    path->setText("Из: "+begin_path);//лайблам присваиваем текст
    path_f->setText("В: "+end_path);//второму тоже


    MyThread(str.trimmed(),str1.trimmed(),0).start(QThread::HighPriority);// запускает второй поток в котором происходит копирование файлов

    connect(button_cancel,SIGNAL(clicked()),dialog_progress,SLOT(close()));//при нажатии на кнопку закрыть, закрыть диалог

}


Код:
MyThread::MyThread(const QString &copyFrom, const QString &copyTo, QObject *parent)
    : QThread(parent), m_from(copyFrom), m_to(copyTo)
{

  
}

void MyThread::run()
{


    QFile file,f;
    int i = 0;

               file.setFileName(m_from);//присваеваем переменной file имя файла на диске
               qDebug() << file.fileName();
               qDebug() << file.open(QIODevice::ReadOnly);//открываем его на чтение

               f.setFileName(m_to);//аналогично предыдущему
               qDebug() << f.fileName();
               qDebug() << f.open(QIODevice::WriteOnly);//на запись


               while (!file.atEnd())//запускаем цикл в котором файл копируется построчно
                {
                  
                   f.write(file.readLine());//построчное записывание
                   emit signalForProgressBar(i);

                   i++;
                }

}

MyThread::~MyThread()
{
    if (!isRunning())
        return;

    wait();
}


Название: Re: QprogressBar в отдельном потоке!
Отправлено: RedDog от Сентябрь 01, 2010, 14:04
Впринципе файл копируется но окно в котором должен отображаться ход процесса копирования, то есть где прогресс бар, оно зависает на время копирования, на нем ничего не видно. Да и как мне передовать ход выполнения копирования на прогресс бар, то есть, что бы он заполнялся.
Создай слот в диалоге, на который будет приходить сигнал от потока с параметром выполнения.

Код:
void MyWindow::on_progress(int progress)
{
    ui->progressBar->setValue(progress);
}
предварительно связав его с сигналом от потока:

Код:
connect(CopyProgress, SIGNAL(progress(int)), this, SLOT(on_progress(int)));
где CopyProgress - указатель на экземпляр объекта потока копирования
Код:
SIGNAL(progress(int))
- его сигнал о проценте выполнения.


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kadr от Сентябрь 01, 2010, 15:32
короче виснет, я не понял где connect нужно прописывать. Я прописал в финкции которая создает диалог.
Код:
...
path->setText("Из: "+begin_path);//лайблам присваиваем текст
    path_f->setText("В: "+end_path);//второму тоже
    MyThread *tr;
    
    connect (tr,SIGNAL(signalForProgressBar(int)),this,SLOT(progress_signal(int)));

    MyThread(begin_path.trimmed(),end_path.trimmed()).start(QThread::HighPriority);// запускает второй поток в котором отображается ход копирования
    
    connect(button_cancel,SIGNAL(clicked()),dialog_progress,SLOT(close()));//при нажатии на кнопку закрыть, закрыть диалог
сделал вот так
Код:
path->setText("Из: "+begin_path);//лайблам присваиваем текст
    path_f->setText("В: "+end_path);//второму тоже
    MyThread *tr = new MyThread(begin_path.trimmed(),end_path.trimmed());

    connect (tr,SIGNAL(signalForProgressBar(int)),this,SLOT(progress_signal(int)));

    //MyThread(begin_path.trimmed(),end_path.trimmed()).start(QThread::HighPriority);// запускает второй поток в котором отображается ход копирования
    tr->start(QThread::HighPriority);
   
    connect(button_cancel,SIGNAL(clicked()),dialog_progress,SLOT(close()));//при нажатии на кнопку закрыть, закрыть диалог
выводит диалог и даже заполняется бар, очень быстро и файл не полностью копируется, когда начинаешь копировать следующий, докачивается предыдущий, а следующий не копируется вообще, это как понимать?


Название: Re: QprogressBar в отдельном потоке!
Отправлено: RedDog от Сентябрь 01, 2010, 15:48
пример:


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kadr от Сентябрь 03, 2010, 14:35
сделал все как написано в файле, и не пойму что ему, от меня надо, не хочет компилиться и все!

Код:
no matching function for call to 'progress_view::progress_view()'
progress_view.h
Код:
#ifndef PROGRESS_VIEW_H
#define PROGRESS_VIEW_H

#include "QThread"
#include "QFile"

class progress_view : public QThread
{
    Q_OBJECT

signals:
    void on_progress(int progress);

public:
    explicit progress_view(const QString &copyFrom, const QString &copyTo, QObject *parent = 0);


    QString m_from,m_to;

protected:
    void run();


};

#endif // PROGRESS_VIEW_H
progress_view.cpp
Код:
#include "progress_view.h"

progress_view::progress_view(const QString &copyFrom, const QString &copyTo, QObject *parent)
    : QThread(parent), m_from(copyFrom), m_to(copyTo)
{
}
void progress_view::run()
{
    QFile file,f;
    int i = 0;

               file.setFileName(m_from);//присваеваем переменной file имя файла на диске

               file.open(QIODevice::ReadOnly);//открываем его на чтение

               f.setFileName(m_to);//аналогично предыдущему

               f.open(QIODevice::WriteOnly);//на запись


               while (!file.atEnd())//запускаем цикл в котором файл копируется построчно
                {
                   f.write(file.readLine());//построчное записывание
                   emit on_progress(i);
                   i++;
                }

    exec();
}
Linux_Comander.cpp связывания сигнала со слотом в конструкторе класса!
Код:
Linux_Comander::Linux_Comander(QWidget *parent) :
    QMainWindow(parent),ui(new Ui::Linux_Comander)
{
    ui->setupUi(this);

    connect(&p_bar,SIGNAL(on_progress(int)),this,SLOT(progress_signal(int)));

...
Linux_Comander.cpp  передача переменных в progress_view и запуск потока!
Код:
progress_view(begin_path,end_path,0);

    p_bar.start();

Если передавать без параметров explicit progress_view(QObject *parent = 0);, то нормально отрабатывает, только мне надо обязательно передавать пути копирования.


Название: Re: QprogressBar в отдельном потоке!
Отправлено: RedDog от Сентябрь 03, 2010, 15:02
чего в ошибках выдает?


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kadr от Сентябрь 03, 2010, 15:45
сейчас сделал по другому, передаю параметры по другому
 p_bar.m_from=begin_path;
 p_bar.m_to=end_path;
 p_bar.start();
Запускается нормально, но при копировании ведет себя не правильно, прогресс бар не заполняется, и файл не копируется, программа после завершения еще остается висеть в процессах.


Название: Re: QprogressBar в отдельном потоке!
Отправлено: RedDog от Сентябрь 03, 2010, 23:53
держи


Название: Re: QprogressBar в отдельном потоке!
Отправлено: Blackwanderer от Сентябрь 04, 2010, 07:24
Может быть вас заинтересует класс QProgressDialog...


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kadr от Сентябрь 08, 2010, 08:40
Попробывал QProgressDialog, да работать с ним легче и понятнее. только вот возник один вопрос.
Я использую QFileSystemModel для отображения файловой системы, так вот после того, как файл скопировался, его размер отображается как нулевой, если скопировать или удалить какой нибудь файл то показывается нормальный размер, как сделать что бы после того как файл скопировался, дерево обновлялось?

Код:
 model_l = new QFileSystemModel(this);
   model_r = new QFileSystemModel(this);

   model_l->setRootPath("C:/");
   model_r->setRootPath("D:/");

   ui->left_pole->setModel(model_l);//установка qtreeview в соответствиис моделью.
   ui->right_pole->setModel(model_r);


Название: Re: QprogressBar в отдельном потоке!
Отправлено: kadr от Сентябрь 09, 2010, 08:10
Привет всем, подскажите, как в QTreeView можно изменить цвет текста в текущем итеме? Мне нужно что бы при нажатии кнопки, допустим insert, как в тотале, текищий элемент выделялся красным цветом, и курсор смещался вниз на одну позицию.  ???


Название: Re: QprogressBar в отдельном потоке!
Отправлено: Karl-Philipp от Сентябрь 09, 2010, 10:46
Привет всем, подскажите, как в QTreeView можно изменить цвет текста в текущем итеме? Мне нужно что бы при нажатии кнопки, допустим insert, как в тотале, текищий элемент выделялся красным цветом, и курсор смещался вниз на одну позицию.  ???
Qt::ForegroundRole   The foreground brush (text color, typically) used for items rendered with the default delegate.

Как данный вопрос относится к ветке QProgressBar? :)