I want my QGraphicsPixmapItem become selectable (i.e. clickable in more general way) on QGraphicScene but it doesn't. I'm actually modifying Qt's Diagram Scene sample, where QGraphicsItem's subclass is used and is selectable. I appreciate your help.
cpp code (partial):
#include <iostream>
#include <QtGui>
#include "overlayPixmapItem.h"
OverlayPixmapItem::OverlayPixmapItem(DiagramType diagramType, QMenu *contextMenu,
QPixmap img, QGraphicsItem *parent,
QGraphicsScene *scene)
: QGraphicsPixmapItem(img, parent), QObject()
{
myDiagramType = diagramType;
myContextMenu = contextMenu;
this->setAcceptsHoverEvents(true);
this->setAcceptHoverEvents(true); //
this->setAcceptedMouseButtons(Qt::LeftButton);
this->setAcceptedMouseButtons(Qt::RightButton);
this->acceptDrops();
setFlag(QGraphicsItem::ItemIsMovable, true);
setFlag(QGraphicsItem::ItemIsSelectable, true);
this->setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
}
:
header (partial):
#ifndef OVERLAYPIXMAPITEM_H
#define OVERLAYPIXMAPITEM_H
#include <QGraphicsPixmapItem>
#include <QList>
#include <QObject>
class QPixmap;
class QGraphicsItem;
class QGraphicsScene;
class QTextEdit;
class QGraphicsSceneMouseEvent;
class QMenu;
class QGraphicsSceneContextMenuEvent;
class QPainter;
class QStyleOptionGraphicsItem;
class QWidget;
class QPolygonF;
class OverlayPixmapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
enum { Type = UserType + 15 };
enum DiagramType { Crosshair };
OverlayPixmapItem(DiagramType diagramType, QMenu *contextMenu,
QPixmap img, QGraphicsItem *parent = 0, QGraphicsScene *scene = 0);
DiagramType diagramType() const { return myDiagramType; }
QPolygonF polygon() const { return myPolygon; }
int type() const { return Type;}
protected:
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
void hoverEnterEvent ( QGraphicsSceneHoverEvent * event );
void hoverLeaveEvent ( QGraphicsSceneHoverEvent * event );
public: signals:
void mouseHoveredOnElem(OverlayPixmapItem *i);
void mouseHoveredOutOfElem(OverlayPixmapItem *i);
private:
DiagramType myDiagramType;
QPolygonF myPolygon;
QMenu *myContextMenu;
};
#endif // OVERLAYPIXMAPITEM_H
As pointed out in my first comment, you call setAcceptedMouseButtons() method twice. While the first call actually set the correct button to be accepted, the second call make this setting lost.
To accept both buttons on this item, you have to combine Qt MouseButtons flags, this way :
item->setAcceptedMouseButtons(Qt::LeftButton|Qt::RightButton) ;
Related
I have a QGraphicsView in a QDockWidget, in which I'm displaying a PNG image. If I create a QPixMapItem in the dockwidget's constructor, and call a dockwidget's member function (a public slot) from within the constructor to display the image, it works fine.
However, if I invoke the slot from my MainWindow (a class called 'IView') via a signal, then the image does not show. What am I doing wrong?
Dockwidget construcor:
IvConfDockWidget::IvConfDockWidget(IView *parent) :
QDockWidget(parent),
ui(new Ui::IvConfDockWidget)
{
ui->setupUi(this);
MyGraphicsView *zoomGraphicsView = new MyGraphicsView();
MyGraphicsScene *zoomScene = new MyGraphicsScene();
ui->zoomLayout->addWidget(zoomGraphicsView);
QPixmap zoomPixmap = QPixmap("/home/mischa/logo.png");
QGraphicsPixmapItem *zoomPixmapItem = new QGraphicsPixmapItem(zoomPixmap);
updateZoomWindowReceived(zoomPixmapItem); // does not work if called from MainWindow
}
Here is the public slot:
void IvConfDockWidget::updateZoomWindowReceived(QGraphicsPixmapItem *zoomPixmapItem)
{
zoomGraphicsView->resetMatrix();
zoomScene->clear();
zoomScene->addItem(zoomPixmapItem);
zoomGraphicsView->setScene(zoomScene);
zoomGraphicsView->show();
}
If I comment out updateZoomWindowReceived() in the constructor, and call it via a signal from my MainWindow, then the graphics does not show. Here is the code in my MainWindow:
IvConfDockWidget *icdw = new IvConfDockWidget;
connect(this, &IView::updateZoomWindow, icdw, &IvConfDockWidget::updateZoomWindowReceived);
QPixmap zoomPixmap = QPixmap("/home/mischa/logo.png");
icdw->zoomGraphicsView->resetMatrix();
QGraphicsPixmapItem *newItem = new QGraphicsPixmapItem(zoomPixmap);
emit updateZoomWindow(newItem);
And for completeness, my derived versions of QGraphicsView and QGraphicsScene:
#define MYGRAPHICSVIEW_H
#include <QGraphicsView>
#include <QDebug>
#include <QMouseEvent>
#include <QScrollBar>
class MyGraphicsView : public QGraphicsView
{
Q_OBJECT
private:
QPointF rightDragStartPos;
QPointF rightDragCurrentPos;
QPointF rightDragEndPos;
QPointF leftDragStartPos;
QPointF leftDragCurrentPos;
QPointF leftDragEndPos; // unused
QPointF middleDragStartPos;
QPointF middleDragCurrentPos;
QPointF middleDragEndPos;
bool rightButtonPressed = false;
bool leftButtonPressed = false;
bool middleButtonPressed = false;
QPoint previousMousePoint;
bool _pan = false;
int _panStartX = 0;
int _panStartY = 0;
public:
explicit MyGraphicsView();
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
QScrollBar *sxbar = nullptr;
QScrollBar *sybar = nullptr;
QString middleMouseMode = "DragMode";
int x = 0;
int y = 0;
signals:
void currentMousePos(QPointF);
void rightDragTravelled(QPointF);
void middleDragTravelled(QPointF pointStart, QPointF pointEnd);
void middleWCSTravelled(QPointF pointStart, QPointF pointEnd);
void middleWCSreleased();
void leftDragTravelled(QPointF pointStart, QPointF pointEnd);
void rightPress();
void leftPress(QPointF pointStart);
void middlePress(QPointF point);
void leftButtonReleased();
void rightButtonReleased();
void middleButtonReleased();
void middlePressResetCRPIX();
public slots:
void updateMiddleMouseMode(QString mode);
};
#endif // MYGRAPHICSVIEW_H
and
#ifndef MYGRAPHICSSCENE_H
#define MYGRAPHICSSCENE_H
#include <QObject>
#include <QGraphicsScene>
#include <QKeyEvent>
class MyGraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
MyGraphicsScene();
signals:
void itemDeleted();
protected:
void keyReleaseEvent(QKeyEvent * keyEvent);
};
#endif // MYGRAPHICSSCENE_H
I figured it out. My MainWindow uses a hybrid drive/RAM data model which can be in different states, and it happened that in one of the states the signal was never emitted. Once I fixed that, the behavior is as desired.
Sorry for the noise.
I have a Box class that inherits from QPushButton. I want to have a onClick event on the button by using connect (SIGNAL and SLOT) and call a custom function onClick() declared in box.h
box.h
#ifndef BOX_H
#define BOX_H
#include <QPushButton>
class Box : public QPushButton {
public:
Box(const QString& text, QWidget* parent = nullptr);
void onClick();
};
#endif // BOX_H
//box.cpp
#include "box.h"
Box::Box(const QString& text, QWidget* parent)
: QPushButton(text, parent)
{
connect(this, SIGNAL(clicked()), SLOT(this->onClick()));
}
void Box::onClick()
{
this->setText("Something");
}
your box needs the label for defining slots
class Box : public QPushButton
{
Q_OBJECT
public:
Box(const QString& text, QWidget* parent = nullptr);
//may be public or private
public slots:
void onClick();
};
I am creating object from QGraphicsRectItem and adding to the Qgraphicscene(scene).
I want to get every movement(pos) of object(qgraphicsrectitem) so that I subclassed Qgraphicsrectitem. But in this class I am getting some errors.
How can I get object position changed in scene ?
error:
'staticMetaObject' is not a member of 'QGraphicsRectItem'
{ &QGraphicsRectItem::staticMetaObject, qt_meta_stringdata_ItemHandler.data
ItemHandler.h
#include <QObject>
#include <QGraphicsRectItem>
class ItemHandler : public QGraphicsRectItem, public QObject
{
Q_OBJECT
public:
ItemHandler(QGraphicsItem *parent = 0 );
~ItemHandler();
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
signals:
void objectHandlePosChanged(QPointF value);
};
ItemHandler.cpp
#include "itemhandler.h"
ItemHandler::ItemHandler(QGraphicsItem *parent) : QGraphicsRectItem(parent)
{
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
}
ItemHandler::~ItemHandler()
{
}
QVariant ItemHandler::itemChange(QGraphicsItem::GraphicsItemChange change,
const QVariant &value)
{
QPointF newPos = value.toPointF();
emit objectHandlePosChanged(newPos);
}
In you header file, inherit first from QObject, as follows:
#include <QObject>
#include <QGraphicsRectItem>
class ItemHandler : public QObject, public QGraphicsRectItem
{
Q_OBJECT
public:
ItemHandler(QGraphicsItem *parent = 0 );
~ItemHandler();
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
signals:
void objectHandlePosChanged(QPointF value);
};
And this is my test main function (sorry it's just a sandbox):
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow* mywindow = new MainWindow();
QGraphicsScene scene;
ItemHandler *item = new ItemHandler;
item->setRect(10.0, 10.0, 10.0, 10.0);
scene.addItem(item);
QApplication::connect(item, SIGNAL(objectHandlePosChanged(QPointF)), mywindow, SLOT(moved(QPointF)));
QGraphicsView view(&scene);
view.setFixedSize(250, 250);
view.setWindowTitle("QGraphicsItem Test");
item->setPos(-100, -100);
item->setPos(-200, -200);
view.show();
return app.exec();
}
I just used an empty MainWindow that is never displayed to have a slot to connect to the signal, there's no point in having a MainWindow: it was already there and I modified it instead of creating a new class. The example works, fires the signal and displays the rectangle.
I want to make one QGraphicsItem in a QGraphicsScene move (or change size) when another one moves. But, trying to access either QGraphicsItem from the QGraphicsScene object causes crashes.
Here's a dummy example. I want to automatically:
Resize BlueItem's width when I click and drag RedItem.
Move RedItem when I click and drag BlueItem.
The dummy code:
redItem.h (A pixmap item)
#include <QGraphicsPixmapItem>
class RedItem : public QGraphicsPixmapItem
{
public:
RedItem();
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
};
redItem.cpp
RedItem::RedItem()
{
setPixmap(QPixmap(redPixMap));
setFlags(ItemIsMovable);
setCacheMode(DeviceCoordinateCache);
}
void RedItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
setPos(event->scenePos(),0); //I can override this part just fine.
}
blueItem.h (A resizable rectangle item)
#include <QGraphicsRectItem>
class BlueItem : public QGraphicsRectItem
{
public:
BlueItem();
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
};
blueItem.cpp is similar to redItem.cpp
graphicsViewWidget.h (The GraphicsView)
#include <QGraphicsView>
#include "blueItem.h"
#include "redItem.h"
class GraphicsViewWidget : public QGraphicsView
{
Q_OBJECT
public:
explicit GraphicsViewWidget(QWidget *parent = 0);
protected:
virtual void mouseMoveEvent(QMouseEvent *event);
private:
RedItem *red;
BlueItem *blue;
};
graphicsViewWidget.cpp
#include "graphicsViewWidget.h"
#include <QRectF>
void Qx::createItem(int frame)
{
red = new RedItem;
red->setPos(0, 0);
scene()->addItem(red);
blue = new BlueItem;
blue->setPos(10, 10);
scene()->addItem(blue);
}
void GraphicsViewWidget::mouseMoveEvent(QMouseEvent *event) //QGraphicsSceneMouseEvent
{
QGraphicsView::mouseMoveEvent(event);
//if(redItem moves)
// resize blueItem;
//if(blueItem moves)
// move redItem;
}
Any help or advice would be greatly appreciated.
If you make item B a child of item A, then it will live in its coordinate space. This means all transformations - moving, scaling, rotating... everything you apply to the parent item will also be applied to all its children and their children and so on...
When i try to put QLabel in QWidget class its not work properly (no hover event or click event only the label pixmap is show) only the last instance work properly, when not use set parent, it create in new window for each label but its work correctly
this gif show the problem:
https://media.giphy.com/media/3o7TKKmZSISGXN4Opq/giphy.gif
this is QLabel subclass header:
#include <QObject>
#include <QLabel>
class myLabel : public QLabel
{
Q_OBJECT
public:
myLabel();
protected:
void mousePressEvent(QMouseEvent *);
void enterEvent(QEvent *);
void leaveEvent(QEvent *);
signals :
void labelClicked();
void enterSignal();
void leaveEventSignal();
private:
};
this class to make a labelButton:
#include <QObject>
#include <QWidget>
#include "mylabel.h"
class labelButton : public QWidget
{
Q_OBJECT
public:
labelButton();
//some functions
private slots:
//slots
private:
//private member
};
and this the class that i want to use the labelButtons in:
#include <QWidget>
#include "labelbutton.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
labelButton *b_1, *b_2, *b_3;
};
here is widget.cpp:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
b_1 = new labelButton;
b_1->setParent(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
b_1->show();
//-----------------------
b_2 = new labelButton;
b_2->setParent(this);
b_2->moveButton(70, 200);
//some functions to initialize the labelButton
b_2->show();
//-----------------------
b_3 = new labelButton;
b_3->setParent(this);
b_3->moveButton(70, 300);
//some functions to initialize the labelButton
b_3->show();
}
here its work, the problem was in passing the parent
i made a function that take a widget and set buttons parent from the function value
b_1 = new labelButton;
//b_1->setParent(this);
b_1->setParentFunc(this);
b_1->moveButton(70, 100);
//some functions to initialize the labelButton
// b_1->show();
in labelButton:
void labelButton::setParentFunc(QWidget *p)
{
myParent = p;
}
mLabel_1->setParent(myParent); // myParent instead of this