我想在Qt的QGraphicsView中实现剪切,复制和粘贴操作。我将所有项目存储在一个班级中。我想要的是当我绘制一个项目然后我可以剪切或复制该项目并将其粘贴到我想粘贴的其他位置。任何人都可以建议我采用相同的方法。
cadgraphicsscene.cpp
#include<QtWidgets>
#include "cadgraphicsscene.h"
#include <QGraphicsSceneMouseEvent>
#include <QTextCursor>
#include <QDebug>
CadGraphicsScene::CadGraphicsScene(QObject *parent, QUndoStack *undoStack)
: QGraphicsScene(parent)
{
setFlags();
mUndoStack = undoStack;
textItem = 0;
myTextColor = Qt::black;
// connect selectionChanged signal to selectItems slot
connect(this, SIGNAL(selectionChanged()), this, SLOT(selectItems()));
}
void CadGraphicsScene::setFlags()
{
// set/unset all the flags
mFirstClick = true;
mSecondClick = false;
mThirdClick = false;
mPaintFlag = false;
}
void CadGraphicsScene::setMode(Mode mode)
{
// determine the mode set
entityMode = mode;
if (entityMode == NoMode)
areItemsSelectable(true);
else
areItemsSelectable(false);
}
void CadGraphicsScene::editorLostFocus(mText *item)
{
QTextCursor cursor = item->textCursor();
cursor.clearSelection();
item->setTextCursor(cursor);
if (item->toPlainText().isEmpty()) {
removeItem(item);
item->deleteLater();
}
}
void CadGraphicsScene::areItemsSelectable(bool b)
{
// make items selectable
foreach (QGraphicsItem *item, itemList)
{
item->setFlag(QGraphicsItem::ItemIsSelectable, b);
item->setFlag(QGraphicsItem::ItemIsMovable, b);
}
}
void CadGraphicsScene::deleteItems()
{
// delete selected items
foreach (QGraphicsItem *item, itemList)
{
if (item->isSelected())
{
mUndoStack->push(new CadCommandDelete(this, item));
item->setSelected(false);
}
}
}
void CadGraphicsScene::selectItems()
{
// refresh record of selected items and their starting positions
selectedItems.clear();
foreach (QGraphicsItem *item, itemList)
{
if (item->isSelected())
{
if (dynamic_cast<QGraphicsItem *>(item))
{
selectedItems.append(qMakePair(
dynamic_cast<QGraphicsItem *>(item),
item->scenePos()));
}
}
}
}
void CadGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
// mousePressEvent in the graphicsScene
static int id = 0;
switch (entityMode)
{
case NoMode:
qDebug() << "No Mode";
break;
case PointMode:
pointItem = new Point(++id);
pointItem->setPos(mouseEvent->scenePos());
itemList.append(pointItem);
mUndoStack->push(new CadCommandAdd(this, pointItem));
break;
case LineMode:
if (mFirstClick)
{
start_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
end_p = mouseEvent->scenePos();
mPaintFlag = true;
mSecondClick = false;
}
if (mPaintFlag)
{
lineItem = new Line(++id, start_p, end_p);
lineItem->setLine(start_p.x(), start_p.y(), end_p.x(), end_p.y());
itemList.append(lineItem);
mUndoStack->push(new CadCommandAdd(this, lineItem));
setFlags();
}
break;
case CircleMode:
if (mFirstClick)
{
start_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
end_p = mouseEvent->scenePos();
mPaintFlag = true;
mSecondClick = false;
}
if (mPaintFlag)
{
circleItem = new Circle(++id, start_p, end_p);
itemList.append(circleItem);
mUndoStack->push(new CadCommandAdd(this, circleItem));
setFlags();
}
break;
case EllipseMode:
if (mFirstClick)
{
start_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = true;
}
else if (!mFirstClick && mSecondClick)
{
mid_p = mouseEvent->scenePos();
mFirstClick = false;
mSecondClick = false;
mThirdClick = true;
}
else if (!mSecondClick && mThirdClick)
{
end_p = mouseEvent->scenePos();
mThirdClick = false;
mPaintFlag = true;
}
if (mPaintFlag)
{
ellipseItem = new Ellipse(++id, start_p, mid_p, end_p);
itemList.append(ellipseItem);
mUndoStack->push(new CadCommandAdd(this, ellipseItem));
setFlags();
}
break;
case TextMode:
textItem = new mText(++id);
textItem->setFont(myFont);
itemList.append(textItem);
mUndoStack->push(new CadCommandAdd(this, textItem));
textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
textItem->setZValue(1000.0);
connect(textItem, SIGNAL(lostFocus(mText*)),
this, SLOT(editorLostFocus(mText*)));
connect(textItem, SIGNAL(selectedChange(QGraphicsItem*)),
this, SIGNAL(itemSelected(QGraphicsItem*)));
addItem(textItem);
textItem->setDefaultTextColor(myTextColor);
textItem->setPos(mouseEvent->scenePos());
emit textInserted(textItem);
setFlags();
default:
;
}
QGraphicsScene::mousePressEvent(mouseEvent);
}
void CadGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
// if any items moved, then create undo commands
foreach (itemPos item, selectedItems)
{
if (item.first->scenePos() != item.second)
{
mUndoStack->push(new CadCommandMove(item.first, item.second.x(),
item.second.y(), item.first->x(),
item.first->y()));
}
}
// refresh record of selected items and call base mouseReleaseEvent
selectItems();
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
void CadGraphicsScene::writeStream(QXmlStreamWriter *stream)
{
// write entities in a file
foreach (QGraphicsItem *item, itemList)
{
if (items().contains(item))
{
if (item->type() == Point::Type)
{
Point *myItem = dynamic_cast<Point *>(item);
stream->writeStartElement("Point");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("x", QString::number(myItem->x()));
stream->writeAttribute("y", QString::number(myItem->y()));
stream->writeEndElement(); //end of Point Item
}
else if (item->type() == Line::Type)
{
Line *myItem = dynamic_cast<Line *>(item);
stream->writeStartElement("Line");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("x1", QString::number(myItem->start_p.x()));
stream->writeAttribute("y1", QString::number(myItem->start_p.y()));
stream->writeAttribute("x2", QString::number(myItem->end_p.x()));
stream->writeAttribute("y2", QString::number(myItem->end_p.y()));
stream->writeEndElement(); //end of Line Item
}
else if (item->type() == Circle::Type)
{
Circle *myItem = dynamic_cast<Circle *>(item);
stream->writeStartElement("Circle");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("cx", QString::number(myItem->center_p.x()));
stream->writeAttribute("cy", QString::number(myItem->center_p.y()));
stream->writeAttribute("radius", QString::number(myItem->radius));
stream->writeEndElement(); //end of Circle Item
}
else if (item->type() == Ellipse::Type)
{
Ellipse *myItem = dynamic_cast<Ellipse *>(item);
stream->writeStartElement("Ellipse");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("cx", QString::number(myItem->p1.x()));
stream->writeAttribute("cy", QString::number(myItem->p1.y()));
stream->writeAttribute("majR", QString::number(myItem->majRadius));
stream->writeAttribute("minR", QString::number(myItem->minRadius));
stream->writeEndElement(); //end of Ellipse Item
}
else if (item->type() == mText::Type)
{
mText *myItem = dynamic_cast<mText *>(item);
stream->writeStartElement("MText");
stream->writeAttribute("id", QString::number(myItem->id));
stream->writeAttribute("x1", QString::number(myItem->x()));
stream->writeAttribute("y1", QString::number(myItem->y()));
stream->writeEndElement(); //end of Text Item
}
}
}
}
void CadGraphicsScene::readStream(QXmlStreamReader *stream)
{
while (!stream->atEnd())
{
stream->readNext();
if (stream->isStartElement() && stream->name() == "Point")
{
qreal x = 0.0, y = 0.0;
foreach (QXmlStreamAttribute attribute, stream->attributes())
{
if (attribute.name() == "xCoord")
x = attribute.value().toString().toDouble();
if (attribute.name() == "yCoord")
y = attribute.value().toString().toDouble();
}
// Point *myPoint = new Point;
// addItem(myPoint);
// myPoint->setPos(x,y);
}
}
}
mainwindow.cpp
#include "mainwindow.h"
#include <QGraphicsSceneMouseEvent>
#include <QMouseEvent>
#include <QDebug>
#include <QHBoxLayout>
#include <QDateTime>
#include <QFileDialog>
#include <QMessageBox>
#include <QTextEdit>
#include <QXmlStreamWriter>
#include <QShortcut>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
setupUi(this);
setWindowTitle(tr("eCAD"));
setCentralWidget(mdiArea);
Ui_MainWindow::statusBar->showMessage("Welcome to eCAD");
// connect(pointButton, SIGNAL(clicked()),
// this, SLOT(drawPoint()));
// connect(lineButton, SIGNAL(clicked()),
// this, SLOT(drawLine()));
// connect(circleButton, SIGNAL(clicked()),
// this, SLOT(drawCircle()));
// connect(ellipseButton, SIGNAL(clicked()),
// this, SLOT(drawEllipse()));
connect(actionPoints, SIGNAL(triggered()),
this, SLOT(drawPoint()));
connect(actionLine, SIGNAL(triggered()),
this, SLOT(drawLine()));
connect(actionCircle, SIGNAL(triggered()),
this, SLOT(drawCircle()));
connect(actionEllipse, SIGNAL(triggered()),
this, SLOT(drawEllipse()));
connect(actionMText, SIGNAL(triggered()),
this,SLOT(drawText()));
connect(actionNew, SIGNAL(triggered()),
this, SLOT(newFile()));
connect(actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
connect(actionPrint, SIGNAL(triggered()),
this, SLOT(filePrint()));
connect(actionPrintPreview, SIGNAL(triggered()),
this, SLOT(filePrintPreview()));
connect(actionZoom_In, SIGNAL(triggered()),
this, SLOT(on_actionZoom_In_triggered()));
connect(actionZoom_Out, SIGNAL(triggered()),
this, SLOT(on_actionZoom_Out_triggered()));
connect(actionInsert_Image,SIGNAL(triggered()),
this, SLOT(on_actionInsert_Image_triggered()));
// toggle actions to false
toggleActions(0);
}
MainWindow::~MainWindow()
{
}
void MainWindow::toggleActions(bool b)
{
actionSave->setEnabled(b);
actionPrint->setEnabled(b);
actionPrintPreview->setEnabled(b);
actionZoom_In->setEnabled(b);
actionZoom_Out->setEnabled(b);
actionPoints->setEnabled(b);
actionLine->setEnabled(b);
actionCircle->setEnabled(b);
actionEllipse->setEnabled(b);
actionMText->setEnabled(b);
actionInsert_Image->setEnabled(b);
}
void MainWindow::setActions()
{
// shortcut keys
new QShortcut(QKeySequence(Qt::Key_Escape),
this, SLOT(setNoMode()));
new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_U),
this, SLOT(showUndoStack()));
new QShortcut(QKeySequence(Qt::Key_Delete),
this, SLOT(deleteItems()));
QAction *actionUndo = view->undoStack->createUndoAction(this);
QAction *actionRedo = view->undoStack->createRedoAction(this);
actionUndo->setShortcut(QKeySequence::Undo);
actionRedo->setShortcut(QKeySequence::Redo);
menuEdit->addAction(actionUndo);
menuEdit->addAction(actionRedo);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneMouseMove)
{
QGraphicsSceneMouseEvent *mouseEvent =
static_cast<QGraphicsSceneMouseEvent *>(event);
QString showMessage = QString("Mouse move (%1,%2)").
arg(mouseEvent->scenePos().x()).
arg(mouseEvent->scenePos().y());
Ui_MainWindow::statusBar->showMessage(showMessage);
}
}
void MainWindow::newFile()
{
// creates a new file
createMdiView();
view->newFile();
view->scene->installEventFilter(this);
view->show();
setActions();
// toggle actions to true
toggleActions(1);
}
void MainWindow::filePrintPreview()
{
// display print preview dialog
QPrinter printer(QPrinter::HighResolution);
QPrintPreviewDialog preview(&printer, this);
connect(&preview, SIGNAL(paintRequested(QPrinter *)), SLOT(print(QPrinter *)));
preview.exec();
}
void MainWindow::filePrint()
{
// display print dialog and if accepted print
QPrinter printer(QPrinter::HighResolution);
QPrintDialog dialog(&printer, this);
if (dialog.exec() == QDialog::Accepted)
print(&printer);
}
void MainWindow::print(QPrinter *printer)
{
// print the page
QPainter painter(printer);
int w = printer->pageRect().width();
int h = printer->pageRect().height();
QRect page(0, 0, w, h);
QFont font = painter.font();
font.setPixelSize((w+h)/100);
painter.setFont(font);
painter.drawText(page, Qt::AlignBottom | Qt::AlignRight,
QDateTime::currentDateTime().
toString(Qt::DefaultLocaleShortDate));
page.adjust(w/20, h/20, -w/20, -h/20);
view->scene->render(&painter, page);
}
CadGraphicsView *MainWindow::createMdiView()
{
// creates a graphicsView and add it to the MDI window
view = new CadGraphicsView;
mdiArea->addSubWindow(view);
return view;
}
void MainWindow::showUndoStack()
{
// calls an undo stack function of graphicsView
view->showUndoStack();
}
void MainWindow::drawPoint()
{
// calls the drawPoint function of graphicsView
view->drawPoint();
}
void MainWindow::setNoMode()
{
// calls the setNoMode function of graphicsView
view->setNoMode();
}
void MainWindow::drawLine()
{
// calls the drawLine function of graphicsView
view->drawLine();
}
void MainWindow::drawCircle()
{
// calls the drawCircle function of graphicsView
view->drawCircle();
}
void MainWindow::drawEllipse()
{
// calls the drawEllipse function of graphicsView
view->drawEllipse();
}
void MainWindow::drawText()
{
// calls the drawEllipse function of graphicsView
view->drawText();
}
void MainWindow::deleteItems()
{
// calls the deleteItems function of graphicsScene
view->scene->deleteItems();
}
void MainWindow::on_actionOpen_triggered()
{
// open file dialog box
QString filename = QFileDialog::getOpenFileName(this,
tr("Open File"),
QString(),
tr("file Name(*.xml)"));
QMainWindow::statusBar()->showMessage("File opened successfully");
if (!filename.isEmpty())
{
QFile file(filename);
if (!file.open(QIODevice::ReadOnly))
{
QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
return;
}
else
{
QXmlStreamReader stream(&file);
CadGraphicsScene *newScene = new CadGraphicsScene(this,
view->undoStack);
while (!stream.atEnd())
{
stream.readNext();
if (stream.isStartElement())
{
if (stream.name() == "SceneData")
newScene->readStream(&stream);
else
stream.raiseError(QString("Unrecognised element '%1'").
arg(stream.name().toString()));
}
}
// check if error occured
if (stream.hasError())
{
file.close();
QMessageBox::warning(this, "Error",
QString("Failed to load '%1' (%2)").
arg(filename).arg(stream.errorString()));
delete newScene;
return;
}
/* close file, display new scene, delete old scene
and display useful message */
file.close();
view->setScene( newScene );
delete view->scene;
view->scene = newScene;
QMessageBox::warning(this, "Done",
QString("Loaded '%1'").arg(filename));
return;
}
}
}
void MainWindow::on_actionSave_triggered()
{
// save file dialog box
QString filename = QFileDialog::getSaveFileName(this,
tr("Save File"),
QString(),
tr("file Name(*.xml)"));
if(!filename.isEmpty())
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
return;
}
else
{
QXmlStreamWriter xmlWriter(&file);
xmlWriter.setAutoFormatting(true);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("SceneData");
xmlWriter.writeAttribute("version", "v1.0");
xmlWriter.writeStartElement("Entities");
view->scene->writeStream(&xmlWriter);
xmlWriter.writeEndElement(); //end of Entities
xmlWriter.writeEndElement(); //end of SceneData
xmlWriter.writeEndDocument();
QMessageBox::warning(this, "Saved",
QString("Saved Scene Data to '%1'").
arg(filename));
file.close();
}
}
}
void MainWindow::on_actionZoom_In_triggered()
{
// Zoom in
//graphicsView->scale(scaleFactor, scaleFactor);
}
void MainWindow::on_actionZoom_Out_triggered()
{
// Zoom out
//graphicsView->scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
void MainWindow::on_actionInsert_Image_triggered()
{
// insert image dialog
QString imagePath = QFileDialog::getOpenFileName(this, tr("open File"),"",
tr("JPEG(*.jpg *.jpeg);;PNG(*.png)"));
imageObject = new QImage();
imageObject->load(imagePath);
image = QPixmap::fromImage(*imageObject);
//scene =new CadGraphicsScene(this);
//scene->addPixmap(image);
//scene->setSceneRect(image.rect());
//graphicsView->setScene(scene);
}
使用以下答案我将使上下文菜单正常工作,同时切割操作也可以正常工作。但我的复制和粘贴操作无效。我有不同的类,如点,椭圆等不同的类。我正在添加我的实体类之一,建议我如何进一步继续/
circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
#include <QPainter>
#include <QGraphicsItem>
#include "qmath.h"
class Circle : public QObject, public QGraphicsItem
{
Q_OBJECT
public:
Circle(int, QPointF, QPointF);
QRectF boundingRect() const;
virtual void paint(QPainter *painter,
const QStyleOptionGraphicsItem *option,
QWidget *widget);
enum { Type = UserType + 3 };
int type() const;
int id;
QPointF center_p, end_p, move_p;
qreal radius;
private:
QVector<QPointF> stuff;
};
#endif // CIRCLE_H
circle.cpp
#include "circle.h"
Circle::Circle(int i, QPointF p1, QPointF p2)
{
// assigns id
id = i;
/* set values of center point, end point
and calculate radius of circle */
center_p = p1;
end_p = p2;
radius = qSqrt(qPow((end_p.x()-center_p.x()), 2)
+ qPow((end_p.y()-center_p.y()), 2));
}
int Circle::type() const
{
// Enable the use of qgraphicsitem_cast with circle item.
return Type;
}
QRectF Circle::boundingRect() const
{
// bounding rectangle for circle
return QRectF((center_p.x()-radius), (center_p.y()-radius),
(2*radius), (2*radius));
}
void Circle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget)
{
// draws/paints the path of circle
QPen paintpen(Qt::black);
paintpen.setWidth(1);
painter->setRenderHint(QPainter::Antialiasing);
if (isSelected())
{
// sets brush for center point
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::red);
painter->setPen(paintpen);
painter->drawEllipse(center_p, 2, 2);
// sets pen for circumference
paintpen.setStyle(Qt::DashLine);
paintpen.setColor(Qt::black);
painter->setBrush(Qt::NoBrush);
painter->setPen(paintpen);
painter->drawEllipse(center_p, radius, radius);
}
else
{
painter->setBrush(Qt::SolidPattern);
paintpen.setColor(Qt::black);
painter->setPen(paintpen);
painter->drawEllipse(center_p, 2, 2);
painter->setBrush(Qt::NoBrush);
painter->drawEllipse(center_p, radius, radius);
}
}
cadgraphicsscene.cpp
void CadGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* evt)
{
QList<QGraphicsItem*> itemList = items(evt->scenePos());
QGraphicsItem* item = itemList.isEmpty() ? 0x00 : itemList.first();
static QGraphicsItem* storedItem = 0x00;
QMenu menu;
//Item found
if(item)
{
menu.addAction("Copy");
menu.addAction("Cut");
}
//An item has been copied/cut
if(storedItem)
{
menu.addAction("Paste");
}
QAction* action = menu.exec(evt->screenPos());
if(action != 0x00)
{
if(action->text() == "Copy")
{
if(storedItem)
delete storedItem;
storedItem = createCopy(item); //has to be implemented
}
else if(action->text() == "Cut")
{
if(storedItem)
delete storedItem;
storedItem = item;
removeItem(item);
}
else if(action->text() == "Paste")
{
QGraphicsItem* item = createCopy(storedItem);
if(item) {
addItem(item);
item->setPos(evt->scenePos());
}
}
}
}
QGraphicsItem* CadGraphicsScene::createCopy(QGraphicsItem* item)
{
if(item == 0x00)
return 0x00;
if(item->type() == Circle::Type) //QGraphicsRectItem
{
Circle* copy = new Circle(-1, center_p, end_p);
return copy;
}
return 0x00;
}
答案 0 :(得分:0)
一种可能的方法是将一个插槽连接到视图的customContextMenuRequested信号,请注意必须激活:
view->setContextMenuPolicy(Qt::CustomContextMenu)
在那里你可以获得场景中光标的当前位置。当在该位置有物品时,使用QMenu复制/剪切物品,存储它(或至少存储您需要的信息)......如果没有物品你可以粘贴它(意味着重复使用先前剪切的项目或使用存储的信息创建新项目。
其他方法是创建自定义图形项并覆盖contextMenuEvent或处理mousePressEvent ......
使用您定义的&#34; CadGraphicsScene&#34;的示例覆盖&#34; contextMenuEvent&#34; -Function:
void CadGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent* evt)
{
QList<QGraphicsItem*> itemsAt = items(evt->scenePos());
QGraphicsItem* item = itemsAt.isEmpty() ? 0x00 : itemsAt.first();
static QGraphicsItem* storedItem = 0x00;
QMenu menu;
//Item found
if(item)
{
menu.addAction("Copy");
menu.addAction("Cut");
}
//An item has been copied/cut
if(storedItem)
{
menu.addAction("Paste");
}
QAction* action = menu.exec(evt->screenPos());
if(action != 0x00)
{
if(action->text() == "Copy")
{
if(storedItem)
delete storedItem;
storedItem = createCopy(item); //has to be implemented
}
else if(action->text() == "Cut")
{
if(storedItem)
delete storedItem;
storedItem = item;
removeItem(item);
}
else if(action->text() == "Paste")
{
QGraphicsItem* item = createCopy(storedItem);
if(item) {
addItem(item);
item->setPos(evt->scenePos());
}
}
}
}
QGraphicsItem* CadGraphicsScene::createCopy(QGraphicsItem* item)
{
if(item == 0x00)
return 0x00;
if(item->type() == QGraphicsRectItem::Type) //QGraphicsRectItem
{
QGraphicsRectItem* rectItem = (QGraphicsRectItem*)item;
QGraphicsRectItem* copy = new QGraphicsRectItem(item->parentItem());
copy->setRect(rectItem->rect());
copy->setPen(rectItem->pen());
copy->setBrush(rectItem->brush());
return copy;
}
return 0x00;
}
本例中的复制函数只处理QGraphicsRectItem,必须扩展所有必需的类型。
测试了使用Qt 4.8 ...
复制圆的例子:
Circle* copy = new Circle(-1, center_p, end_p); //Dont know where you get your ID
然后将&#34; copy&#34; -object添加到场景中。