2009-05-28 25 views
8

Escribo mi primera pieza de software adecuada. Parte de esto implicará que el usuario vea una imagen y elija aceptarla o rechazarla. Al hacer esto, la imagen se guardará en una carpeta aceptada o rechazada, y posiblemente se rotará y/o se redimensionará.Ejecutar un proceso o hilo por separado en Qt

Por el momento, mi operación de rotación/cambio de tamaño/guardar está pausando la ejecución de mi programa, pero me gustaría que sucediera en el fondo para que la siguiente imagen se muestre al instante.

¿Es la única manera de hacer esto en Qt para procesar la imagen en un hilo separado, o hay otra manera? Todavía me estoy dando vueltas por C++ y Qt, ¡así que no quiero confundirme buceando en un nuevo campo!

+8

Una palabra de advertencia. No puede usar QPixmaps fuera del hilo de GUI. Me ha picado recientemente esta es una aplicación de tipo de representación de imagen roscada similar. Use QImage en su lugar. Si realmente necesita un QPixmap (que yo hice) tendrá que devolver un QImage del hilo y hacer la conversión (que es bastante costosa) en el hilo principal de la GUI. –

Respuesta

14

Qt tiene soporte para roscas. Puede encontrar this example application interesante ya que es algo similar a lo que describe.

También, here is the full Qt thread documentation.

+0

¿Recomendarías simplemente bucear y aprender los conceptos básicos? – Skilldrick

+4

Los subprocesos son la respuesta correcta y el soporte de subprocesos de Qt es bastante bueno. Si fuera yo, solo aprendería con el ejemplo. La aplicación vinculada es similar en el sentido de que realiza una tarea en segundo plano y le permite recibir notificaciones cuando termina. Tome un ejemplo que sea interesante o aplicable para usted y pruébelo usted mismo. Busque cosas que no entiende en los documentos hasta que todo el proceso sea más claro. Usualmente eso te llevará a donde necesitas ir. – Naaff

+0

¡Cuidado, hay una pérdida de memoria en el ejemplo! El objeto de hilo nunca se elimina. ¿Y por qué protegen la operación de escritura de m_abort y no la operación de lectura? Por qué protegerlo de todos modos, lo peor que puede pasar es que haya un bucle adicional procesado. – TimW

3

este tipo de tareas son perfectamente adecuadas para los hilos. aún así, primero debe hacer una función 'normal' que lo haga, y cuando funcione agregue un hilo que lea una cola y llame a la misma función de procesamiento.

Qt tiene muchas herramientas para ayudarlo en esto, principalmente el hecho de que la mayoría de los contenedores son seguros para subprocesos, y también un par de algoritmos de subprocesos (como map-reduce). aún así, primero pruébelo sincrónicamente.

2

Editado

Lo siento chicos, tienen un tiempo muy difícil vincular el "Tipo Ejemplo cola personalizada" a los requisitos.

Por lo que puedo decir de la pregunta, una vez que el usuario ha aceptado o rechazado la imagen, debe rotar y/o escalar opcionalmente y guardarse siempre en un directorio específico y pasar a la siguiente imagen. (-> ya no hay interacción con el usuario)
Incluso si el usuario abandona el diálogo actual, la imagen aún tiene que guardarse.

El "Ejemplo de tipo personalizado en cola" maneja solo una imagen, siempre está vinculado a la interfaz gráfica de usuario y cuando los usuarios salen del cuadro de diálogo, la operación de la secuencia se detiene.
Por lo tanto, si inicia su programa desde el ejemplo En cola, probablemente comenzará a escribir una cola de imágenes protegida por mutex para que pueda agregar nuevas imágenes a la lista si hay operaciones de salvar pendientes. De lo contrario, el usuario aún tiene que esperar en las operaciones pendientes.
El segundo problema es que probablemente no desea esperar en las operaciones de salvar pendientes cuando se cierra el cuadro de diálogo.

Lo que haría para cumplir los requisitos es trabajar con el grupo de subprocesos. Alimente el grupo de subprocesos las operaciones de guardado que desee y utilice un patrón de decorador basado en QRunnable si también necesita ser rotado/escalado. La biblioteca maneja correctamente todas las colas y las operaciones pendientes se ejecutan incluso si el usuario abandona el diálogo actual. Al final, posiblemente usaría el código de ejemplo En cola para cargar nuevas imágenes y dar al usuario una indicación de espera para la operación de carga.

Mis runnables y decorador probablemente se verían así ... (tal vez algunos constructores adicionales para reemplazar las funciones establecidas) así que puedo agregar fácilmente una nueva operación como esta QThreadPool::globalInstance()->start(saver); sin usar ningún objeto de sincronización de bajo nivel.

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 pregunta, ¿por qué usas boost :: shared_ptr? Hay clases específicas de Qt como QSharedData, QSharedDataPointer para este propósito. – bkausbk

1

bien crear un hilo separado con QThread o uso de subprocesos subprocesos de trabajo con QRunnable o echar un vistazo a la clase QtConcurrent alto nivel.Here es un ejemplo de escala de imagen.

1

La forma más sencilla de hacerlo es utilizar QtConcurrent :: ejecutar

Cuestiones relacionadas