[Solved] Signal & Slot to QGraphicView items



  • Hello
    I have a main window to which a couple of QSpinBox es are attached, as well as a graphicsview. To the graphicsview there's a scene attached which then has qgraphicsview items attached. These again have graphicsviewitem attached to them as well, making the full path to the final item:

    mainwindow->graphicsview->scene->rootgraphicsviewitem->childgraphicsviewitem

    The childgraphicsviewitem inherits QObject making it support signal/slots, and emits the following signal:

    @void updateCordSpinBox(int);@

    I'm now wondering how to attach this signal to the setValue(int) slot of the spinbox? The following naturally fails:

    @QObject::connect(this,SIGNAL(updateCordSpinBox(int)),spinBox_Y2,SLOT(setValue(int)));@

    but I don't know what to set as the target object...

    If any additional information is needed,
    please don't hesitate to request and I'll do my best to respond. Thank you!
    Best regards
    Richard


  • Moderators

    maybe

    @ui->spinBox_Y2 @

    if you used Qt Designer to make your mainwindow, are you?

    what error do you get exactly?



  • first "spinBox_Y2 was not declared in this scope" and with the "ui->" "ui was not declared in this scope"

    The QGraphicsView is added via the designer. The scene is attached using:

    @ scene = new QGraphicsScene();

    ui->graphicsView->setScene(scene);
    ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
    ui->graphicsView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    ui->graphicsView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    

    @

    The rootgraphicsitem is then attached to the scene with:

    @myGItem = new GItem(this, QPixmap(folderPath+"/"+fileName), true, 0, scene);@

    and finally the childitem is added within the myGItem:

    @ Node *node = new Node;
    node->setText("Node");

    node->setPos(cord);
    scene->addItem(node);
    
    scene->clearSelection();
    node->setSelected(true);
    

    @

    (there can be several children attached to one rootgraphics item) Hopefully this clearified the situation...Thanks
    Best regards
    Richard

    ps. heh actually just noticed as I copied the code that the children aren't attached to the rootgraphicsitem but directly to the scene...but I can't really see how this would affect the situation..


  • Moderators

    Have you checked the scope of your varables?

    Where did you put the connect? In the constructor? Can you show its code? Also the definition of you slot.



  • The connect instruction is in the constructor of the "Node", that is the child graphicalitem. Unfortunately I don't really know what to check for regarding the scope...I'm new to Qt and still a bit unsure with the signal/slot principle.

    To be able to connect these, does the element need to know the full path to the object to which it refers to, or does the macros take care of this? In case they need to know the full path, can it be extracted from the information available, being the nodes parent is a graphical scene (though there should be the myGItem in between) which is attached to a main window that has the object in question attached to it? Or do I need to pass a pointer to the main window along the creation path all the way to the Node?

    I'll post the code asap, but I'm away for the weekend and unfortunately do not have access to my code as I forgot to copy it with me... :( But I'll follow the forum and try to reply as well as possible.

    Thank you for you assistance!
    Best regards
    Richard



  • It depends on which method you have used to create your UI widgets from the ui_*.h file. Inheritance vs encapsulation. Please post your code.



  • Also, you could just inherit your QGV items from [[doc:QGraphicsObject]] to enable signal/slot functionality.



  • Hello
    OK so here's the constructor of each class as well the the lines creating the objects:

    @MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    ui->setupUi(this);

    setUpModels();
    setUpScene();
    setUpConnections();
    
    pop = new Preview(this);
    clickedFile = "";
    

    }

    GItem::GItem(QObject *root, const QPixmap &pixmap, bool hidden, QGraphicsItem *parent,
    QGraphicsScene *scene)
    : QObject(root), QGraphicsPixmapItem(pixmap, parent, scene){

    this->scene = scene;
    this->mainImage = pixmap;
    
    if(hidden)
        this->hideElement();
    
    QObject::connect(this,SIGNAL(clicked(QPointF)),this,SLOT(addNode(QPointF)));
    

    }

    Node::Node(QObject *parent) :
    QObject(parent)
    {
    myTextColor = Qt::red;
    myOutlineColor = Qt::red;
    setFlags(ItemIsSelectable);

    QObject::connect(this,SIGNAL(updateCordSpinBox(int)),spinBox_Y2,SLOT(setValue(int)));
    
    emit updateCordSpinBox(15); // to test the connection
    

    }

    // Scene setup

    void MainWindow::setUpScene(){
    scene = new QGraphicsScene();

    ui->graphicsView->setScene(scene);
    ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
    ui->graphicsView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    ui->graphicsView->setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    

    }

    // Constructing the objects:
    MainWindow w;
    GItem *myGItem = new GItem(this, QPixmap("C:/test/ab.png"), false, 0, scene);
    Node *node = new Node(this);@

    With high probability there's something really wrong with the whole logic... Both the GItem and the Node class begin with the "Q_OBJECT" macro.
    B.R.
    Richard



  • If you want to connect the Node object to the spinbox in the Node constructor, the Node class must know about the spinbox. You could accomplish this by passing the spinbox as an extra parameter in the Node constructor.

    But, you probably don't want the Node class to know about the spinbox. A better solution is probably to connect the Node object to the spinbox somewhere else, e.g. in the code that uses the Node constructor to create the Node object. Not sure this is universally true, but I tend to think that connecting two objects a and b is usually better done by the object creating a and/or b, rather than a or b themselves.



  • If I do it this way, and create multiple instances of the Node, do I then need to connect each one of the new instances after creating them?

    And do yo happen to know if this is the correct practice, or if a pointer should be passed all the way to the node?



  • It depends on the use case but often connections between objects are made by a higher-level object that has knowledge of how they should interact. Usually when designing QObject classes you aim for loose coupling ie so that your class does not directly depend upon knowledge of another QObject subclass.

    Having said that it is sometimes convenient to have some level of coupling if the classes in question really are closely related. If your item must always be connected to a spinbox then fine pass the pointer down and have the item make the connection.

    If the item may sometimes not be used in conjunction with a spin box then I would recommend having your higher-level object make the connection.



  • slowly getting the hang of this... though I'm still a bit uncertain how to make the proper connection...
    Just to try I made a connection inside the mainwindo:

    @connect(this,SIGNAL(udsb(int)),ui->spinBox_X1,SLOT(setValue(int)));@

    were the udsb was a signal emitted with a static value when a pushbutton was hit, just to see the value of the spinbox actually changed. This worked fine. My problem is I can't manage to duplicate this from the GItem object... I've made a private MainWindow pointer variable to the GItem class,

    @MainWindow *root;@

    and when creating the object I pass the main window to that pointer.

    @GItem *myGItem = new GItem(this, QPixmap("C:/test/ab.png"), false, 0, scene);@

    were

    @GItem::GItem(MainWindow *root, const QPixmap &pixmap, bool hidden, QGraphicsItem *parent,
    QGraphicsScene *scene)
    : QObject(root), QGraphicsPixmapItem(pixmap, parent, scene){
    this->root = root;
    this->scene = scene;
    this->mainImage = pixmap;@

    The nodes are then created inside myGItem after which I try to connect them to the spinbox, without success...

    @Node *node = new Node(this);
    node->setText("Node");

    node->setPos(cord);
    scene->addItem(node);
    
    scene->clearSelection();
    node->setSelected(true);
    

    // qDebug() << root->
    QObject::connect(node,SIGNAL(updateCordSpinBox(int)),root->ui->spinBox_X1,SLOT(setValue(int)));

    linkList << node;
    qDebug() <&lt; linkList.length();@
    

    I get a error saying

    "invalide use of incomplete type struct Ui::MainWindow"

    The ui variable (holding the UI is set as private, but it didn't help making it public... Any suggestions how to correctly pass a pointer so that I can refer to the spinbox element, added via the designer to ui?
    Thanks
    Richard



  • Quick work around is to add:

    @
    #include "ui_mainwindow.h"
    @

    in your item class implementation. The error just means that your item class has no idea what the Ui::MainWindow type is.

    A better solution would be to have your main window pass through a pointer to the respective spin box rather than a pointer to itself.



  • The problem is there are several spin boxes and then I'd have to pass a pointer to all of them (?). By passing the main window, can't I then access them all?



  • YEY the line you suggested did the trick!! :D Now I'm only curious if this is the best way to do it or if there's another way to pass the information about the multiple spinboxes from the ui...

    A HUGE thanks to all you that participated in helping me!! :D
    Richard



  • [quote author="ThaRez" date="1317039266"]The problem is there are several spin boxes and then I'd have to pass a pointer to all of them (?). By passing the main window, can't I then access them all?[/quote]

    Yes you can access them all this way. But the coupling (as I understand it) is between an item and a specific spinbox. So you should better pass through the appropriate spinbox corresponding to each item when you create each item. Or use the other approach and have the mainwindow make the connections as needed.

    Anyway, glad you got something working.


Log in to reply
 

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