Visualizzazione dei risultati da 1 a 5 su 5
  1. #1

    [Qt] Thread e update interfaccia

    ciao!
    risolto un problema, se ne crea un altro.
    sto provando a vedere in giro, ma non sto capendo bene.

    allora, all'avvio di una finestra, dovrei eseguire delle oeprazioni in background.
    alla fine di ogni operazione, aggiornare dei componenti della finestra.
    per le operazioni in background avrei fatto una cosa del genere (per ora una cosa molto easy giusto per capire meglio):
    codice:
    #ifndef STARTRESIZING_H
    #define STARTRESIZING_H
    
    #include <QRunnable>
    #include <QPlainTextEdit>
    #include <QPushButton>
    #include <QThread>
    #include <QDebug>
    
    class StartResizing : public QRunnable
    {
    public:
        explicit StartResizing(QVector<QString> list, int width, int height, QPlainTextEdit* textArea, QString dir, QPushButton* btn);
        virtual ~StartResizing();
        void run();
    
    protected:
        QVector<QString> list;
        int width;
        int heigh;
        QPlainTextEdit* textArea;
        QString dir;
        QPushButton* btn;
    };
    
    #endif // STARTRESIZING_H
    
    
    #include "startresizing.h"
    
    StartResizing::StartResizing(QVector<QString> list, int width, int height, QPlainTextEdit *textArea, QString dir, QPushButton *btn)
    {
        this->list = list;
        this->width = width;
        this->heigh = height;
        this->textArea = textArea;
        this->dir = dir;
        this->btn = btn;
    }
    
    void StartResizing::run()
    {
        for(int i = 0; i < list.length(); i++)
        {
            textArea->appendPlainText(list[i]);
        }
    }
    
    StartResizing::~StartResizing()
    {
    }
    poi nel costruttore della finestra:
    codice:
    ResizeWindow::ResizeWindow(QVector<QString> list, int width, int height, QString startDir, QWidget *parent) :
        QScrollArea(parent),
        ui(new Ui::ResizeWindow)
    {
        ui->setupUi(this);
        QRunnable* runnable = new StartResizing(list, width, height, ui->txtArea, startDir, ui->btnClose);
        QThreadPool::globalInstance()->start(runnable);
    }
    ottenendo diversi errori che ancora non capisco molto bene.
    qualcuno ha qualche suggerimento da darmi in proposito??

  2. #2
    Da un thread non puoi modificare direttamente un componente visuale. Devi linkare una funzione per mezzo della funzione connect.
    Per info su Qt ti consiglio il forum dedicato
    https://forum.qt.io/
    Ciao ciao.

  3. #3
    Come detto, non si può toccare la GUI da altri thread, e mi lascia un po' inquieto vedere classi derivate da QWidget in un QRunnable... Se vuoi essere notificato di quando l'operazione termina emetti un segnale dal runnable e aggancialo (con una queued connection) ad uno slot relativo ad un oggetto GUI, in modo che il segnale faccia il giro dal loop degli eventi. In ogni caso, se spieghi un po' meglio cosa stai facendo ti si può dare un aiuto un po' più mirato...
    Amaro C++, il gusto pieno dell'undefined behavior.

  4. #4
    allora, intanto grazie ad entrambi.
    mi sono documentato un pò meglio ed ho fatto qualche passo indietro.
    mi sono resco conto in Qt questo approccio è sbagliato.
    spiego bene cosa dovrei fare, partendo da ciò che mi serve e tralasciando il resto dell'applicazione che non rientra nell'argomento.

    data una lista di file già selezionata in precedenza, dovrei processare questi file (ridimensionarli) e per ogni file fare un update della text area.
    e poi indicare quando l'operazione è finita.
    quindi, senza entrare nel ridimensionamento dei file che non rientra qui:
    codice:
    ALL'AVVIO DELLA FINESTRA
          PER OGNI FILE NELLA LISTA
                RIDIMENSIONA IL FILE
                SCRIVI NELLA TEXT AREA -> FILE RIDIMENSIONATO
           ALLA FINE DELLA LISTA, ABILITARE UN DETERMINATO BOTTONE
           AVVERTIRE DELLA FINE DELLE OPERAZIONI (NELLA TEXT AREA -> OPERAZIONE TERMINATA)
    per capire meglio l'uso dei thread e delle operazioni in background in Qt, mi sto limitando a stampare i valori di un semplice ciclo for.
    ma la sostanza cambia poco per il problema che ho.

    ho capito che devo creare una classe worker che esegue queste operazioni, e che si connette alla window attraverso il sistema di signals/slots e connect.

    ci sto ancora lavorando su, perchè è molto diverso da come ho fatto in java (dove la gui si può modificare senza questi vincoli).
    un esempio, anche molto banale, mi farebbe comodo.

  5. #5
    allora, dovreoi avercela fatta:
    codice:
    #ifndef WORKTHREAD_H
    #define WORKTHREAD_H
    
    #include <QMutex>
    #include <QThread>
    #include <QVector>
    
    class WorkerThread : public QThread
    {
        Q_OBJECT
    public:
        explicit WorkerThread(QVector<QString> list, int width, int height, QString startDir, QObject *parent = 0, bool b = false);
        void run();
        bool stop;
    
    private:
        QVector<QString> list;
        int width;
        int height;
        QString startDir;
    
    signals:
        void valueChanged(QString text);
        void finished();
    };
    
    #endif // WORKTHREAD_H
    
    #include "workerthread.h"
    
    WorkerThread::WorkerThread(QVector<QString> list, int width, int height, QString startDir, QObject *parent, bool b) :
        QThread(parent), stop(b)
    {
        this->list = list;
        this->width = width;
        this->height = height;
        this->startDir = startDir;
    }
    
    void WorkerThread::run()
    {
        for(int i = 0; i < list.count(); i++)
        {
            QMutex mutex;
            // PREVIENE CHE ALTRI THREAD IMPOSTINO LO STOP
            mutex.lock();
            if(this->stop) break;
            mutex.unlock();
            // EMETTE IL SEGNALE PER IMPOSTARE IL TESTO SULLA GUI
            emit valueChanged(list.value(i));
            this->msleep(500);
        }
        emit finished();
    }
    nella finestra:
    codice:
    #ifndef RESIZEWINDOW_H
    #define RESIZEWINDOW_H
    
    #include <QScrollArea>
    #include "workerthread.h"
    #include <QDebug>
    
    namespace Ui {
    class ResizeWindow;
    }
    
    class ResizeWindow : public QScrollArea
    {
        Q_OBJECT
    
    public:
        explicit ResizeWindow(QVector<QString> list, int width, int height, QString startDir, QWidget *parent = 0);
        ~ResizeWindow();
        WorkerThread* wt;
    
    private slots:
        void on_btnClose_clicked();
    
    public slots:
        void onValueChanged(QString text);
        void onFinished();
    
    private:
        Ui::ResizeWindow *ui;
    };
    
    #endif // RESIZEWINDOW_H
    
    #include "resizewindow.h"
    #include "ui_resizewindow.h"
    
    ResizeWindow::ResizeWindow(QVector<QString> list, int width, int height, QString startDir, QWidget *parent) :
        QScrollArea(parent),
        ui(new Ui::ResizeWindow)
    {
        ui->setupUi(this);
        wt = new WorkerThread(list, width, height, startDir, this);
        connect(wt, SIGNAL(valueChanged(QString)), this, SLOT(onValueChanged(QString)));
        connect(wt, SIGNAL(finished()), this, SLOT(onFinished()));
        wt->start();
    }
    
    void ResizeWindow::on_btnClose_clicked()
    {
        wt->stop = true;
        this->close();
    }
    
    void ResizeWindow::onValueChanged(QString text)
    {
        ui->txtArea->appendPlainText(text);
    }
    
    void ResizeWindow::onFinished()
    {
       ui->txtArea->appendPlainText("OPERAZONI TERMINATE");
    }
    
    ResizeWindow::~ResizeWindow()
    {
        delete ui;
    }
    questo funziona.
    sono bene accetti eventuali suggerimenti!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.