PDA

View Full Version : I cannot get QGraphicsRectItem to change colour on mousedoubleclickevent



Docas
31st January 2020, 21:28
Good day everyone

I am struggling to implement a mouseDoubleClickEvent on a QGraphicsRectItems initialized in another class. I have a class called GatewayWidget where i have created the QgraphicsRectItems in a scene using myshape class, but i cannot get the mousedDoubleClickEvent to click on a QgraphicsRectItem on a scene. When i insert a breakpoint at(scene->items()) no items are returned, but the same mouseDoubleClickEvent works when I call a widget(named logWidg) on a doubleclicking of the same QGraphicsRectItem. However when I call on the QGraphicsRectItem to change colour on doubleclick it does not work. please help! I appreciate it advance! please see my code below



void GatewayWidget::receivedTitlesEx(const QString &_rStrDescription, const CORE::Time &_rSimTime, const QList<std::shared_ptr<DM::Object> > &_rTitles, int _eType)
{ // I add my QGraphicsRectItems on the scene here
myshape* shape1 = new myshape(text);
//shape1->setFlag(QGraphicsItem::ItemIsMovable);
shape1->setPos(0, 25);
scene->addItem(shape1);
shape1->setFlag(QGraphicsItem::ItemIsMovable);
shape1->setFlag(QGraphicsItem::ItemIsSelectable);
shape1->setFlag(QGraphicsItem::ItemIsFocusable);
}


void myshape::mouseDoubleClick(QGraphicsSceneMouseEvent *event)
{

QGraphicsItem::mousePressEvent(event);

GatewayWidget gw; //this is the class that this method is implemented, and also where i have initialized the scene and drawn qgraphicsitems
gw.on_btnSelectItem_clicked(); //on_btnSelectItem_Clicked is the method implemented on Gatewaywidget that is supposed to change QGraphicsRectItem on double click, but it does not work. please help

//logWidg = new loginWidget();// but this widget can launch successfully when i click on the QGrapicsRectItem
//logWidg->show();

QList<QGraphicsItem*> stackOfShapes = gw.scene->items();// I tried to check if gw can return items but the breakpoint i inserted returns zero items




myshape .h file is as follows:




class myshape :public QObject, public QGraphicsRectItem{

public:
myshape(QGraphicsItem *item) {
setPen(QPen(QBrush(Qt::black), 1));
setBrush(QBrush(Qt::green));
setRect(0, 0, 80, 80);

}

protected:

void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);

private:

GatewayWidget *gatew; //i have implemented the myshape::mousedoubleclick event on the class(GatewayWidget)


virtual QSizeF sizeHint(Qt::SizeHint which,
const QSizeF& constraint = QSizeF()) const {
Q_UNUSED(which);
Q_UNUSED(constraint);
return boundingRect().size();
}

virtual void setGeometry(const QRectF& rect) {

setPos(rect.center());
}


};


on_btnSelectItem_clicked() is the method i call that is supposed to change colour of QGraphicsRectItem on mouseDoubleClickEvent but it does not work





void GatewayWidget::on_btnSelectItem_clicked()
{

foreach(QGraphicsItem *item, scene->selectedItems())
{

QGraphicsRectItem *rect = qgraphicsitem_cast<QGraphicsRectItem *>(item);
if (!rect)
continue;

QBrush br(Qt::SolidPattern);
br.setColor(Qt::black);
rect->setBrush(br);
rect->update();
}
}

Ginsengelf
4th February 2020, 10:17
Hi,



GatewayWidget gw; this creates a second temporary instance of class GatewayWidget. This is NOT your original instance, and it will by destroyed when the function ends.

Ginsengelf

Docas
4th February 2020, 11:16
Hi

Thank you for your response,please I would appreciate your advise on how I can access the function(on_btnSelectItem_clicked()) on GatewayWidget

Ginsengelf
4th February 2020, 14:40
Hi, the simples would be to pass the GatewayWidget to myshape during construction, e.g.


void GatewayWidget::receivedTitlesEx(...)
{
myshape* shape1 = new myshape(text, this);
...
}

and store the pointer in a member.

Ginsengelf

EDIT: or emit a signal instead of calling the function directly

Docas
5th February 2020, 15:20
Hi, the simples would be to pass the GatewayWidget to myshape during construction, e.g.


void GatewayWidget::receivedTitlesEx(...)
{
myshape* shape1 = new myshape(text, this);
...
}

and store the pointer in a member.

Ginsengelf

EDIT: or emit a signal instead of calling the function directly

Hi, thanks for the reply and your help. I am still a new learner ,I know I can access the shape1 pointer using shape1->scene().items in the class, but shape1 is still not recognized . I am asking if you can show me how to store this pointer? by member you mean my class GatewayWidget()?


I also tried implementing mousedoubleclickevent() directly to the GatewayWidgetClass() but it does not respond to the mousedoubleclick(event). please see how i did it?



class GatewayWidget : public VgdWidget, public QGraphicsRectItem
{
Q_OBJECT
CORE_OBJ_EX(VgdWidget, GatewayWidget, GatewayWidget,
1.0,
"Basic gatway widget for managing interoperability links.",
"");

static const unsigned long WIDGET_UPDATE_PERIOD = 100; // [ms]

public:
GatewayWidget(const QColor &_colorBackground = QColor(240, 240, 240));
~GatewayWidget();


protected:
virtual void timerEvent(QTimerEvent *pEvent);
protected:
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event);


and in my main class GatewayWidget() i call mousedoubleclick(event) like this:


void GatewayWidget::mouseDoubleClickEvent(QGraphicsScen eMouseEvent *event)
{
QMessageBox::information(0, "This", "mouse doubleclick working");
foreach(QGraphicsItem *item, scene->selectedItems())
{
QGraphicsRectItem *rect = qgraphicsitem_cast<QGraphicsRectItem *>(item);
if (!rect)
continue;

QBrush br(Qt::SolidPattern);
br.setColor(Qt::black);
rect->setBrush(br);
rect->update();
}

QGraphicsItem::mouseDoubleClickEvent(event);
}


But nothing happens when i click, is it possible to implement mousedoubleclick(event) like this or it must be implemented from an outside class like I am trying to do with myshape? I would appreciate your advise oh how I can make this work work


thank you in advance!

d_stranz
5th February 2020, 18:50
class GatewayWidget : public VgdWidget, public QGraphicsRectItem

Why are you inheriting from QGraphicsRectItem? Is GatewayWidget actual one of your rectangles on screen, or is it the view used to display the QGraphicsScene that contains them?

I am beginning to wonder how it is that you are working on this complex project but you seem to know so little about C++ and programming. Is this someone else's project that you have taken over and are making a GUI for it? The project uses templates, smart pointers, graph data structures, and other more advanced programming ideas, but you don't seem to show that you understand it very well.

Docas
5th February 2020, 19:32
Why are you inheriting from QGraphicsRectItem? Is GatewayWidget actual one of your rectangles on screen, or is it the view used to display the QGraphicsScene that contains them?

I am beginning to wonder how it is that you are working on this complex project but you seem to know so little about C++ and programming. Is this someone else's project that you have taken over and are making a GUI for it? The project uses templates, smart pointers, graph data structures, and other more advanced programming ideas, but you don't seem to show that you understand it very well.

No GatewayWidget is not one of my rectangles on screen, I could not call mousedoubleclick(event) on gatewayWidget and I read on Google forums that I needed to inherit QGraphicsRectItem to use mousedoubleclick(event). Maybe I got it wrong?


Concerning your question, Yes you are correct I am a new learner, thats why I posted in this newbie section and true I do not know a lot. It was someone's project that I am tasked to implement the gui. I think I also was not aware that it will be this complex, and now I have a deadline and I am so drained.....

I am kindly asking with my whole heart if you can please assist me to implement the mousedoubleclick(event) , how do I make mousedoubleclick(event) to work on my current QGraphicsRectItems? like I said the one I tried with :


void GatewayWidget::mouseDoubleClickEvent(QGraphicsScen eMouseEvent *event)
{
QMessageBox::information(0, "This", "mouse doubleclick working");
foreach(QGraphicsItem *item, scene->selectedItems())
{
QGraphicsRectItem *rect = qgraphicsitem_cast<QGraphicsRectItem *>(item);
if (!rect)
continue;

QBrush br(Qt::SolidPattern);
br.setColor(Qt::black);
rect->setBrush(br);
rect->update();
}

QGraphicsItem::mouseDoubleClickEvent(event);
}


It does not respond to any mousedoubleclick that is why I tried to implement it with an outside class myshape(). I would appreciate your advise , and I appreciate your help thus far and your patience with my little knowledge.

d_stranz
5th February 2020, 21:31
how do I make mousedoubleclick(event) to work on my current QGraphicsRectItems?

First, remove the inheritance from QGraphicsRectItem that you added to GatewayWidget, and remove the mouseDoubleClickEvent() code too.

Second, the steps you need to follow are these:

1. Derive a new class from QGraphicsRectItem and add an event handler for the mouseDoubleClickEvent to it:



// .h

class GatewayRectItem : public QGraphicsRectItem
{
public:
GatewayRectItem( QGraphicsItem * parent = nullptr ) : QGraphicsRectItem( parent ) {}

protected:
void mouseDoubleClickEvent( QGraphicsSceneMouseEvent * event );

// If you want to handle other events, add handlers for those here too
}

// .cpp

// Implement the event handler
void GatewayRectItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent * event )
{
// You now have the double-click event. The rect that was clicked is "this". What do you want to do?

// If you want to also have the QGraphicsRectItem base class process this event, you must call
QGraphicsRectItem::mouseDoubleClickEvent( event );
}


2 - When you create your rect items, you call the new constructor. You also need to make sure the item is selectable so it responds to mouse clicks:




GatewayRectItem * rect = new GatewayRectItem();
rect->setFlags( QGraphicsItem::ItemIsSelectable );
scene->addItem( rect );


3 - Decide what you want to do with the double-click. In this case, I would have the GatewayRectItem emit a signal that you can handle somewhere else in a slot that can determine the correct color. To do that, you need to also derive GatewayRectItem from QObject so it can send signals:



// .h

class GatewayRectItem : public QObject, public QGraphicsRectItem
{
Q_OBJECT;

public:
GatewayRectItem( QGraphicsItem * parent = nullptr );

signals:
void doubleClicked( QGraphicsSceneMouseEvent * event );

protected:
void mouseDoubleClickEvent( QGraphicsSceneMouseEvent * event );
}

// .cpp

GatewayRectItem::GatewayRectItem( QGraphicsItem * parent )
: QGraphicsRectItem( parent )
{
// Can just do this here, so all items have the flag set
setFlags( QGraphicsItem::ItemIsSelectable );
}

// Implement the event handler
void GatewayRectItem::mouseDoubleClickEvent( QGraphicsSceneMouseEvent * event )
{
// You now have the double-click event. Emit the signal to let a slot know
emit doubleClicked( event );

// If you want to also have the QGraphicsRectItem base class process this event, you must call
QGraphicsRectItem::mouseDoubleClickEvent( event );
}


4 - Add a slot to handle this signal. I assume you would want to do that in your GatewayWidget class:



// .h

class GatewayWidget : public VgdWidget
{
// ... all the original code

public slots:
void onRectDoubleClicked( QGraphicsSceneMouseEvent * event );

// ...
};

// .cpp

void GatewayWidget::onRectDoubleClicked( QGraphicsSceneMouseEvent * event )
{
// first, get the rect instance that sent the signal
GatewayRectItem * rect = qobject_cast< GatewayRectItem * >( sender() );

// Now you have the rect that was double-clicked, and you have the event details if you need them
// Do whatever you need to do to determine what color the rect should be, then set the color

rect->setBrush( QBrush( theNewColor ) );
}


5 - And finally, when you create the rect, you need to connect its signal to the GatewayWidget's slot:




GatewayRectItem * rect = new GatewayRectItem();

// Don't need this now since it is set in the constructor for GatewayRectItem
// rect->setFlags( QGraphicsItem::ItemIsSelectable );

scene->addItem( rect );

connect( rect, &GatewayRectItem::doubleClicked, this, &GatewayWidget::onRectDoubleClicked );


None of this code has been tested - I am just writing it here. There could be typos, so don't just copy and paste without checking it.

Docas
6th February 2020, 10:09
Thank you for your help once more, without your help I would not have progressed this far, I do not take it for granted. It is working , it changes color on doubleclick.

May I please ask another question. Now I want that when I doubleclick on the rect, it must then pop up a widget, but the widget is looking for the index of the rect so that It can pop the widget with the information specific to that rect. I tried it like the code below to get the index of the rect, but it only pops up the widget once(with the correct information). Then nothing after that to any subsequent rect that I click. my question is should I store the indexes of each rect on creation with QLIST[] or how should I store the index of the clicked rect ? i would appreciate your assistance once more




void GatewayWidget::onRectDoubleClicked(QGraphicsSceneM ouseEvent * event)
{
// first, get the rect instance that sent the signal
GatewayRectItem * rect = qobject_cast< GatewayRectItem * >(sender());
// rect->setBrush(QBrush(Qt::black));

QList<QGraphicsItem*> stackOfRect = scene->items();

int indexOfShape = stackOfRect.indexOf(rect);// trying to index the clicked rect
if (CORE::castPtrType<C2DM::LinkState>(m_pLinkStateListModel->getTitle(indexOfShape)))// getTitle is looking for the index clicked
{
// create link ctrl widget
//C2DM::LinkState *pState = CORE::castPtrType<C2DM::LinkState>(indexOfShape);
const C2DM::LinkState *pState = CORE::castPtrType<C2DM::LinkState>(m_pLinkStateListModel->getTitle(indexOfShape));
showLinkToolBoxWidget(pState->m_strLinkId);

}




}

d_stranz
6th February 2020, 17:35
if (CORE::castPtrType<C2DM::LinkState>(m_pLinkStateListModel->getTitle(indexOfShape)))// getTitle is looking for the index clicked

Why do you think that the scene index returned in the QList is a constant that won't change? The scene could change the order of items in it based on the current stacking order of things in the scene, and the order can change as you add new items to the scene. And if you have QGraphicsLineItem, QGraphicsTextItem, and QGraphicsRectItem instances in the scene, all of these will have an index, too, and the index will depend on where they are in the hierarchy of scene objects.

The only way you can guarantee that you can look up something by an index number is if you assign the index number yourself. The easiest way to do this is to use the mechanism you are already using on your rect objects: use another setData() property to assign the index to your rects. If you are using the key "0" already, then use a different key (1) to assign an index when you create the rect. If you are only indexing the rects, then start at index 0 and increment as you add new rects.

If you ever delete a rect, then you will have to make sure that your model and your rects remain consistent - if you remove a rect with index 42, because you have removed the title with index 42, then you have to make sure that you either re-index everything from 42 up or access title <---> rect relationship in a way that is not affected by missing index numbers. Once again, an std:: map<> would work great for this.

Docas
9th February 2020, 19:37
Hello

I just came to say thank you I followed your advice and it worked beautifully. I also wanted to let you know that I was able to meet my deadline on the 7th of Feb 2020, I was able to demonstrate to my boss of what I have completed so far on the gui and he was happy. I acknowledge that I would not have been able to demonstrate any functionality if not for your guidance from your generous heart, and I say thank you. I thank you for how quick you respond to questions whenever I post. You have taught me a lot and I hope to learn more from you in the future. I thank you! May God bless you!

I also wanted to ask if there is anywhere else I can find you where you offer courses, like Pluralsight or Udemy?

d_stranz
9th February 2020, 20:46
You are welcome. I am glad you made your deadline and that your boss is happy.

I don't teach any courses. I have been programming in C / C++ for nearly 40 years and using Qt for almost 15 years and in that time I have learned a few useful things, so I am glad I can use this forum to help others from time-to-time.

I am sure you can search any of the online sites for C++ and Qt courses. Here is one list. (https://digitaldefynd.com/best-c-plus-plus-tutorial-course-certification/) KDAB also offers courses in Europe, the USA, and other places on C++ and Qt programming.