2009-05-28 4 views
8

Sto scrivendo il mio primo utile software appropriato. Parte di esso coinvolgerà l'utente che sta visualizzando un'immagine e scegliendo di accettarlo o rifiutarlo. In questo modo l'immagine verrà salvata in una cartella accettata o rifiutata e possibilmente ruotata e/o ridimensionata.Esecuzione di un processo o una filettatura separata in Qt

Al momento, la mia operazione di rotazione/ridimensionamento/salvataggio interrompe l'esecuzione del mio programma, ma mi piacerebbe che succedesse in background così l'immagine successiva viene visualizzata istantaneamente.

È l'unico modo per eseguire questa operazione in Qt per elaborare l'immagine in un thread separato o esiste un altro modo? Continuo a girare C++ e Qt, quindi non voglio confondermi tuffandomi in un nuovo campo!

+8

Una parola di avvertimento. Non è possibile utilizzare QPixmaps al di fuori del thread della GUI. Recentemente sono stato morso da questa è un'applicazione di tipo di rendering di immagini con thread simile. Utilizzare invece QImage. Se hai davvero bisogno di una QPixmap (cosa che ho fatto) dovrai restituire una QImage dal thread e fare la conversione (che è piuttosto costosa) nel thread della GUI principale. –

risposta

14

Qt ha il supporto del filo. Potresti trovare interessante this example application poiché è in qualche modo simile a ciò che descrivi.

Inoltre, here is the full Qt thread documentation.

+0

Quindi consiglieresti di immergerti e imparare le basi? – Skilldrick

+4

I thread sono la risposta giusta e il supporto thread di Qt è abbastanza buono. Se fossi in me, imparerei solo con l'esempio. L'applicazione collegata è simile in quanto svolge un'attività in background e ti consente di ricevere una notifica quando viene eseguita. Prendi un esempio che sia interessante o applicabile a te e provalo tu stesso. Cerca le cose che non capisci nei documenti finché l'intero processo non è più chiaro. Di solito questo ti porterà dove devi andare. – Naaff

+0

Attenzione, c'è una perdita di memoria nell'esempio! L'oggetto thread non viene mai eliminato. E perché proteggono l'operazione di scrittura di m_abort e non l'operazione di lettura ?! Perché proteggerlo comunque, la cosa peggiore che può succedere è che c'è un ciclo in più elaborato. – TimW

3

questo tipo di attività sono perfettamente adatte per le discussioni. comunque, dovresti prima fare una funzione 'normale' che lo fa, e quando funziona aggiungi un thread che legge una coda e chiama la stessa funzione di elaborazione.

Qt ha un sacco di strumenti per aiutarti in questo, principalmente il fatto che la maggior parte dei contenitori sono thread-safe, e anche un paio di algoritmi di threading (come map-reduce). ancora, provalo prima in modo sincrono.

2

A cura

Scusate ragazzi, ho un momento molto difficile che collega la "coda tipo personalizzato Esempio" per i requisiti.

Per quanto ne so dalla domanda, una volta che l'utente ha accettato o rifiutato l'immagine deve essere ruotata e/o ridimensionata facoltativamente e sempre salvata in una directory specifica e passare all'immagine successiva. (-> nessuna interazione con l'utente)
Anche se l'utente lascia la finestra di dialogo corrente, l'immagine deve ancora essere salvata.

L'esempio di tipo personalizzato in coda gestisce solo un'immagine, è sempre collegato alla GUI e quando gli utenti escono dalla finestra di dialogo, l'operazione thread viene interrotta.
Quindi, se avvia il suo programma dall'esempio in coda, probabilmente inizierà a scrivere una coda di immagini protetta da mutex in modo che possa aggiungere nuove immagini all'elenco se ci sono operazioni di salvataggio in sospeso. In caso contrario, l'utente deve ancora attendere le operazioni in sospeso.
Il secondo problema è che probabilmente non desidera attendere le operazioni di salvataggio in sospeso quando la finestra di dialogo si chiude.

Quello che farei per soddisfare i requisiti è lavorare con il pool di thread. Feed il pool di thread le operazioni di salvataggio desiderate e utilizzare un modello decoratore basato su QRunnable se deve anche essere ruotato/ridimensionato. Tutte le accodazioni vengono gestite correttamente dalla libreria e le operazioni in sospeso vengono eseguite anche se l'utente lascia la finestra di dialogo corrente. Alla fine potrei usare il codice di esempio in coda per caricare nuove immagini e dare all'utente un'indicazione di attesa per l'operazione di caricamento.

Probabilmente le mie runnables e decorator assomigliano a questo ... (forse alcuni costruttori aggiuntivi per sostituire le funzioni impostate) così posso facilmente aggiungere nuove operazioni come questa QThreadPool::globalInstance()->start(saver); senza utilizzare alcun oggetto di sincronizzazione di basso livello.

class ImageDecorator : public QRunnable 
{ 
    NextStep nextStep; 
public: 
    typedef boost::shared_ptr<QRunnable> NextStep; 

    ImageDecorator(const NextStep& nextStep) : nextStep(nextStep) { 
    } 

    ImageDecorator() : nextStep() { 
    } 

    // set/get image functions.... 

protected: 
    void next() { 
     if(nextStep) 
      nextStep->run(); 
    } 
}; 


class RotateImage : public ImageDecorator 
{ 
public: 
    typedef boost::shared_ptr<Image> Image; 

    RotateImage(const NextStep& nextStep) : ImageDecorator(nextStep) { 
    } 

    RotateImage() : ImageDecorator() { 
    } 
    // set angle functions.... 

private: 
    void run() 
    { 
     // rotate the image 
     // ... 
     next(); 
    } 
}; 

class ResizeImage : public ImageDecorator 
{ 
public: 
    typedef boost::shared_ptr<Image> Image; 

    ResizeImage(const NextStep& nextStep) : ImageDecorator(nextStep) { 
    } 

    ResizeImage() : ImageDecorator() { 
    } 
    // set size functions.... 

private: 
    void run() 
    { 
     // resize the image 
     next(); 
    } 
}; 

class SaveImage : public ImageDecorator 
{ 
public: 
    typedef boost::shared_ptr<Image> Image; 

    SaveImage(const NextStep& nextStep) : ImageDecorator(nextStep) { 
    } 

    SaveImage() : ImageDecorator() { 
    } 
    // set fileName functions.... 

private: 
    void run() 
    { 
     // save the image 
     next(); 
    } 
}; 

// save the image 
SaveImage *const saver(new SaveImage()); 
saver->setImage(/*use shared pointer*/); 
saver->setFilename(...); 

QThreadPool::globalInstance()->start(saver); 

// rotate and save the image 
const ImageDecorator::NextStep saver(new SaveImage()); 
saver->setImage(/*use shared pointer*/); 
saver->setFilename(...); 
RotateImage *const rotateAndSave(new RotateImage(saver)); 
rotateAndSave->setImage(/*use shared pointer*/); 
rotateAndSave->setAngle(...); 

QThreadPool::globalInstance()->start(rotateAndSave); 


// resize rotate and save the image 
const ImageDecorator::NextStep saver(new SaveImage()); 
saver->setImage(/*use shared pointer*/); 
saver->setFilename(...); 
const ImageDecorator::NextStep rotateAndSave(new RotateImage(saver)); 
rotateAndSave->setImage(/*use shared pointer*/); 
rotateAndSave->setAngle(...); 
ResizeImage *const resizeRotateAndSave(new ResizeImage(rotateAndSave)); 
resizeRotateAndSave->setImage(/*use shared pointer*/); 
resizeRotateAndSave->setSize(...); 

QThreadPool::globalInstance()->start(resizeRotateAndSave); 
+0

Solo una domanda, perché usi boost :: shared_ptr? Esistono classi specifiche per Qt come QSharedData, QSharedDataPointer per questo scopo. – bkausbk

1

creare un thread separato con QThread o utilizzare di thread thread di lavoro con QRunnable o dare un'occhiata ad alto livello di classe QtConcurrent.Here è un esempio per il ridimensionamento dell'immagine.

1

Il modo più semplice per farlo è utilizzare QtConcurrent :: run