Results 1 to 14 of 14

Thread: QGraphicRectItem update colour in foreach statement

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,329
    Thanks
    317
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    void QGraphicsItem::setData ( int key, const QVariant & value )
    This is a method in the base class for QGraphicsRectItem (QGraphicsItem). The "key" can be integer you want it to be. The reason it is there is to allow you to store more than one value for each item. Since you will probably be storing only one value in each QGraphicsRectItem, you can use 0 (zero) as the key.

    For the value, I would use the enum C2DM:: LinkState:: m_eType (eg. C2DM:: LinkState:: EIS_GOOD, EIS_BUSY, etc.). Your addRect() code would be modified to look like this:

    Qt Code:
    1. void GatewayWidget::addRect(DM::Object *_pTitle)
    2. {
    3. if (CORE::checkPtrType<C2DM::LinkState>(_pTitle) == true)
    4. {
    5.  
    6. C2DM::LinkState *pState = (C2DM::LinkState*)_pTitle;
    7.  
    8.  
    9. QGraphicsTextItem *textColor = scene->addText(QString::fromStdString(pState->m_strLinkId));
    10.  
    11. int x = (qrand() % 4);
    12. int pos = (x * 75) - 75 / 2;
    13. textColor->setPos(400, pos + 200);
    14. textColor->setFlag(QGraphicsItem::ItemIsMovable);
    15. textColor->setFlag(QGraphicsItem::ItemIsSelectable);
    16. QGraphicsRectItem *rectangleColor = new QGraphicsRectItem(QRectF(0, 0, 50, 50), textColor);
    17. rectangleColor->setData( 0, int( pState->m_eType ) ); // Automatically creates a QVariant<int>
    18. // etc. for the other rectangle
    To copy to clipboard, switch view to plain text mode 

    Your code for getTitleDescriptionColor() needs to check that the rectangle's LinkState type value matches the value you passed in:

    Qt Code:
    1. QColor getTitleDescriptionColor(const DM::Object *_pTitle, const QColor &_colorBackground, QGraphicsRectItem *_row)
    2. {
    3.  
    4. QColor ret = _colorBackground;
    5.  
    6. if (CORE::checkPtrType<C2DM::LinkState>(_pTitle) == true)
    7. {
    8.  
    9. C2DM::LinkState *pState = (C2DM::LinkState*)_pTitle;
    10.  
    11. // If the state type passed in does not match the state type stored in the rect, then do nothing
    12. int stateType = int( pState->m_eType );
    13. int rectState = _row->data( 0 ).toInt();
    14. if ( stateType != rectState )
    15. return ret;
    16.  
    17. // Otherwise, continue with the original code to change the rect color
    18.  
    19. // ...
    To copy to clipboard, switch view to plain text mode 

    You will need to add code to change the value stored in the QGraphicsRectItem whenever its LinkState changes.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  2. #2
    Join Date
    Jan 2020
    Posts
    13
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    Thank you for the response and generous help!

    I implemented it and it does change the color for a specific QGraphicsRectItem with its connection status(thank you), however when it updates the status correctly it also add new QGraphicsRectItems(see attachment),a repeat of QGraphicsRectItems that was on the scene but with an updated status. I called the addRect function on the update statement like this:
    Qt Code:
    1. void GatewayWidget::receivedTitlesEx(const QString &_rStrDescription, const CORE::Time &_rSimTime, const QList<std::shared_ptr<DM::Object> > &_rTitles, int _eType)
    2. {
    3.  
    4. if (_rStrDescription == "LINK.*.STATE")
    5. {
    6. foreach (const std::shared_ptr<DM::Object> &objPtr, _rTitles)
    7. {
    8.  
    9. if (CORE::checkPtrType<C2DM::LinkState>(objPtr) == true)
    10. {
    11. if (_eType == QSubscription::NEW_TITLES)
    12. {
    13. C2DM::LinkState *pState = (C2DM::LinkState*)objPtr->_clone();
    14.  
    15. addRect(pState);// this is the first call of the method that adds the QGraphicsRectItem(nodes) on the scene
    16.  
    17. }
    18. else if (_eType == QSubscription::UPDATED_TITLES)
    19. {
    20. C2DM::LinkState *pState = (C2DM::LinkState*)objPtr->_clone();
    21.  
    22. addRect(pState);//on updated status i call the addRect() again. When it updates the link status and change the color, it also adds the new QGraphicsRectItem when it is was already added on the first call of addRect() above.
    23. }
    To copy to clipboard, switch view to plain text mode 

    my understanding was that I am supposed to call addRect() again on the UPDATED_TITLES as seen on the else if clause above, am I correct?

    I think that on the addRect() function, I always add QGraphicsRectItems on the scene through this lines:
    Qt Code:
    1. QGraphicsTextItem *textColor = scene->addText(QString::fromStdString(pState->m_strLinkId));
    2. QGraphicsRectItem *rectangleColor = new QGraphicsRectItem(QRectF(0, 0, 50, 50), textColor);
    3. rectangleColor->setData(0, int(pState->m_eState));
    To copy to clipboard, switch view to plain text mode 

    then whenever I call addRect() it creates another QGraphicsRectItem with the updated status. my question is am I supposed to write another statement on addRect() that will check if the QGraphicsRectItems are already added on the scene, and if they are, then just change color only and not add a new QGraphicsRectItem?

    on your statement"You will need to add code to change the value stored in the QGraphicsRectItem whenever its LinkState changes." do you mean I should change the value int Rectstate when _eType changes here :
    Qt Code:
    1. }
    2. else if (_eType == QSubscription::UPDATED_TITLES) //this is where _eType changes(which is the LinkState),is this where I am supposed to write the code? how do I access the value [I]int rectState[/I] on this function?
    3. {
    4. C2DM::LinkState *pState = (C2DM::LinkState*)objPtr->_clone();
    5. addRect(pState);
    To copy to clipboard, switch view to plain text mode 

    function addRect() I updated it as you advised:
    Qt Code:
    1. void GatewayWidget::addRect(DM::Object *_pTitle)
    2. {
    3. if (CORE::checkPtrType<C2DM::LinkState>(_pTitle) == true)
    4. {
    5.  
    6. C2DM::LinkState *pState = (C2DM::LinkState*)_pTitle;
    7.  
    8.  
    9. QGraphicsTextItem *textColor = scene->addText(QString::fromStdString(pState->m_strLinkId));
    10.  
    11. int x = (qrand() % 4);
    12. int pos = (x * 75) - 75 / 2;
    13. textColor->setPos(400, pos + 200);
    14. textColor->setFlag(QGraphicsItem::ItemIsMovable);
    15. textColor->setFlag(QGraphicsItem::ItemIsSelectable);
    16. QGraphicsRectItem *rectangleColor = new QGraphicsRectItem(QRectF(0, 0, 50, 50), textColor);
    17. rectangleColor->setData(0, int(pState->m_eState));
    18.  
    19. rectangleColor->setPos(0, 25);
    20.  
    21. rectangleColor->setFlag(QGraphicsItem::ItemIsSelectable);
    22.  
    23. getTitleDescriptionColor(pState, m_backgroundColor, rectangleColor);
    24.  
    25.  
    26. }
    To copy to clipboard, switch view to plain text mode 

    Function getTitleDescription() as follows:
    Qt Code:
    1. QColor getTitleDescriptionColor(const DM::Object *_pTitle, const QColor &_colorBackground, QGraphicsRectItem *_row)
    2. {
    3.  
    4. QColor ret = _colorBackground;
    5.  
    6. if (CORE::checkPtrType<C2DM::LinkState>(_pTitle) == true)
    7. {
    8.  
    9. C2DM::LinkState *pState = (C2DM::LinkState*)_pTitle;
    10.  
    11. // If the state type passed in does not match the state type stored in the rect, then do nothing
    12. int stateType = int(pState->m_eState);
    13. int rectState = _row->data(0).toInt();
    14. if (stateType != rectState)
    15. {
    16.  
    17. return ret;
    18.  
    19. }
    20. else
    21. {
    22.  
    23. if (pState->m_eState == C2DM::LinkState::EIS_GOOD)
    24. {
    25. ret = QColor(Qt::green).darker(120);
    26. _row->setBrush(ret);
    27. }
    28. else if (pState->m_eState == C2DM::LinkState::EIS_BUSY)
    29. {
    30. ret = QColor(Qt::yellow).darker(120);
    31. _row->setBrush(ret);
    32. }
    33. else
    34. {
    35. ret = QColor(Qt::red).darker(120);
    36. _row->setBrush(ret);
    37. }
    38.  
    39. }
    40.  
    41.  
    42. }
    To copy to clipboard, switch view to plain text mode 

    Please pardon me for slow understanding, please help me on the way forward.Thank you for your help in advance.
    Attached Images Attached Images

  3. #3
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,329
    Thanks
    317
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    however when it updates the status correctly it also add new QGraphicsRectItems(see attachment),a repeat of QGraphicsRectItems that was on the scene but with an updated status. I called the addRect function on the update statement like this:
    Think about what you are saying here. If the status of a rect changes, why would you want to add a new rect? Just change the status of the rect that already exists. You can call setData() for a rect any time, not just when you create it. If the status changes from EIS_GOOD to EIS_BUSY, then simply call setData( 0, EIS_BUSY ) for that rect, don't create a new one with EIS_BUSY status.

    You need to take a step back and really think through the logic of your program. It seems like you are just copying and pasting without really thinking about what you want the code to do.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  4. #4
    Join Date
    Jan 2020
    Posts
    13
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    I think you misunderstood me. What I meant is I do not want a new rect to be added everytime a status change,how do I this? is my question. setdata() is setup correctly because the color of the rect changes as i expect,But i do not want a new rect to be added with the new status. On my addRect() function, the first thing i do is to create a new rect, then setdata on that rect,like this:

    Qt Code:
    1. void GatewayWidget::addRect(DM::Object *_pTitle)
    2. {
    3.  
    4. QGraphicsTextItem *textColor = scene->addText(QString::fromStdString(pState->m_strLinkId));
    5. QGraphicsRectItem *rectangleColor = new QGraphicsRectItem(QRectF(0, 0, 50, 50), textColor); //create rect
    6. rectangleColor->setData(0, int(pState->m_eState));//then set data
    To copy to clipboard, switch view to plain text mode 

    my question is, is there a way I can setdata() without creating a new rect? how do i call setdata() for an existing rect on the scene?

    Please see the attached image i sent, you can see that setdata is correct but i do not know how to prevent the creation of a new rect

  5. #5
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,329
    Thanks
    317
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    is there a way I can setdata() without creating a new rect? how do i call setdata() for an existing rect on the scene?
    Of course you can call setData() on an existing rect.

    I think your basic problem is that you do not have any connection between the data you are trying to model (your data tree of links and nodes) and the graphical items you are using to display the model on the screen (the QGraphicsRectItem and QGraphicsLineItem instances).

    If you want the graphics items on the screen to reflect the status of the data items in your model, then you have to create another data structure that connects a specific item from your model with the graphics item that represents it on screen. This is what I meant several replies ago when I said:

    So what you need to do is to add an association between each rect and its specific LinkState value.
    You can't add items to your graphics scene and then just forget about them. If they represent something in your model, you need to create an explicit association between the model and the graphics item.

    What I would do is create something like this:

    Qt Code:
    1. std::map< DM::Object *, QGraphicsItem * >
    To copy to clipboard, switch view to plain text mode 

    as a data structure in the GatewayWidget class (or some other class if it is more appropriate). Each time you create a new graphics item, you add an entry to the map that associates the Object with the graphics item. When you need to update a graphics item because the Object status has changed, you use the map to retrieve the graphics item pointer using the Object pointer as the key.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  6. #6
    Join Date
    Jan 2020
    Posts
    13
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    Hello

    Thank you for your help one again. I used std::map and it updates correctly. I have a problem with the routes(source and destination). I sometimes have multiple source address(string) going to different destinations and I read that with std::map() i cannot have multiple keys. The mapping that worked for the links(unique keys and values) is
    Qt Code:
    1. std::map< std::string, QGraphicsItem * > QgraphicRectItems;//declared in my .h file
    2.  
    3. rectangleColor->setData(0, int(pState->m_eState));
    4. QgraphicRectItems.insert(std::make_pair(pState->m_strLinkId, rectangleColor));//make a pair of QGraphicRect items on the scene and their link IDs
    To copy to clipboard, switch view to plain text mode 

    then on my update function i call the mappings like this:
    Qt Code:
    1. std::map< std::string, QGraphicsItem *>::iterator it = QgraphicRectItems.find(pState->m_strLinkId);
    2. if (it != QgraphicRectItems.end()) {
    3. QGraphicsItem *name = it->second;
    4. name->setData(0, int(pState->m_eState));
    5. QGraphicsRectItem *rect = qgraphicsitem_cast<QGraphicsRectItem *>(name);
    6. getTitleDescriptionColor(pState, m_backgroundColor, rect);
    To copy to clipboard, switch view to plain text mode 

    But for the routes this doesn't work because sometimes i have multiple keys, so I implemented std::multimap like this:
    Qt Code:
    1. std::multimap<std::string, QGraphicsItem *> RouteSourceDuplicates;//declared on my .h file
    2.  
    3. else if (CORE::checkPtrType<C2DM::RouteState>(_pTitle) == true)
    4. {
    5. C2DM::RouteState *pRoute = (C2DM::RouteState*)_pTitle;
    6.  
    7. rectangle = new QGraphicsRectItem(QRectF(0, 0, 60, 60), text);
    8.  
    9. rectangle->setData(0, int(pRoute->m_eTxLinkState));
    10. RouteSourceDuplicates.insert(std::make_pair(pRoute->m_strSource, rectangle));//make a pair of QGraphicRect items on the scene and their source IDs
    To copy to clipboard, switch view to plain text mode 

    then on my calling function i did like this:
    Qt Code:
    1. else if (_eType == QSubscription::UPDATED_TITLES)
    2. {
    3. C2DM::RouteState *pRoute = (C2DM::RouteState*)objPtr->_clone();
    4.  
    5. for (std::multimap<std::string, QGraphicsItem *>::iterator Values = RouteSourceDuplicates.begin();
    6. Values != RouteSourceDuplicates.end(); ++Values)
    7. {
    8.  
    9. QGraphicsItem *nameSource = Values->second;
    10. nameSource->setData(0, int(pRoute->m_eTxLinkState));
    11. QGraphicsRectItem *rectSource = qgraphicsitem_cast<QGraphicsRectItem *>(nameSource);//it breaks on this qgraphicitem_cast
    12.  
    13. getTitleDescriptionColor(pRoute, m_backgroundColor, rectSource);
    14.  
    15. }
    To copy to clipboard, switch view to plain text mode 

    It only works the first time i load the data, second time it just crushes. it gives an Access violation executing location error(please see attachment,it has the error where it breaks). I am struggling to fix it. I am asking for your guidance once again to make it work, please.
    the duplicate keys in my data is like this:

    Qt Code:
    1. pRoute->m_strSource[Node A] pRoute->m_strDestination[Node B] //same source address but different destinations
    2. pRoute->m_strSource[Node A] pRoute->m_strDestination [Node C]
    To copy to clipboard, switch view to plain text mode 
    and I am using pRoute->m_strSource as my key and QgraphicsItem as a value in std::multimap
    Attached Images Attached Images

  7. #7
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,329
    Thanks
    317
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    second time it just crushes.
    The error seems to be due to an invalid QGraphicsRectItem pointer. Either you are storing a NULL pointer in your map / multimap or you have deleted a QGraphicsRectItem and you have not updated the map / multimap to remove that pointer. So when qgraphicsitem_cast() tries to access the item (the rect pointer) it is accessing a NULL or invalid pointer and it crashes.

    I still do not understand why you are calling clone() every time you access one of your DM:: Object instances. Why? You don't save these cloned copies anywhere. Just cast the "objPtr" to whatever it should be and use it. Don't clone it, because you are simply wasting time and fragmenting memory by repeatedly creating new instances of things, only to throw them away a few lines later when the pointer goes out of scope at the end of the else if() clause.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  8. #8
    Join Date
    Jan 2020
    Posts
    13
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    Thank you for your help once more, its working now, it was an invalid pointer like you said. Concerning the clone() , its the only way I knew how to retrieve the object instances, I am still newbie in this. I am going to try and implement as you advise.Thank you.

    I got another question please if I am still allowed. The nodes(QGraphicsRectItems) in the scene keeps crossing paths. I know I am supposed to set the setPos() for each of the nodes on the scene but I do not how to store the items so that I can set individual setPos(). I read my data from the object instance like this:

    Qt Code:
    1. void GatewayWidget::addRect(DM::Object *_pTitle)
    2. {
    3.  
    4. C2DM::RouteState *pRoute = (C2DM::RouteState*)_pTitle;
    5. QGraphicsRectItem *rectangle;
    6.  
    7. text = scene->addText(QString::fromStdString(pRoute->m_strSource));// pRoute->Source may contain 4, 8 or any number of nodes that are retried from the data
    8. text->setPos(600, (qrand() % 400)); //try to setpos() but its ugly
    9. rectangle = new QGraphicsRectItem(QRectF(0, 0, 60, 60), text); //then put it in QGraphicsRectItems
    To copy to clipboard, switch view to plain text mode 

    I tried to set randomly position them, which is not ideal. Now this makes the QGraphicsLineItems *line that I use to connect source and destination to cross paths(please see attachment). So I am asking for your guidance, on how I can store the nodes(pRoute->Source) ,which will enable me to retrieve and setPos() for each QGraphicRectItem?
    Attached Images Attached Images

  9. #9
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,329
    Thanks
    317
    Thanked 871 Times in 858 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: QGraphicRectItem update colour in foreach statement

    how I can store the nodes
    I think you need to do some research online. Start by using Google for "directed graph c++" and read about the different ways to implement graph data structures. (Your DM Object trees and the matching QGraphicsItem tree) are directed graphs in computer science / mathematics terminology.

    Next you need to use Google to find information on "directed graph layout". There are many ways to lay out graphs, but this Wikipedia article on "Layered graph drawing" might be good for your needs. To draw a layered graph, you create a "row" for each level in your tree. You then count the number of nodes at each level, and the divide the row up into that many boxes and put one node in each box, under the parent it belongs to. You can see an example on the Wikipedia page.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

Similar Threads

  1. foreach or alike
    By prophet0 in forum Qt Programming
    Replies: 18
    Last Post: 5th January 2012, 17:03
  2. foreach error while compiling
    By smanoj in forum Newbie
    Replies: 4
    Last Post: 24th November 2011, 05:32
  3. Help with QT, SQLite, Update Statement
    By chetu1984 in forum Newbie
    Replies: 3
    Last Post: 17th March 2011, 22:24
  4. lifetime of foreach
    By BalaQT in forum Newbie
    Replies: 4
    Last Post: 4th March 2010, 15:55
  5. Foreach performance
    By jano_alex_es in forum General Programming
    Replies: 2
    Last Post: 17th November 2009, 13:26

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.