【问题标题】:How can I draw a selection rectangle on QScrollArea?如何在 QScrollArea 上绘制选择矩形?
【发布时间】:2016-02-04 12:44:32
【问题描述】:

我创建了一个图像查看器应用程序,它打开并保存图像并将图像加载到 QLabel 上,然后我创建了一个 ScrollArea 来滚动大图像,在我的第二步中,我试图绘制一个选择矩形来选择一个特定的子区域,我绘制选择矩形的步骤如下:

1- 我使用 PaintEvent 来绘制矩形。 2- 我使用 MouseEvent 来选择子区域。

问题是,当我运行我的代码时,我可以在 QWidget 上绘制矩形,但不能在 ScrollArea 上。

这是我的代码:

在 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);
};

这是 imageviewer.cpp

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

打开和保存功能:

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);
}

绘画和鼠标事件函数:

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;
}

这是我的应用程序的屏幕截图

【问题讨论】:

    标签: c++ qt qscrollarea


    【解决方案1】:

    如何在 QScrollArea 上绘制选择矩形?

    您需要QRubberBand,它应该直接应用于您用来显示要滚动的图像的ui->imageLabel 小部件。是否应该为ui->imageLabel 重载QLabel 是一个实施问题。请参阅example 了解鼠标事件,当然更好地将其应用于您的标签图像类。

    从代码的外观我了解您使用 Qt 设计器?这会使覆盖该标签类变得复杂,但您可以不使用 .ui 文件或使用event filter 来捕获给定对象的所有事件。

    当然,您目前拥有的东西最终可以打磨得足以适合实际使用。它只会为你付出更多的努力。您可以避免重载paintEvent 等,关键是在需要应用的地方直接应用正确的方法。

    // 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);
    }
    

    【讨论】:

    • 你能解释一下我应该在我的代码中改变什么吗?我尝试使用 QRubberBand 但它不起作用。
    • 我从 QRubberBand 链接添加了编辑后的样本。从我以前的经验来看,这是可行的。
    • 由于制作了新的 ui->imageLabel,我刚刚遇到了一个新问题。当我放大或缩小时,它会调整标签而不是图像的大小。在添加此步骤之前它运行良好,我该怎么办?
    • 我没有看到它,猜测可能有效:doc.qt.io/qt-5/qlabel.html#scaledContents-prop
    • 再次感谢!!真的很有帮助
    猜你喜欢
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    相关资源
    最近更新 更多