I am having a problem where I emit a signal in a mouseMove event, but that signal does not get recieved by a slot on another object until i release the mouse.
Details:
I have a class called SelectableItem, which subclasses QGraphicsObject :
#pragma once
#if !defined PARTS_SELECTABLE_ITEM_H
#define PARTS_SELECTABLE_ITEM_H
#include <QGraphicsObject>
namespace Parts {
class SelectableItem : public QGraphicsObject {
Q_OBJECT
public:
SelectableItem();
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) = 0;
QRectF boundingRect() const = 0;
void SetIsSelectedCustom(bool b);
bool IsSelectedCustom();
void SetIsSelectable(bool b);
bool IsSelectable();
void SetIsHovering(bool b);
bool IsHovering();
void Move(QPointF offset);
signals:
void moveItem(QGraphicsSceneMouseEvent *e);
void deselectAllItems();
void deselectItem(Parts::SelectableItem*);
void selectItem(Parts::SelectableItem*);
void stopSelectionDrag();
void stopMovingParts();
void deleteSelectedItems();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *e);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *e);
void mouseMoveEvent(QGraphicsSceneMouseEvent *e);
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e);
void hoverEnterEvent(QGraphicsSceneHoverEvent *e);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *e);
bool m_is_selected;
bool m_is_hovering;
bool m_is_selectable;
}; // class SelectableItem
} // namespace Parts
#endif // PARTS_SELECTABLE_ITEM_H
I have two other classes that subclass the SelectableItem class. They are Part and Terminal
Part:
#pragma once
#if !defined PARTS_PART_H
#define PARTS_PART_H
#include "PartLabel.h"
#include "PartDialog.h"
#include "Terminal.h"
#include "SelectableItem.h"
#include <QGraphicsObject>
#include <QGraphicsSvgItem>
#include <QSvgRenderer>
#include <map>
namespace Parts {
class Terminal;
class Part : public SelectableItem {
Q_OBJECT
public:
friend class PartLabel;
Part();
~Part();
enum PartLabelLocation {
North,
South,
East,
West
};
// Inherited Functions
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect() const;
void setPos(qreal x, qreal y);
// Part Functions
void SetData(std::map<std::string, std::string> data);
void SetTerminals(std::list<Terminal*> terms);
void AddTerminalsToScene(QGraphicsScene* s);
void SetPartGraphic(QGraphicsSvgItem *svg);
void SetDialog(PartDialog *d);
std::string GetName();
void SetName(const std::string &name);
void Move(QPointF offset);
PartLabel* GetLabel();
std::map<std::string, std::string>* GetData();
std::list<Terminal*> GetTerminalList();
QPointF GetCenterPointPos();
void SetLabelNorth();
void SetLabelSouth();
void SetLabelEast();
void SetLabelWest();
void ResetLabelPosition();
QGraphicsSvgItem* GetPartSvg();
signals:
void partRotated();
private:
// Inherited Functions
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *e);
void hoverEnterEvent(QGraphicsSceneHoverEvent *e);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *e);
void contextMenuEvent(QGraphicsSceneContextMenuEvent *e);
// Part Functions
void DrawTerminal(QPainter *painter, QPointF &point);
QRectF CalculateBoundingBox();
void Initialize();
void RotateCW();
void RotateCCW();
void OpenPropertiesDialog();
void SinglePartContextMenu(QGraphicsSceneContextMenuEvent *e);
void MultiplePartContextMenu(QGraphicsSceneContextMenuEvent *e);
// Part Members
QGraphicsSvgItem *m_part_graphic;
std::map<std::string, std::string> m_data;
std::list<Terminal*> m_terminals;
QRectF m_bounding_box;
PartLabel *m_label;
PartDialog *m_dialog;
bool m_is_initialized;
int m_label_position;
}; // class Part
}; // namespace Parts
#endif // PARTS_PART_H
Terminal:
#pragma once
#if !defined PARTS_TERMINAL_H
#define PARTS_TERMINAL_H
#define TERMINAL_RADIUS 15
#define CONNECTED_TERMINAL_RADIUS 7.5
#include "Part.h"
#include "SelectableItem.h"
#include <QGraphicsObject>
namespace Parts {
class Part;
class Connection;
class Terminal : public SelectableItem {
Q_OBJECT
public:
enum TerminalDirection {
North,
East,
South,
West
};
Terminal(const std::string &name, const QPointF &rel_coords, const std::string &direction);
// Inherited Functions
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QRectF boundingRect() const;
QPointF GetRelativeCoord();
QPointF GetConnectionCoord();
void SetPart(Part *p);
bool HasPart();
void Move();
void RotateCW();
void RotateCCW();
void SetIsConnected(bool b);
bool IsConnected();
void AddConnection(Connection *c);
void RemoveConnection(Connection *c);
std::list<Connection*> GetConnectionList();
signals:
void connectionBegun(Parts::Terminal *t);
void connectionCompleted(Parts::Terminal *t);
private:
// Inherited Functions
void mouseReleaseEvent(QGraphicsSceneMouseEvent *e);
void hoverEnterEvent(QGraphicsSceneHoverEvent *e);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *e);
//void contextMenuEvent(QGraphicsSceneContextMenuEvent *e);
void IncrementDirection();
void DecrementDirection();
QPointF m_rel_coords;
QPointF m_rotated_rel_coords;
bool m_is_connected;
int m_direction;
int m_rotation_angle;
QRectF m_bounding_rect;
Part *m_part;
std::string m_name;
std::list<Connection*> m_connections;
}; // class Terminal
} // namespace Parts
#endif // PARTS_TERMINAL_H
The SelectableItem class's mouseMove function is as follows:
void SelectableItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) {
if(!m_is_selectable)
return;
if(m_is_selected)
emit moveItem(e);
else {
emit deselectAllItems();
emit selectItem(this);
}
}
The signal emit selectItem(this) is instantly recieved by another class SysGraphicsScene which handles item selection.
The problem I'm having is that the Part class emits this signal via its base class and the signal is recieved by the SysGraphicsScene class instantly. However, the Terminal class emits this signal via it's base class (SelectableItem, which is the same base class that Part has.) and the signal is not recieved instantly by SysGraphicsScene but only after mouseReleased.
I have no idea why two derived classes would work differently. Any ideas?
Ugh found the problem. Some of my Terminal objects were never getting connected to signals while som where. I knew it had to be something basic. :/
Related
I derive custom item from QGraphicsItem and added some properties for QPropertyAnimation
Q_PROPERTY(qreal x READ x WRITE setX);
Q_PROPERTY(qreal y READ y WRITE setY);
Q_PROPERTY(QPointF pos READ pos WRITE setPos);
this is my header file
#ifndef MYSQUARE_H
#define MYSQUARE_H
#include<QObject>
#include<QPainter>
#include<QGraphicsItem>
#include<QGraphicsItemGroup>
#include<QGraphicsPixmapItem>
#include<QPainterPath>
#include<QPointF>
#include<QSizeF>
#include<QImage>
#include<QLabel>
#include<QCoreApplication>
#include <QStringBuilder>
#include <QString>
#include <QTranslator>
#include <QList>
#include <QVariant>
#include <QDebug>
#include <QtSvg>
#include <QSvgGenerator>
#include "arrow.h"
#include "mysvgitem.h"
class QGraphicsSvgItem;
class QPolygonF;
class Arrow;
class MySquare : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity);
Q_PROPERTY(QPointF pos READ pos WRITE setPos);
Q_PROPERTY(qreal x READ x WRITE setX);
Q_PROPERTY(qreal y READ y WRITE setY);
enum resize_direction
{
rd_none,
rd_left,
rd_top,
rd_right,
rd_bottom
1,1 Top
};
public:
MySquare();
QRectF boundingRect() const;
QPolygonF polygon() const { return myPolygon; }
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
bool Pressed;
void addArrow(Arrow *arrow);
QPointF returnCenter();
void setMyPolygon();
void setItemSize(qreal height,qreal width);
void setImage(const QString& str);
void setImage(const QString& str ,QSize);
void setImage(const QString& str ,QRectF rec);
void setSvgImage(const QString& str);
void setSvgImage(const QString& str ,QSizeF);
void setSvgImage(const QString& str ,QRectF rec);
void setText(const QString& str ,QRectF rec);
~MySquare();
signals:
void click();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
QVariant itemChange(GraphicsItemChange change, const QVariant &value) ;
private:
QPolygonF myPolygon;
QList<Arrow *> arrows;
QRectF myItemRect;
QString MyText;
QRectF MyTextRect;
QGraphicsTextItem *itemXY;
QString *posXY;
resize_direction resize_direction_;
};
#endif // MYSQUARE_H
Especially I want to create property to use it in animation, how is it possible to do.
I tried to use size property like
Q_PROPERTY(QSize size READ size WRITE setSize);
but I receive error
moc_mysquare.cpp: In member function ‘virtual int MySquare::qt_metacall(QMetaObject::Call, int, void**)’:
moc_mysquare.cpp:138:55: error: ‘size’ was not declared in this scope
case 1: *reinterpret_cast< QSize*>(_v) = size(); break;
^
moc_mysquare.cpp:149:55: error: ‘setSize’ was not declared in this scope
case 1: setSize(*reinterpret_cast< QSize*>(_v)); break;
Your property states that "there are functions named size() and setSize()". But you don't have them in your class.
I would like to emit a signal when hovering a QLabel with the mouse in QT.
Is it possible ?
If not, how can I do it ?
Thanks.
You can do hover handling without subclassing of QLabel. Try next code sample for it:
void LabelHoverHandler::attach(QLabel *label)
{
label->setAttribute(Qt::WA_Hover, true);
label->installEventFilter(this);
}
bool LabelHoverHandler::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::HoverEnter)
{
emit signalMouseHover(dynamic_cast<QLabel*>(obj) );
qDebug() << "HoverEnter";
}
return false;
}
LabelHoverHandler header file:
class LabelHoverHandler : public QObject
{
Q_OBJECT
public:
LabelHoverHandler(QObject *parent);
virtual ~LabelHoverHandler() {};
void attach(QLabel *label);
protected:
bool eventFilter(QObject *obj, QEvent *event);
signals:
void signalMouseHover(QLabel*);
};
Simply create an instance of LabelHoverHandler and call method attach() with a needed label as a parameter.
A possible implementation:
// mylabel.h
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QLabel>
class MyLabel : public QLabel
{
Q_OBJECT
public:
MyLabel();
~MyLabel();
protected:
virtual void enterEvent(QEvent *ev);
virtual void leaveEvent(QEvent *ev);
private:
bool hover;
};
#endif // MYLABEL_H
and:
// mylabel.cpp
#include "mylabel.h"
#include <QEvent>
MyLabel::MyLabel()
{
hover = false;
setAttribute(Qt::WA_Hover, true);
}
MyLabel::~MyLabel()
{
}
void MyLabel::enterEvent(QEvent *ev)
{
if (!hover){
hover = true;
setText("Send signal here");
}
QLabel::enterEvent(ev);
}
void MyLabel::leaveEvent(QEvent *ev)
{
if (hover){
hover = false;
setText("Mouse leave area");
}
QLabel::leaveEvent(ev);
}
I got simple class MyStackedWidget but looks like it doesn't fires drag and drop events - what am I doing wrong?
#ifndef MYSTACKEDWIDGET_H
#define MYSTACKEDWIDGET_H
#include <QStackedWidget>
class MyStackedWidget : public QStackedWidget
{
Q_OBJECT
public:
MyStackedWidget();
signals:
void dragEnterSignal(QDragEnterEvent *event);
void dropSignal(QDropEvent *event);
void dragMoveSignal(QDragMoveEvent *event);
void dragLeaveSignal(QDragLeaveEvent *event);
public slots:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dragLeaveEvent(QDragLeaveEvent *event);
};
#endif // MYSTACKEDWIDGET_H
#include "mystackedwidget.h"
#include <QMimeData>
#include <QDragEnterEvent>
MyStackedWidget::MyStackedWidget()
{
setMouseTracking(true);
}
void MyStackedWidget::dragEnterEvent(QDragEnterEvent *event)
{
const QMimeData *mimeData = event->mimeData();
if(mimeData->hasUrls() && mimeData->urls().size() == 1) {
event->acceptProposedAction();
}
emit dragEnterSignal(event);
}
void MyStackedWidget::dropEvent(QDropEvent *event)
{
emit dropSignal(event);
}
void MyStackedWidget::dragMoveEvent(QDragMoveEvent *event)
{
emit dragMoveSignal(event);
}
void MyStackedWidget::dragLeaveEvent(QDragLeaveEvent *event)
{
emit dragLeaveSignal(event);
}
I have read this How to distinguish between mouseReleaseEvent and mousedoubleClickEvent on QGrapnhicsScene and this Distinguish between single and double click events in Qt in order to solve my problem. But they do not work. I created a class QLabel:
mouselabel.h
#ifndef MOUSELABEL_H
#define MOUSELABEL_H
#include <QLabel>
#include <QMouseEvent>
#include <QEvent>
#include <QDebug>
class MouseLabel : public QLabel
{
Q_OBJECT
public:
explicit MouseLabel(QWidget *parent = 0);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent *event);
void leaveEvent(QMouseEvent *);
int x, y;
signals:
void Mouse_Pressed();
void Mouse_Position();
void Mouse_Left();
void Mouse_Release();
void Mouse_DoubleClick();
public slots:
};
#endif // MOUSELABEL_H
mouselabel.cpp
#include "mouselabel.h"
MouseLabel::MouseLabel(QWidget *parent) :
QLabel(parent)
{
}
void MouseLabel::mouseMoveEvent(QMouseEvent *event) {
this->x = event->x();
this->y = event->y();
emit Mouse_Position();
}
void MouseLabel::mousePressEvent(QMouseEvent *event)
{
emit Mouse_Pressed();
}
void MouseLabel::mouseReleaseEvent(QMouseEvent *event)
{
emit Mouse_Release();
}
void MouseLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
emit Mouse_DoubleClick();
}
void MouseLabel::leaveEvent(QMouseEvent *)
{
emit Mouse_Left();
}
As described in the two links, in order to distinguish between a click and a double click, I created a timer and it starts when a mouserelease event happens and it stops when there is a double click mouse. But, this does not work. Can you help me to solve the problem?
The lightest possible solution is using a QBasicTimer, just have those 2 methods overloaded and the timer in your widget:
void mouseReleaseEvent(QMouseEvent *) {
if (timer.isActive()) {
timer.stop();
qDebug() << "double click";
}
else {
timer.start(300, this);
}
}
void timerEvent(QTimerEvent *) {
timer.stop();
qDebug() << "single click";
}
QBasicTimer timer;
The downside is a timer approach delays the single click, which is kind of annoying, but you could mask that, for example for selecting objects, using the mousePressEvent for immediate response.
I am implementing copy operation in graphicsView for different entities such as point, ellipse, circle etc. in qt but getting an error
error: invalid conversion from 'QGraphicsItem*' to 'QGraphicsItemGroup*
My code to copy operation in cadgraphicsview.cpp is:
void CadGraphicsScene::copy()
{
selectedItems.clear();
foreach(QGraphicsItemGroup *item, itemList){
QString str;
if (item->isSelected())
{
if(item->type() == Point::Type)
{
Point *pointItem = (Point *) item;
str = QString("Point %1 %2 ")
.arg(pointItem->scenePos().x())
.arg(pointItem->scenePos().y());
}
}
}
}
In cadgraphicsscene.h
#ifndef CADGRAPHICSSCENE_H
#define CADGRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QXmlStreamWriter>
#include <QUndoStack>
#include <QLabel>
#include <QFrame>
#include "cadcommandadd.h"
#include "cadcommanddelete.h"
#include "cadcommandmove.h"
class CadGraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit CadGraphicsScene(QObject *parent, QUndoStack *);
enum Mode { NoMode, PointMode, LineMode, CircleMode, EllipseMode, TextMode };
QFont font() const
{
return myFont;
}
QColor textColor() const
{
return myTextColor;
}
void setTextColor(const QColor &color);
void setFont(const QFont &font);
void deleteItems();
void writeStream(QXmlStreamWriter *stream);
void readStream(QXmlStreamReader *stream);
public slots:
void setMode(Mode mode);
void selectItems();
void editorLostFocus(mText *item);
void cut();
void copy();
void paste();
void del();
protected:
void contentsContextMenuEvent(QContextMenuEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent);
void setFlags();
void areItemsSelectable(bool);
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void mousePressEvent(QMouseEvent *event);
signals:
void textInserted(QGraphicsTextItem *item);
void itemSelected(QGraphicsItem *item);
private:
Mode entityMode;
QUndoStack *mUndoStack;
bool mFirstClick;
bool mSecondClick;
bool mThirdClick;
bool mPaintFlag;
QVector<QPointF> stuff;
QPointF start_p, mid_p, end_p, move_p, check_p;
QPen paintpen, linePen;
QList<QGraphicsItem *> itemList;
Point *pointItem;
Line *lineItem;
Circle *circleItem;
Ellipse *ellipseItem;
mText *textItem;
QColor myTextColor;
QFont myFont;
typedef QPair<QGraphicsItem *, QPointF> itemPos;
QList<itemPos> selectedItems;
private:
QAction *cutAct;
QAction *copyAct;
QAction *pasteAct;
};
#endif // CADGRAPHICSSCENE_H
Help me out to sought this :)
You define itemList as:
QList<QGraphicsItem *> itemList;
You are then trying to iterate it with:
foreach(QGraphicsItemGroup *item, itemList){
// ...
}
From the documentation you can see that QGraphicsItemGroup inherits from QGraphicsItem. So every QGraphicsItemGroup "is a" QGraphicsItem. But not every QGraphicsItem "is a" QGraphicsItemGroup.
If you want to iterate that itemList then item will have to be a QGraphicsItem, or itemList will have to be a QGraphicsItemGroup. It seems that since you are testing for specific classes then the former is probably what you want.