我正在写我的第一个适当有用的软件。其中一部分将涉及用户查看图像,并选择接受或拒绝它。执行此操作将导致图像保存到已接受或拒绝的文件夹,并可能旋转和/或调整大小。
目前,我的旋转/调整大小/保存操作暂停执行我的程序,但我希望它在后台运行,以便立即显示下一张图像。
在Qt中执行此操作的唯一方法是在单独的线程中处理图像,还是有另一种方法?我仍然对C ++和Qt感兴趣,所以我不想因为潜入新领域而迷惑自己!
答案 0 :(得分:14)
Qt有线程支持。你可能会发现this example application很有趣,因为它与你描述的有些相似。
答案 1 :(得分:3)
这些任务非常适合线程。仍然,你应该首先执行一个“正常”的功能,当它工作时,添加一个读取队列并调用相同处理函数的线程。
Qt有很多工具可以帮助你解决这个问题,主要是大多数容器都是线程安全的,还有一些线程算法(比如map-reduce)。仍然,首先尝试同步。
答案 2 :(得分:2)
<强>被修改强>
对不起,伙计们,我很难将“排队自定义类型示例”链接到要求。
据我所知,一旦用户接受或拒绝了图像,它必须是可选的旋转和/或缩放,并始终保存到特定目录并继续下一个图像。 ( - &gt;不再与用户进行交互)
即使用户离开当前对话框,仍然需要保存图像。
“排队自定义类型示例”仅处理一个图像,始终链接到gui,当用户退出对话框时,线程操作将停止。
因此,如果他从Queued示例启动他的程序,他可能会开始编写一个受互斥锁保护的图像队列,这样如果有待处理的保存操作,他就可以将新图像添加到列表中。否则,用户仍然需要等待待处理的操作
第二个问题是,当对话框关闭时,他可能不想等待待处理的保存操作。
我要做的是满足要求是使用线程池。为线程池提供所需的保存操作,如果还需要旋转/缩放,则使用基于QRunnable的装饰器模式。所有排队都由库正确处理,即使用户离开当前对话框,也会执行待处理操作。
最后,我可能会使用Queued示例代码来加载新图像,并为用户提供加载操作的等待指示。
我的runnables和decorator可能看起来像这样......(可能还有一些额外的构造函数来替换set函数)所以我可以很容易地添加像QThreadPool::globalInstance()->start(saver );
这样的新操作而不使用任何低级别同步对象。
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 );
答案 3 :(得分:1)
使用QThread
创建单独的线程或使用QRunnable
的线程池工作线程,或者查看高级QtConcurrent类。 Here是图像缩放的示例。
答案 4 :(得分:1)
最简单的方法是使用QtConcurrent :: run