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


Автор: DSan 29.4.2008, 23:01
Имеем:

программа по нажатию на директорию в дереве каталогов файловой системы отображает эскизы изображений из выбранной директории. Алгоритм формирования прост - загружается изображение в QImage, масштабируется до нужного размера и отображается в ListView в виде иконки. Создание эскиза вынесено во вторичный поток. После формирования эскиз передается в главный поток через сигнал-слот соединение для отображения.

Класс для формирования эскизов:

Код

class ThumbThread : public QThread {
    
    Q_OBJECT
    
public:
    ThumbThread() : stopped(false) {}
    void setThumbPath(const QString &path);
    void stop();
    void run();

signals:
    void showThumb(const QImage &, const QString &);

private:
    QString thumbPath;
    volatile bool stopped;
};

void ThumbThread::setThumbPath(const QString &path) {
    thumbPath = path;
}

void ThumbThread::stop() {
    stopped = true;
}

void ThumbThread::run() {
    
    ...
    
    for(int i = 0; i < fileList.count(); i++) {

        if(stopped)
            break;    

        ... // формируется эскиз resultImg
        
        emit showThumb(resultImg, fileName);        
    }
    
    stopped = false;
}


Главное окно (класс MainWindow):

Код

// конструктор
MainWindow::MainWindow() {
    
    ...
    // соединение
    connect(&thread, SIGNAL(showThumb(const QImage &, const QString &)), this, SLOT(thumbCreated(const QImage &, const QString &)));
}

// добавление эскиза в модель (отображается в соответствующем QListView)
void MainWindow::thumbCreated(const QImage &img, const QString &fileName) {
    QStandardItem *item = new QStandardItem();
    
    item->setData(QIcon(QPixmap::fromImage(img)), Qt::DecorationRole);
    item->setData(fileName, Qt::ToolTipRole);
    
    thumbModel->appendRow(item);
}

// слот для запуска потока при выборе директории в дереве каталогов
// thread объявлен как private член в классе MainWindow
void MainWindow::pathEntered() {
    
    // поток работает?
    if(thread.isRunning()) {
        thread.stop(); // останавливаем
        thread.wait(); // ждем, когда закончится обработка текущего на данный момент эскиза
    }
    
    thumbModel->clear(); // очищение модели с эскизами
    
    thread.setThumbPath(pathEdit->text()); // указание каталога для формирования эскизов
        
    thread.start();
}


Суть проблемы:

если не дожидаться, пока поток подгрузит _все_ эскизы выбранной директории, и выбрать другую, то после очистки модели первым будет отображен эскиз, который был сформирован последним перед остановкой потока. Т.е. получается, что эскиз, который формировался непосредственно перед остановкой потока, не успевает отобразиться в ListView и попадает уже в "новую партию" эскизов. Каким образом можно решить данную проблему?

Автор: JackYF 29.4.2008, 23:48
Цитата(DSan @  29.4.2008,  22:01 Найти цитируемый пост)
Каким образом можно решить данную проблему? 

Вижу два возможных выхода:

1) прервать предыдущий рабочий поток, если он был, во время перехода на новый элемент в дереве
2) передать вместе с картинкой и некий ID запроса. Если это не последний запрос, не отображать эскиз.

Автор: DSan 30.4.2008, 14:29
Цитата(JackYF @ 29.4.2008,  23:48)
Вижу два возможных выхода:

1) прервать предыдущий рабочий поток, если он был, во время перехода на новый элемент в дереве
2) передать вместе с картинкой и некий ID запроса. Если это не последний запрос, не отображать эскиз.

Воспользовался вторым советом.

Спасибо, проблема решена.

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