Skip to content
  • 0 Votes
    15 Posts
    472 Views
    KenAppleby 0K

    @StudentScripter

    Below is code that I can share. It's a complete example which perhaps does what you need. The void HandlesItem::paint() function is where the graphics transformations are done. It's rather long-winded but it at least shows what's required. It draws a painter path around the model items and deals with scaling and rotation of the model items as well as scaling of the graphics view.

    I'm sorry there is so much code: it's mostly the test framework. It uses mouse wheel events + modifiers to set the scale and rotation of items and the view.

    // main.cpp #include <QGraphicsRectItem> #include <QGraphicsRectItem> #include <QRandomGenerator> #include <QPainter> // A graphics path item that paints a selection graphic rectangle around a model item. class HandlesItem : public QGraphicsPathItem { public: HandlesItem(QGraphicsItem * modelItem, QGraphicsItem * parent =nullptr); void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget =nullptr) override; void setViewScale(double scale); protected: QGraphicsItem * mModelItem{ nullptr }; }; // A contentless graphics item that acts as a proxy for a model item and manages a HandlesItem for it. // The model item position must be set by setting the Proxy item position. // The model item scale and rotation must be set by the setItemScale() and setItemRotation() functions. // Model items and HandleItems are assumed to transform about their center points. class Proxy : public QGraphicsRectItem { public: Proxy(QGraphicsItem * modelItem, QGraphicsItem * parent =nullptr); void setSelected(bool selected); bool isSelected() const; void setItemRotation(double angle); void setItemScale(double scale); void setViewScale(double scale); // call to set the HandleItem's pen width according to the view scale. protected: QGraphicsItem * mModelItem{ nullptr }; HandlesItem * mHandlesItem{ nullptr }; bool mSelected{ false }; }; // -------------------------------------- HandlesItem::HandlesItem(QGraphicsItem * modelItem, QGraphicsItem * parent) : QGraphicsPathItem{ parent }, mModelItem{ modelItem } { setViewScale(1.0); setTransformOriginPoint(mModelItem->boundingRect().center()); } void HandlesItem::setViewScale(double scale) { QPen pen{ Qt::yellow }; pen.setWidthF(4.0/scale); setPen(pen); } void HandlesItem::paint(QPainter * painter, [[ maybe_unused ]] const QStyleOptionGraphicsItem * option, [[ maybe_unused ]] QWidget * widget) { const double scale{ mModelItem->scale() }; const double margin{ 8.0 / scale }; QRectF r{ mModelItem->boundingRect().adjusted(-margin, -margin, margin, margin) }; const QPointF tl{ r.topLeft() }, tr{ r.topRight() }, br{ r.bottomRight() }, bl{ r.bottomLeft() }; QTransform transform; transform.translate(r.center().x(), r.center().y()); transform.scale(mModelItem->scale(), mModelItem->scale()); transform.rotate(mModelItem->rotation()); transform.translate(-r.center().x(), -r.center().y()); const QPointF tlt{ transform.map(tl) }, trt{ transform.map(tr) }, brt{ transform.map(br) }, blt{ transform.map(bl) }; QPainterPath path; path.moveTo(tlt); path.lineTo(trt); path.lineTo(brt); path.lineTo(blt); path.lineTo(tlt); setPath(path); QGraphicsPathItem::paint(painter, option, widget); } Proxy::Proxy(QGraphicsItem * modelItem, QGraphicsItem * parent) : QGraphicsRectItem{ parent }, mModelItem{ modelItem } { mModelItem->setPos(0, 0); // the model item is positioned by the Proxy. mModelItem->setParentItem(this); setFlag(QGraphicsItem::ItemHasNoContents); mHandlesItem = new HandlesItem{ modelItem, this }; setSelected(false); } void Proxy::setSelected(bool selected) { mSelected = selected; mHandlesItem->setVisible(mSelected); update(); } bool Proxy::isSelected() const { return mSelected; } void Proxy::setItemRotation(double angle) { if (mModelItem) { mModelItem->setTransformOriginPoint(mModelItem->boundingRect().center()); mModelItem->setRotation(mModelItem->rotation() + angle); } } void Proxy::setItemScale(double scale) { if (mModelItem) { mModelItem->setTransformOriginPoint(mModelItem->boundingRect().center()); mModelItem->setScale(mModelItem->scale() * scale); } } void Proxy::setViewScale(double scale) { mHandlesItem->setViewScale(scale); } // The remaining code is a QGraphicsView and QGraphicsScene test framework for the above. #include <QGraphicsView> class GraphicsView : public QGraphicsView { public: GraphicsView(QWidget * parent); void initialise(QGraphicsScene& scene); protected: void mousePressEvent(QMouseEvent * event) override; void mouseMoveEvent(QMouseEvent * event) override; void mouseReleaseEvent(QMouseEvent *) override; void wheelEvent(QWheelEvent *) override; void setSelection(Proxy * item); void initialiseScene(); void setViewTransform(); QTransform makeTransform() const; QList<Proxy *> mItems; Proxy * mSelectedItem{ nullptr }; Proxy * mDragging{ nullptr }; QPointF mMoveScenePoint; double mScale{ 1.0 }; double mRotation{ 0.0 }; }; #include <QMainWindow> #include <QGraphicsScene> #include <QBoxLayout> class HandlesMainWindow : public QMainWindow { public: HandlesMainWindow(QWidget * parent =nullptr); protected: QGraphicsScene mScene; }; HandlesMainWindow::HandlesMainWindow(QWidget * parent) : QMainWindow(parent) { QWidget * centralwidget; QVBoxLayout * verticalLayout; GraphicsView * graphicsView; resize(532, 377); centralwidget = new QWidget(this); centralwidget->setObjectName("centralwidget"); verticalLayout = new QVBoxLayout(centralwidget); verticalLayout->setObjectName("verticalLayout"); graphicsView = new GraphicsView(centralwidget); graphicsView->setObjectName("graphicsView"); verticalLayout->addWidget(graphicsView); setCentralWidget(centralwidget); graphicsView->initialise(mScene); } #include <QMouseEvent> #include <QWheelEvent> namespace { QRandomGenerator& rng() { static QRandomGenerator sRng; return sRng; } QColor randomColor() { return QColor{ rng().bounded(64, 255), rng().bounded(64, 255), rng().bounded(64, 255) }; } QPointF randomPoint() { return QPointF{ 1.0*rng().bounded(20, 400), 1.0*rng().bounded(20, 400) }; } QRectF randomRect() { return QRectF{ 0.0, 0.0, 1.0*rng().bounded(20, 100), 1.0*rng().bounded(20, 100) }; } } GraphicsView::GraphicsView(QWidget * parent) : QGraphicsView{ parent } { setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setRenderHint(QPainter::Antialiasing); setTransformationAnchor(ViewportAnchor::NoAnchor); } void GraphicsView::initialise(QGraphicsScene& scene) { setScene(&scene); initialiseScene(); } void GraphicsView::mousePressEvent(QMouseEvent * event) { const QPoint p{ event->pos() }; QGraphicsItem * item{ itemAt(p) }; if (item) { mDragging = qgraphicsitem_cast<Proxy *>(item->parentItem()); mMoveScenePoint = mapToScene(p); } else { mDragging = nullptr; } } void GraphicsView::mouseMoveEvent(QMouseEvent * event) { const QPoint p{ event->pos() }; if (mDragging) { const QPointF sp{ mapToScene(p) }; mDragging->moveBy(sp.x() - mMoveScenePoint.x(), sp.y() - mMoveScenePoint.y()); mMoveScenePoint = sp; } } void GraphicsView::mouseReleaseEvent(QMouseEvent * event) { mDragging = nullptr; const QPoint p{ event->pos() }; QGraphicsItem * item{ itemAt(p) }; if (item) { setSelection(qgraphicsitem_cast<Proxy *>(item->parentItem())); } else { setSelection(nullptr); } } void GraphicsView::wheelEvent(QWheelEvent * event) { if (event->modifiers() == Qt::NoModifier) { double deltaScale{ 1.0 }; QPoint p = event->angleDelta(); if (p.y() > 0) { deltaScale = 1.1; } else if (p.y() < 0) { deltaScale = 1.0/1.1; } event->accept(); if (mSelectedItem) { mSelectedItem->setItemScale(deltaScale); } else { mScale = mScale * deltaScale; setViewTransform(); } } else if (event->modifiers() == Qt::ControlModifier){ QPoint p = event->angleDelta(); double rotation{ 0.0 }; if (p.y() > 0) { rotation = 2.0; } else if (p.y() < 0) { rotation = -2.0; } event->accept(); if (mSelectedItem) { mSelectedItem->setItemRotation(rotation); } else { mRotation += rotation; setViewTransform(); } } } void GraphicsView::setSelection(Proxy * item) { mSelectedItem = item; if (item) { item->setSelected(true); } for (auto i : mItems) { if (not (i == item)) { i->setSelected(false); } } } void GraphicsView::setViewTransform() { setTransform(makeTransform()); for (auto i : mItems) { i->setViewScale(mScale); } } QTransform GraphicsView::makeTransform() const { QTransform result; const QPointF center{ rect().center() }; result.translate(center.x(), center.y()); result.scale(mScale, mScale); result.rotate(mRotation); result.translate(-center.x(), -center.y()); return result; } void GraphicsView::initialiseScene() { scene()->setBackgroundBrush(QBrush{ Qt::cyan }); for (int i = 0; i < 20; i++) { QGraphicsRectItem * item{ new QGraphicsRectItem(::randomRect()) }; item->setBrush(QBrush{ ::randomColor() }); Proxy * proxy{ new Proxy{ item } }; proxy->setPos(::randomPoint()); scene()->addItem(proxy); mItems << proxy; } } #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); HandlesMainWindow w; w.show(); return a.exec(); }
  • 0 Votes
    4 Posts
    353 Views
    SGaistS

    The trick of the mouse to rotate is that the rendering is rotated independently from the item itself.

    As for the movement, unless I am mistaken, it's always moving "horizontally" with respect to the item rotation rotation. Much like when you are walking, you are going forward, when you rotate you still go forward but with a different angle than before.

  • 0 Votes
    2 Posts
    409 Views
    JoeCFDJ

    @RobotMaker said in Svg Rendering Perspective Transform on QGraphicsView Viewport:

    Some code will be helpful. And how you update it?

    try to call this after your change to update it. I use it to toggle svg pics display.
    update(const QRectF &) ==>update( boundingRect() ); I assume you overrides boundingRect();

  • std::transform over QMap

    Unsolved General and Desktop
    13
    0 Votes
    13 Posts
    3k Views
    SGaistS

    Hi,

    You can use QMap:: keyValueBegin and QMap::keyValueEnd for your use case.

  • 0 Votes
    12 Posts
    2k Views
    SGaistS

    Did you already read the Graphics View Overview in Qt's documentation ?

  • 0 Votes
    2 Posts
    583 Views
    T

    @houmingc You took that example straight from the documentation page for Rotation, which shows a picture of exactly what will happen. What more do you need? "Default angle" makes no sense. If you don't specify one there will be no rotation. It rotates around the origin along the axis. If you still don't understand, make a quick example and play around with it.

  • 0 Votes
    3 Posts
    1k Views
    R

    @Wieland
    I will try as soon as I find the time :)

  • 0 Votes
    3 Posts
    1k Views
    A

    i cant share that, why its a private one, i just need to how to change this Qt_tr_noop to tr, and not include inside static i just want to use the tr().

  • 0 Votes
    3 Posts
    2k Views
    P

    Thanks that did exactly what I needed.

  • 0 Votes
    2 Posts
    1k Views
    M

    Hi,

    I think you can do something using SharedEffect::vertexShader. I'm not an expert but you can find some information and examples here