简体   繁体   中英

How can I draw a selection rectangle on QScrollArea?

I have created an Image Viewer application that opens and saves an image and load the image on QLabel,then I created a ScrollArea to scroll for large images, in my second step I am trying to draw a selection rectangle to select a specific sub area , the steps I have taken to paint the selection rectangle as follows:

1- I used an PaintEvent to paint the rectangle. 2- I used MouseEvent to select the sub area.

The problem is, when I run my code, I can draw the rectangle on the QWidget but not on the ScrollArea.

Here is my code:

in imageviewer.h

class ImageViewer : public QWidget{
Q_OBJECT
public:
   explicit ImageViewer(QWidget *parent = 0);
   ~ImageViewer();
private:
   Ui::ImageViewer *ui;

private slots:
  void on_openButton_pressed();

  void on_saveButton_pressed();

private:
  QPixmap image;
  QImage *imageObject;
  bool selectionStarted;
  QRect selectionRect;
  QMenu contextMenu;

protected:
  void paintEvent(QPaintEvent *e);
  void mousePressEvent(QMouseEvent *e);
  void mouseMoveEvent(QMouseEvent *e);
  void mouseReleaseEvent(QMouseEvent *e);
};

this is imageviewer.cpp

ImageViewer::ImageViewer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ImageViewer)
{
    ui->setupUi(this);
    ui->scrollArea->setWidget(ui->imageLabel);
}

open & save functions:

void ImageViewer::on_openButton_pressed()
{
    QString imagePath = QFileDialog::getOpenFileName(this, tr("Open File") , "" ,
                                                 tr("JPEG (*.jpg *.jpeg);;PNG (*.png);;BMP (*.bmp)"));

    imageObject = new QImage();
    imageObject->load(imagePath);

    image = QPixmap::fromImage(*imageObject);

    ui->imageLabel->setPixmap(image);
    ui->imageLabel->adjustSize();

}

void ImageViewer::on_saveButton_pressed()
{
    QString imagePath = QFileDialog::getSaveFileName(this, tr("Save File") , "" ,
                                                 tr("JPEG (*.jpg *.jpeg);;PNG (*.png);;BMP (*.bmp)"));

    *imageObject = image.toImage();
    imageObject->save(imagePath);
}

paint & mouse event functions:

void ImageViewer::paintEvent(QPaintEvent *e){
    QWidget::paintEvent(e);
    QPainter painter(this);
    painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
    painter.setBrush(QBrush(QColor(255,255,255,120)));
    painter.drawRect(selectionRect);
}

void ImageViewer::mousePressEvent(QMouseEvent *e){
    if(e->button() == Qt::RightButton){
        if(selectionRect.contains(e->pos()))
            contextMenu.exec(this->mapToGlobal(e->pos()));
    }
    else{
        selectionStarted = true;
        selectionRect.setTopLeft(e->pos());
        selectionRect.setBottomRight(e->pos());
    }
}

void ImageViewer::mouseMoveEvent(QMouseEvent *e){
    if(selectionStarted){
        selectionRect.setBottomRight(e->pos());
        repaint();
    }
}

void ImageViewer::mouseReleaseEvent(QMouseEvent *e){
    selectionStarted = false;
}

and this is a screenshot for my application

在此处输入图片说明

How can I draw a selection rectangle on QScrollArea?

You need QRubberBand which supposed to be directly applied to ui->imageLabel widget you use to display an image you want to scroll. Whether or not you should overload QLabel for ui->imageLabel is a question of implementation. Please see the example for mouse events which, of course better be applied to your label image class.

I understand from the way the code looks you used Qt Designer? That complicates overriding that label class but you can either not use .ui file or use event filter for trapping all the events for the given object.

What you currently have can be finally polished enough to be good for actual use, of course. It just makes much more effort for you. You can avoid overloading paintEvent etc. and the key is to apply the right approach directly where it needs to be applied.

// the example applied to authors code as requested
class MyImageLabel : public QLabel
{
public:
   explicit MyImageLabel(QWidget *parent = 0) : QLabel(parent), rubberBand(0) {}
private:
   QRubberBand* rubberBand;
   QPoint origin;

   void mousePressEvent(QMouseEvent *event);
   void mouseMoveEvent(QMouseEvent *event);
   void mouseReleaseEvent(QMouseEvent *event)
};

void MyImageLabel::mousePressEvent(QMouseEvent *event)
{
    origin = event->pos();
    if (!rubberBand)
        rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
    rubberBand->setGeometry(QRect(origin, QSize()));
    rubberBand->show();
}

void MyImageLabel::mouseMoveEvent(QMouseEvent *event)
{
    rubberBand->setGeometry(QRect(origin, event->pos()).normalized());
}

void MyImageLabel::mouseReleaseEvent(QMouseEvent *event)
{
    rubberBand->hide();
    // determine selection, for example using QRect::intersects()
    // and QRect::contains().
}

ImageViewer::ImageViewer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ImageViewer)
{
    ui->setupUi(this);
    // resolve this better than:
    delete ui->imageLabel; // you already have the QLabel object here?
    ui->imageLabel = new MyImageLabel;
    ui->scrollArea->setWidget(ui->imageLabel);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM