如何在 GraphicsView 上绘制一个选择矩形,矩形外有黑色区域?

问题描述 投票:0回答:1

我是 Qt 的新手,我创建了一个图像查看器应用程序,我想在图形视图上裁剪图像,使其在矩形之外有黑色区域。如下所示: enter image description here

我试过这个代码: 在 mainwindow.h 中:


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPen>
#include <QGraphicsRectItem>
#include <QGraphicsEllipseItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QWidget>
#include <QWheelEvent>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow

{
    Q_OBJECT


public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void wheelEvent(QWheelEvent *event);
    bool CropFlag=false;
    QPixmap globalimage;
    QGraphicsRectItem *ItemRect;



protected:
    void mousePressEvent(QMouseEvent * event) ;
    void mouseMoveEvent(QMouseEvent* event) ;
    void mouseReleaseEvent(QMouseEvent* event) ;
    bool eventFilter(QObject *obj, QEvent *ev);


private slots:
   
    void on_cropbtn_clicked();
    
private:
    QGraphicsScene *Scene=new QGraphicsScene();
    Ui::MainWindow *ui;
    QPointF PressPoint;
    QPointF ReleasePoint;
    QPointF MovePoint;

};

#endif // MAINWINDOW_H

这是mainwindow.cpp:


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QGraphicsScene>



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    Scene=new QGraphicsScene(this);
    globalimage.load("C:/Users/783684/Pictures/40557.jpg");
    Scene->addPixmap(globalimage);
    ui->graphicsView->setScene(Scene);
    ui->graphicsView->viewport()->installEventFilter(this);
    ui->graphicsView->setMouseTracking(true);

  }

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::mousePressEvent(QMouseEvent * event)
{

}

void MainWindow::mouseMoveEvent(QMouseEvent* event)
{

}

void MainWindow::mouseReleaseEvent(QMouseEvent* event)
{

}

bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
{
    if(ui->graphicsView->viewport()&&CropFlag==true){

        if(ev->type()==QEvent::MouseMove)
        {
            QMouseEvent *mEvent = (QMouseEvent*)ev;
            MovePoint = ui->graphicsView->mapToScene(mEvent->pos()); 
            
        }
        else if(ev->type()==QEvent::MouseButtonPress)
        {
            QMouseEvent *mEvent = (QMouseEvent*)ev;
            PressPoint = ui->graphicsView->mapToScene(mEvent->pos()); 
            
        }
        else if(ev->type()==QEvent::MouseButtonRelease)
        {
            QMouseEvent *mEvent = (QMouseEvent*)ev;
            ReleasePoint = ui->graphicsView->mapToScene(mEvent->pos()); 
                               
            QRectF cropRectF(PressPoint, ReleasePoint);
            QRect cropRect(cropRectF.toRect());
            QPixmap croppedPixmap = globalimage.copy(cropRect);
            
            QList<QGraphicsItem*> overlayItems = ui->graphicsView->scene()->items();
            for (QGraphicsItem* item : overlayItems)
            {
                if (item->type() == QGraphicsRectItem::Type)
                {
                    ui->graphicsView->scene()->removeItem(item);
                    delete item; // Clean up the removed item
                }
            }
            QGraphicsPixmapItem* croppedImageItem = new QGraphicsPixmapItem(croppedPixmap);
            // Create a new QGraphicsRectItem as an overlay with a darkening effect
            QGraphicsRectItem* darkOverlayItem = new QGraphicsRectItem();
            darkOverlayItem->setRect(ui->graphicsView->viewport()->rect());
            darkOverlayItem->setBrush(QBrush(QColor(0, 0, 0, 128)));
            darkOverlayItem->setPen(QPen(QColor(0,0,255,0)));



            // Add the overlay item and cropped image item to the scene
            ui->graphicsView->scene()->addItem(darkOverlayItem);
            ui->graphicsView->scene()->addItem(croppedImageItem);

            // Set the position of the cropped image item as needed
            croppedImageItem->setPos(PressPoint);


        }
    }
    return false;
}






void MainWindow::on_cropbtn_clicked()
{
    CropFlag=true;
    ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);

}

这是我的输出的屏幕截图: enter image description here

c++ qt crop qgraphicsview
1个回答
0
投票

你可以使用3个

QGraphicsItems
:

图像始终可见;另外两个可以只显示和隐藏,而不是重复创建它们。

可以使用

QGraphicsView::rubberBandRect
定义裁剪区域。然后根据需要映射结果。

QGraphicsView
的视口上安装事件过滤器来拦截鼠标释放事件,您可以通过
QPixmap::copy
获取图像中被橡皮筋覆盖的部分。

示例:

#include <QApplication>
#include <QtWidgets>

bool cropFlag=false;
QGraphicsView *graphicsView;
QGraphicsScene *scene;
QGraphicsPixmapItem* croppedImageItem;
QGraphicsRectItem* darkOverlayItem;
QGraphicsPixmapItem* pixmapItem;

class EventFilter : public QObject
{
protected:
    bool eventFilter(QObject *watched, QEvent *event) override
    {
        if(event->type() == QEvent::MouseButtonRelease && cropFlag)
        {
            //avoid this being triggered when only clicking
            if(!graphicsView->rubberBandRect().isEmpty())
            {
                //the cropped part is the rubber band rect mapped to the scene
                //this is what worked in this example
                //but it might need to change based on use case
                QPixmap croppedPixmap = pixmapItem->pixmap().copy(graphicsView->mapToScene(graphicsView->rubberBandRect()).boundingRect().toRect());

                if(croppedPixmap.isNull())
                    return QObject::eventFilter(watched, event);

                //new cropped piece
                croppedImageItem->setPixmap(croppedPixmap);
                //just use top left of rubber band rect mapped to scene (same note as the copied pixmap)
                croppedImageItem->setPos(graphicsView->mapToScene(graphicsView->rubberBandRect().topLeft()));

                croppedImageItem->show();
                darkOverlayItem->show();
            }
        }

        return QObject::eventFilter(watched, event);
    }
};

int main(int argc,char*argv[])
{
    QApplication a(argc, argv);

    QWidget w;
    QVBoxLayout l;
    QPushButton cropSwitchBtn("Crop");
    graphicsView = new QGraphicsView;
    scene = new QGraphicsScene();
    EventFilter eventFilter;

    w.setLayout(&l);
    l.addWidget(&cropSwitchBtn);
    l.addWidget(graphicsView);

    graphicsView->setScene(scene);
    graphicsView->viewport()->installEventFilter(&eventFilter);
    graphicsView->installEventFilter(&eventFilter);
    graphicsView->setMouseTracking(true);

    pixmapItem = new QGraphicsPixmapItem;
    pixmapItem->setPixmap(QPixmap("image.png"));

    croppedImageItem = new QGraphicsPixmapItem;

    darkOverlayItem = new QGraphicsRectItem();
    darkOverlayItem->setRect(pixmapItem->boundingRect());
    darkOverlayItem->setBrush(QBrush(QColor(0, 0, 0, 128)));

    //pixmap first
    scene->addItem(pixmapItem);
    //then the overlay (must be added before croppedImageItem)
    scene->addItem(darkOverlayItem);
    scene->addItem(croppedImageItem);

    //keep them hidden until cropping is enabled
    croppedImageItem->hide();
    darkOverlayItem->hide();

    cropSwitchBtn.connect(&cropSwitchBtn, &QPushButton::clicked, [=]()
    {
        //on and off switch
        cropFlag = !cropFlag;

        if(cropFlag)
        {
            graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
            darkOverlayItem->setBrush(QBrush(QColor(0, 0, 0, 128)));
        }
        else
        {
            graphicsView->setDragMode(QGraphicsView::NoDrag);
            darkOverlayItem->setBrush(QBrush(QColor(0, 0, 0, 0)));
            croppedImageItem->hide();
            darkOverlayItem->hide();
        }
    });

    w.show();

    return a.exec();
}

演示:

注意:这是一个基本示例,并不适用于所有情况,您可能需要根据您的用例进行调整。

© www.soinside.com 2019 - 2024. All rights reserved.