0

I'm writing a simple Qt c++ program to compare two images. I have already asked a question on the project's design (Qt Model-View-Controller) but my professor said i didn't have to use any of qt predefined model/views.

However now i'm having an issue in changing the way the images are displayed. More precisely, after i have already loaded two images, cropped them and displayed them flawlessly, i get a segmentation fault when trying to re-display the images cropped in a different way. Here's some code:

File MainWindow.h:

class MainWindow : public QMainWindow, public View, public Controller
      {
          Q_OBJECT

      public:
          explicit MainWindow(QWidget *parent = 0);
          ~MainWindow();
          virtual void myUpdate();


      private slots:
          void open();
          void loadImage();
          void zoomIn();
          void zoomOut();
          void normalSize();
          void fitToWindow();
          void about();
          void vertical();
          void horizontal();


      private:
          Ui::MainWindow *ui;

          Image imageComposition;
          QImage *result;
          QImage* displayVertical(QImage *res, QPainter *painter);
          QImage* displayHorizontal(QImage *res, QPainter *painter);

          void createActions();
          void createMenus();
          void updateActions();
          void scaleImage(double factor);
          void diffImages();

          .... // methods and attributes non relevant for this question.

File MainWindow.cpp:

....//methods non relevant for this question.

void MainWindow::diffImages()
{
  // **SIGEGV happening on the following line!!**
  result = new QImage(QSize(imageComposition.getLeft()->width(),imageComposition.getLeft()->height()), QImage::Format_ARGB32_Premultiplied);

  ui->Canvas->resize(imageComposition.getLeft()->width(),imageComposition.getLeft()->height());

  QPainter *painter = new QPainter(result);

  switch(imageComposition.getDivisionBar()) {
    case 0 :
    result = displayVertical(result, painter);
    break;
    case 1 :
    result = displayHorizontal(result, painter);
    break;
  };

  ui->Canvas->setPixmap(QPixmap::fromImage(*result));
}

.....

QImage* MainWindow::displayVertical(QImage *res, QPainter *painter)
{

  QRect leftRect(QPoint(0,0), QPoint(imageComposition.getLeft()->width()/2,imageComposition.getLeft()->height() - 1 ));
  QImage leftSide(imageComposition.getLeft()->copy(leftRect));

  QRect rightRect(QPoint(imageComposition.getRight()->width()/2, 0), QPoint(imageComposition.getRight()->width() - 1,imageComposition.getRight()->height() - 1));
  QImage rightSide(imageComposition.getRight()->copy(rightRect));

  painter->drawImage(0,0, leftSide);
  painter->drawImage(res->width()/2, 0, rightSide);

  return res;

}

QImage *MainWindow::displayHorizontal(QImage *res, QPainter *painter) {

  QRect upperRect(QPoint(0,0), QPoint(imageComposition.getLeft()->width() - 1, imageComposition.getLeft()->height() / 2));
  QImage upperSide(imageComposition.getLeft()->copy(upperRect));

  QRect lowerRect(QPoint(0,imageComposition.getRight()->height() / 2), QPoint(imageComposition.getRight()->width() - 1, imageComposition.getRight()->height() - 1));
  QImage lowerSide(imageComposition.getRight()->copy(lowerRect));

  painter->drawImage(0, 0, upperSide);
  painter->drawImage(0, res->height() / 2, lowerSide);

  return res;

  }

So the segmentation fault happens in diffImages(), at the first line, when result (a QImage already containing something, as it was initialized the first time two images are rendered.) should be re-initialized to display the images in another way. That is when the user press the button "Display horizontally".

I searched the web and some suggest to put the painter->drawImage(), wich is contained in the diffImages() function, in an overloaded implementation of MainWindow::paintEvent(QPaintEvent *). But that way diffImages() is called whenever something needs to be redrawed, including the initial window displaying, wich leads to a loop of redraw() calls. So I decided not to follow that suggestion.

From what i can understand, the possible cause of the problem could be the fact that result is still being displayed on the screen inside the QLabel when the method called after wants to re-initialize it. What do you suggest?? Thank you in advance.

p.s. I tried to be as clear as possible, but if you need the full source or other explanation please let me know.

Community
  • 1
  • 1
IvanProsperi94
  • 109
  • 2
  • 7
  • 1
    how is your `Image` class (member `imageComposition`) declared or initialized? and you could also put the image on the stack, why need it on the heap? – Zaiborg Aug 13 '14 at 13:40
  • 1
    Most possible reason is that object returned by `imageComposition.getLeft()` doesn't exist. It's not initialized or already destroyed. Edit your question and add more about `imageComposition` if you won't be able to find the mistake by yourself. – Ezee Aug 13 '14 at 13:48
  • Image is just a class that stores two pointers to QImages and an unsigned short int to determine in wich way the images should be displayed. It is initialized in the loadImage() function, when the images are loaded through a QFileDialog. Now i'll try to see if imageComposition is null when the method is re-called. Thank you!! – IvanProsperi94 Aug 13 '14 at 13:56
  • You were right!! imageComposition.getLeft() is not accessible!!. Well, Image::left, wich is a QImage pointer is not accessible. I wonder why imageComposition got destroyed. It's strange because it is a member of MainWindow, so it should not be destroyed until MainWindow is destroyed should't it?? – IvanProsperi94 Aug 13 '14 at 14:04
  • It will be helpful if you add a back-trace of the crash – ahmed Aug 13 '14 at 21:17
  • also, it's recommended to not use pointers with QImage and QPainter – ahmed Aug 13 '14 at 21:18
  • You seem a little too keen on using pointers. Don't use them unless there is a good reason to do that. And even then, consider using smart pointers. In your `diffImages` function you initialize `QPainter` object with `new`, but you don't seem to delete it anywhere. This is a memory leak. Same goes for your `result` variable. – thuga Aug 14 '14 at 05:53
  • Unfortunately I was not able to get a back-trace, because I don't know how to do it with Qt Creator. Even searching online didn't help. If someone of you do know how to do this, please let me know. However now I'll try to remove some of these pointers and see if i can get it to work. Thank you all again!! – IvanProsperi94 Aug 14 '14 at 08:52
  • Ok I think I'm going crazy. I removed the unuseful pointers and replaced with normal stack variables. But it doesn't work. I get the runtime error "QPaintDevice: Cannot destroy paint device that is being painted" when executing line `ui->Canvas->setPixmap(QPixmap::fromImage(*result));` and nothing is shown on the screen. Do you have any suggestions?? – IvanProsperi94 Aug 14 '14 at 09:53
  • Sounds like your `QPainter` is still active when your `result` object gets destroyed. You can try calling [`QPainter::end`](http://qt-project.org/doc/qt-5/qpainter.html#end) when you finish painting. – thuga Aug 14 '14 at 10:46

0 Answers0