Hi,

I'm trying to convert the "imagescaling" example http://doc.qt.io/qt-5/qtconcurrent-i...g-example.html to work with a call to a member function instead of the global one.

Here is the modified code:

imagescaling.cpp
Qt Code:
  1. #include "imagescaling.h"
  2. #include <qmath.h>
  3.  
  4. const int imageSize = 100;
  5.  
  6. QImage* scale(const QString &imageFileName)
  7. {
  8. QImage* image = new QImage(imageFileName);
  9. image->scaled(QSize(imageSize, imageSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
  10. return image;
  11. }
  12.  
  13. Images::Images(QWidget *parent)
  14. : QWidget(parent)
  15. {
  16. setWindowTitle(tr("Image loading and scaling example"));
  17. resize(800, 600);
  18.  
  19. imageScaling = new QFutureWatcher<QImage*>(this);
  20. connect(imageScaling, SIGNAL(resultReadyAt(int)), SLOT(showImage(int)));
  21. connect(imageScaling, SIGNAL(finished()), SLOT(finished()));
  22.  
  23. openButton = new QPushButton(tr("Open Images"));
  24. connect(openButton, SIGNAL(clicked()), SLOT(open()));
  25.  
  26. cancelButton = new QPushButton(tr("Cancel"));
  27. cancelButton->setEnabled(false);
  28. connect(cancelButton, SIGNAL(clicked()), imageScaling, SLOT(cancel()));
  29.  
  30. pauseButton = new QPushButton(tr("Pause/Resume"));
  31. pauseButton->setEnabled(false);
  32. connect(pauseButton, SIGNAL(clicked()), imageScaling, SLOT(togglePaused()));
  33.  
  34. QHBoxLayout *buttonLayout = new QHBoxLayout();
  35. buttonLayout->addWidget(openButton);
  36. buttonLayout->addWidget(cancelButton);
  37. buttonLayout->addWidget(pauseButton);
  38. buttonLayout->addStretch();
  39.  
  40. imagesLayout = new QGridLayout();
  41.  
  42. mainLayout = new QVBoxLayout();
  43. mainLayout->addLayout(buttonLayout);
  44. mainLayout->addLayout(imagesLayout);
  45. mainLayout->addStretch();
  46. setLayout(mainLayout);
  47. }
  48.  
  49. Images::~Images()
  50. {
  51. imageScaling->cancel();
  52. imageScaling->waitForFinished();
  53. }
  54.  
  55. QImage* Images::scale_(const QString &imageFileName)
  56. {
  57. QImage* image = new QImage(imageFileName);
  58. image->scaled(QSize(imageSize, imageSize), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
  59. return image;
  60. }
  61.  
  62. void Images::open()
  63. {
  64. // Cancel and wait if we are already loading images.
  65. if (imageScaling->isRunning()) {
  66. imageScaling->cancel();
  67. imageScaling->waitForFinished();
  68. }
  69.  
  70. // Show a file open dialog at QStandardPaths::PicturesLocation.
  71. QStringList files = QFileDialog::getOpenFileNames(this, tr("Select Images"),
  72. QStandardPaths::writableLocation(QStandardPaths::PicturesLocation),
  73. "*.jpg *.png");
  74.  
  75. if (files.count() == 0)
  76. return;
  77.  
  78. // Do a simple layout.
  79. qDeleteAll(labels);
  80. labels.clear();
  81.  
  82. int dim = qSqrt(qreal(files.count())) + 1;
  83. for (int i = 0; i < dim; ++i) {
  84. for (int j = 0; j < dim; ++j) {
  85. QLabel *imageLabel = new QLabel;
  86. imageLabel->setFixedSize(imageSize,imageSize);
  87. imagesLayout->addWidget(imageLabel,i,j);
  88. labels.append(imageLabel);
  89. }
  90. }
  91.  
  92. // Use mapped to run the thread safe scale function on the files.
  93. //imageScaling->setFuture(QtConcurrent::mapped(files, scale));
  94. imageScaling->setFuture(QtConcurrent::mapped(files, [this](const QString &file){this->scale_(file);}));
  95.  
  96. openButton->setEnabled(false);
  97. cancelButton->setEnabled(true);
  98. pauseButton->setEnabled(true);
  99. }
  100.  
  101. void Images::showImage(int num)
  102. {
  103. labels[num]->setPixmap(QPixmap::fromImage(*(imageScaling->resultAt(num))));
  104. }
  105.  
  106. void Images::finished()
  107. {
  108. openButton->setEnabled(true);
  109. cancelButton->setEnabled(false);
  110. pauseButton->setEnabled(false);
  111. }
To copy to clipboard, switch view to plain text mode 

imagescaling.h

Qt Code:
  1. #ifndef IMAGESCALING_H
  2. #define IMAGESCALING_H
  3.  
  4. #include <QtWidgets>
  5. #include <QtConcurrent>
  6.  
  7. class Images : public QWidget
  8. {
  9. Q_OBJECT
  10. public:
  11. Images(QWidget *parent = 0);
  12. ~Images();
  13. QImage *scale_(const QString &imageFileName);
  14. public Q_SLOTS:
  15. void open();
  16. void showImage(int num);
  17. void finished();
  18. private:
  19. QPushButton *openButton;
  20. QPushButton *cancelButton;
  21. QPushButton *pauseButton;
  22. QVBoxLayout *mainLayout;
  23. QList<QLabel *> labels;
  24. QGridLayout *imagesLayout;
  25. QFutureWatcher<QImage*> *imageScaling;
  26. };
  27.  
  28. #endif // IMAGESCALING_H
To copy to clipboard, switch view to plain text mode 

If I map the global function everything works:

Qt Code:
  1. imageScaling->setFuture(QtConcurrent::mapped(files, scale));
To copy to clipboard, switch view to plain text mode 

If I map to the member function it won't compile:

Qt Code:
  1. imageScaling->setFuture(QtConcurrent::mapped(files, &Images::scale_));
  2. or
  3. imageScaling->setFuture(QtConcurrent::mapped(files, [this](const QString &file){this->scale_(file);}));
To copy to clipboard, switch view to plain text mode 

ERROR:

Qt Code:
  1. ...\imagescaling.cpp:133: Fehler: C2664: "void QFutureWatcher<QImage *>::setFuture(const QFuture<T> &)" : Converting of Argument 1 of "QFuture<void>" in "const QFuture<T> &" not possible
  2. with
  3. [
  4. T=QImage *
  5. ]
To copy to clipboard, switch view to plain text mode 

Is using QtConcurrent::mapped() the wrong approach to bind with member functions?