How to achieve exclusive (e.g. Radio Button) type behavior with QGraphicObject?



  • I'm working with Qt (v 5.3) again after sometime away. As a refresher exercise I am prototyping a module using QGraphicView in order to understand better how to use it. The functionality is simple:

    !http://i795.photobucket.com/albums/yy237/skinnyTOD/map_zps8db3bd51.jpg(map)!

    Some number of QGraphicObjects which function like buttons with states and behaviors:

    • OFF - image panel hidden; default button art
    • ON - image panel displayed; highlight button art

    At startup all buttons are in an OFF state

    • A clicked button will toggle it's state (non-Exclusive)
    • If a different button is already in an ON state, it must be turned off (Exclusive)

    Everything is data driven and created dynamically at runtime.


    So that is my little learning exercise. What I am trying to sort out is an efficient messaging mechanism to handle the "radio button sometimes" exclusive behavior and sending a message to a group of objects without strongly coupling them.

    • I've looked at signals and slots but that gets tedious if there are many connections to make.
    • QSignalMapper which seems somewhat better
    • QEvent is probably the most solid approach but I've had trouble finding good learning examples.

    I am making this more complicated than need be but as I say, it's a learning exercise to get used to Qt again.

    So my question (finally): is there an approach I am overlooking (or misunderstanding) or one of these mentioned which would be better (e.g most flexible, maintainable, scalable). Not looking for code per se, but an understanding of how to go about coding something like this using the Qt framework.




  • @
    class RadioButton : public QGraphicsObject {
    static RadioButton selectedButton;
    ...
    void unselect(); // deal with being deselected
    void select(); // deal with being selected
    void mousePressEvent(QGraphicsSceneMouseEvent *) {
    if (selectedButton)
    selectedButton.unselect();
    if (selectedButton != this) {
    selectedButton = this;
    select();
    }
    else
    selectedButton = nullptr;
    }
    };
    @

    There are lots of other options. I think this one is lean while remaining readable. A small adjustment is needed if there is more than one button group.

    Starting from a Qt 5 code base, look at QML / Quick 2 before diving into anything major with Graphics View. On any system with accelerated OpenGL, Quick is almost certainly going to be faster and more efficient at runtime.



  • Thanks – gave that a try but I'm getting errors I don't know how to fix. I was getting an error on nullptr but I changed my .pro file:

    CONFIG += c++11

    and it went away. The other errors were not so yielding (my understanding of C++ is rudimentary at best)

    I understand the concept though: storing a reference to the currently selected item.

    @
    #include <QGraphicsObject>
    #include <QPainter>
    //#include <QGraphicsSceneMouseEvent>

    class ClickSpot : public QGraphicsObject
    {
    Q_OBJECT

    static ClickSpot selectedButton;

    public:
    ClickSpot(QGraphicsItem *parent = 0, QString pathToDir = "");
    virtual ~ClickSpot();

    void unselect(); // deal with being deselected
    void select(); // deal with being selected
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *);
     QRectF boundingRect() const;
    
    
     void mousePressEvent(QGraphicsSceneMouseEvent *) {
    
         if (selectedButton)  // ERROR #1
             selectedButton.unselect();
         if (selectedButton != this) { // ERROR #2
             selectedButton = this; // ERROR #3
             select();
         }
         else
             selectedButton = nullptr;
     }
    

    private:
    bool active;
    QPixmap* onStatePxm;
    QPixmap* offStatePxm;
    };

    @

    error #1: value of type 'ClickSpot' is not contextually convertible to 'bool'
    if (selectedButton)

    error #2: invalid operands to binary expression 'ClickSpot' and 'ClickSpot *')
    _ if (selectedButton != this) {_

    error #3: invalid operands to binary expression 'ClickSpot' and 'ClickSpot *')
    _if (selectedButton != this) {

    error #4: object of type 'ClickSpot' cannot be assigned because its copy assignment operator is implicitly deleted
    selectedButton = nullptr;



  • All four errors are due to ClickSpot being an object instead of a pointer. My pseudocode didn't bother with that detail.

    @
    static ClickSpot * selectedButton;
    @

    and then initialize it in a C++ file:

    @
    ClickSpot * ClickSpot::selectedButton = nullptr;
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.