我在寫第一個適當的有用軟件。其中的一部分將涉及用戶查看圖像,並選擇接受或拒絕它。這樣做會導致圖像被保存到接受或拒絕的文件夾中,並可能旋轉和/或調整大小。在Qt中運行單獨的進程或線程
目前,我的旋轉/調整大小/保存操作暫停執行我的程序,但我希望它發生在後臺,以便下一個圖像即時顯示。
是唯一的方式來做到這一點在Qt中處理圖像在一個單獨的線程,或者有另一種方式?我仍然把我的腦袋圍繞C++和Qt,所以我不想通過潛入一個新領域來迷惑自己!
我在寫第一個適當的有用軟件。其中的一部分將涉及用戶查看圖像,並選擇接受或拒絕它。這樣做會導致圖像被保存到接受或拒絕的文件夾中,並可能旋轉和/或調整大小。在Qt中運行單獨的進程或線程
目前,我的旋轉/調整大小/保存操作暫停執行我的程序,但我希望它發生在後臺,以便下一個圖像即時顯示。
是唯一的方式來做到這一點在Qt中處理圖像在一個單獨的線程,或者有另一種方式?我仍然把我的腦袋圍繞C++和Qt,所以我不想通過潛入一個新領域來迷惑自己!
Qt有線程支持。您可能會發現this example application有趣,因爲它與您所描述的有些相似。
那麼你會建議只是潛入並學習基礎知識? – Skilldrick 2009-05-28 22:32:56
線程是正確的答案,Qt的線程支持非常好。如果是我,我只是通過示例來學習。鏈接的應用程序類似於它在後臺執行任務,並允許您在完成時收到通知。舉一個有趣或適用於你的例子,並自己嘗試一下。查看文檔中您不瞭解的內容,直到整個過程更加清晰。通常這會讓你到你需要去的地方。 – Naaff 2009-05-28 22:51:36
這些類型的任務非常適合線程。仍然,你應該首先做一個「正常」的功能,當它工作時,添加一個讀取隊列並調用相同處理函數的線程。
Qt有很多工具可以幫助你解決這個問題,主要是大部分容器都是線程安全的,還有一些線程算法(比如map-reduce)。仍然,首先嚐試它同步。
編輯
對不起球員,我有一個非常艱難的時間鏈接「隊列自定義類型示例」的要求。
據我所知道的問題,一旦用戶接受或拒絕圖像,它必須是可選的旋轉和/或縮放,並始終保存到一個特定的目錄,並繼續下一個圖像。 ( - >不再與用戶進行交互)
即使用戶離開當前對話框,圖像仍然需要保存。
「排隊的自定義類型示例」只處理一個圖像,始終鏈接到gui,當用戶退出對話框時,線程操作停止。
所以如果他從排隊的例子開始他的程序,他可能會開始寫一個互斥鎖保護的圖像隊列,以便他可以添加新的圖像到列表中,如果有未決的保存操作。否則,用戶仍然必須等待未決操作。
第二個問題是他可能不想在對話框關閉時等待掛起的保存操作。
我會做什麼來滿足要求是與線程池合作。爲線程池提供所需的保存操作,並使用基於QRunnable的修飾器模式(如果還需要旋轉/縮放)。即使用戶離開當前對話框,所有隊列也會被庫正確處理並執行掛起的操作。 最後,我可能會使用Queued示例代碼加載新圖像,併爲用戶提供加載操作的等待指示。
我的runnables和裝飾器可能看起來像這樣...(也許一些額外的構造函數來替換設置的函數),所以我可以很容易地添加像這樣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);
可以創建一個單獨的線程與QThread
或線程池工作線程使用帶有QRunnable
或看看高水平QtConcurrent類。Here是一個圖像縮放的例子。
最簡單的方法是使用QtConcurrent :: run
一個字的警告。您不能在GUI線程之外使用QPixmaps。最近我被這個類似的線程圖像渲染類型應用程序所咬。改爲使用QImage。如果你真的需要一個QPixmap(我做過),你必須從線程返回一個QImage,然後在主GUI線程中進行轉換(這非常昂貴)。 – 2009-05-29 13:21:46