我是 Qt 的新手,我创建了一个图像查看器应用程序,我想在图形视图上裁剪图像,使其在矩形之外有黑色区域。如下所示:
我试过这个代码: 在 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);
}
你可以使用3个
QGraphicsItems
:
QGraphicsPixmapItem
:一个用于实际图像,另一个用于裁剪部分。QGraphicsRectItem
:用于覆盖在裁剪部分下方,使其看起来被裁剪。图像始终可见;另外两个可以只显示和隐藏,而不是重复创建它们。
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();
}
注意:这是一个基本示例,并不适用于所有情况,您可能需要根据您的用例进行调整。