SetWindowModified with QGraphicsView, is it bug?



  • Hi all
    I have a custom QGraphicsView
    this View is used in a widget with some layouts.
    when I set the modified window to true in the GraphcisView this widget should be modified and the ancestors should capture this flag and and set their window modified to true.
    I have used [*] in both the child and parent but nothing happened in the parent.

    Any ideas.
    Thanks in Advance



  • Can you post a small compilable example that reproduces the problem please?



  • thanks ZapB
    I'll try to explain it briefly:
    I have a class derived from QGraphicsItem which is YPeerNode
    Another class derived from QGraphicsView is YPeersView

    In YView there is a handler for mousePressEvent, whenever a mouse click happens there will be node added to the stage (view)

    @void YPeersView::mousePressEvent(QMouseEvent *event)
    {
    QPoint p=event->pos();
    QPointF pf=mapToScene(p);
    YPeerNode * node=NULL;
    addNode(pf);
    QGraphicsView::mousePressEvent(event);

    }@

    in addNode, as usual I construct an object and add it to the scene:

    @
    YPeerNode* YPeersView::addNode(QPointF pos)
    {
    YPeerNode* node=new YPeerNode(5);
    node->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);

    if(scene())
    {
        scene()->addItem(node);
        scene()->clearSelection();
        setWindowModified(true);
        node->update();       
        itemsCountChanged(scene()->items().count());
        return node;
    }
    return 0;
    

    }
    @
    The nodes are added and everything is perfect.
    but setWindowModified(true); should set the widget to be modified, I used the setWindowTitle for the View with place holder ([ * ]) and also I've set the placeholder ([ * ]) for the parent widget, the parent widget doesn't receive this change, I can set it manually using its setWindowModified but not applied to the child widget.

    That's what should happen as they say in the help files.

    Thanks



  • Indeed. I can reproduce this problem. As you say from the docs it looks as if this event should propagate up to the top-level parent window. I have stepped into the Qt code and this should be handled by the virtual QWidget::changeEvent() function but it isn't. I also tried it with a QTextEdit child widget instead of a QGraphicsView and got the same results. I'll dig a little deeper.



  • Hmmm this looks to be a bug. As a work around you could emit your own sceneModified() signal form within your mousePressEvent() function and connect this up to a slot in your mainwindow that just does:

    @
    void MainWindow::onSceneModified()
    {
    setWindowModified( true );
    }
    @

    This is what the Qt examples do.

    I have even tried overriding changeEvent() in a mainwindow but it does not receive the supposedly propagated ModifiedChange event.



  • I have confirmed on IRC that this is indeed a bug in Qt. I'll file a bug report and let you know where it is. In the interim just use the above work around.



  • I have filed a bug in JIRA. You can find it at http://bugreports.qt.nokia.com/browse/QTBUG-20150



  • Thank you ZapB, it's really weird I'm working with qt for 1 month, it's too early to find such a bug.

    Regards



  • I think it is a regression (judging by comments on other related bug reports). If I get the time I'll see about making a patch to fix it.



  • I'll try to emit the events manually, I need sometime to read about Events mechanisms in Qt and let you know, thanks



  • Something like this should do it:

    In your YPeersView headr file add a new sceneModified() signal:

    @
    class YPeersView : public QGraphicsView {
    Q_OBJECT
    public:
    ...

    signals:
    void sceneModified();

    ...
    

    };
    @

    Be sure to emit this in you handler instead of calling setWindowModified:
    @
    YPeerNode* YPeersView::addNode(QPointF pos)
    {
    YPeerNode* node=new YPeerNode(5);
    node->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);

    if(scene())
    {
        scene()->addItem(node);
        scene()->clearSelection();
        
        /** \bug In Qt - work around using custom signal */
        //setWindowModified(true);
        emit sceneModified();
    
        node->update();       
        itemsCountChanged(scene()->items().count());
        return node;
    }
    return 0;
    

    }
    @

    In your mainwindow header add a new slot to handle this signal:

    @
    class MainWindow : public QMainWindow {
    Q_OBJECT
    public:
    ...

    public slots:
    void onSceneModified() { setWindowModified( true ); }
    };
    @

    And finally make the connection in your mainwindow ctor (or somewhere else convenient):

    @
    MainWindow::MainWindow( QWidget* parent )
    : QMainWindow( parent )
    {
    ...
    connect( m_view, SIGNAL( sceneModified() ), this, SLOT( onSceneModified() ) );
    }
    @

    That should do it I think.



  • Thanks ZapB
    I'm already using Signals/Slots to notify the parent that the scene items number has been changed
    but I was working on implementing events handlers (custom events)
    I've read that signals/slots don't use separate threads which means non-responsive program.

    I'll try to call events, if it didn't work I'll use the signal/slot mechanism.



  • Hi
    I did it using the events
    My custom event
    @
    class YChangedEvent : public QEvent
    {
    public:
    YChangedEvent();
    };
    @

    in the view custom class I use this function
    @
    void YPeersView::sceneStateChanged()
    {
    QApplication::postEvent(parent(),new YChangedEvent());
    }
    @

    in the Mainwindow
    @
    void YPeerScenarioWidget::customEvent(QEvent *e)
    {

    if(e->type()==YEvents::YCHANGEDEVENT)
    {
        setWindowModified(true);
    }
    

    }

    @

    it works, thanks ZapB
    I think I started to love Qt more than C#



  • Yeah either approach will work. Signals/slots work just like direct function calls if both objects have affinity with the same thread (which yours do form the loosk of things). If the sender and receiver are affine with different threads then the signal/slot mechanism actually uses QEvents behined the scenes and the slot works asynchronously.

    Of course if you are comfortable using custom events yourself then either approach works perfectly fine.

    Glad you got it working anyway. Have fun with the rest of your project.



  • Oh that's good point, Slots/Signals mechanism is really flexible.
    It will save us lot of time.

    Thanks for your help


Log in to reply
 

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