Can't draw rectangle on a Custom Video Widget with Paint Event



  • For a GUI project I want to select an area on a custom video widget and draw rectangle on selected area.

    So far with the code down below I can select the area with QRubberband but instead of drawing red rectangle when I release the click the code just stops QRubberband from disappearing.

    Here is the code:

    myvideoobject.h

    #ifndef MYVIDEOOBJECT_H
    #define MYVIDEOOBJECT_H
    
    #include <QVideoWidget>
    
    class QRubberBand;
    
    class MyVideoObject : public QVideoWidget
    {
    public:
        MyVideoObject(QWidget *parent = nullptr);
    protected:
        void mouseMoveEvent(QMouseEvent *ev);
        void mousePressEvent(QMouseEvent *ev);
        void mouseReleaseEvent(QMouseEvent *ev);
        void paintEvent(QPaintEvent *ev);
    private:
        QRubberBand *rubberBand;
        QPoint origin;
        QRect rect;
    };
    
    #endif // MYVIDEOOBJECT_H
    

    myvideoobject.cpp

    #include "myvideoobject.h"
    
    #include <QMouseEvent>
    #include <QPainter>
    #include <QRubberBand>
    
    MyVideoObject::MyVideoObject(QWidget *parent):
        QVideoWidget(parent),
        rubberBand(nullptr){}
    
    void MyVideoObject::mousePressEvent(QMouseEvent *ev)
    {
        origin = ev->pos();
        if(!rubberBand)
            rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
        rubberBand->setGeometry(QRect(origin,QSize()));
        rubberBand->show();
        QVideoWidget::mousePressEvent(ev);
    }
    
    void MyVideoObject::mouseMoveEvent(QMouseEvent *ev)
    {
        rubberBand->setGeometry(QRect(origin,ev->pos()).normalized());
        QVideoWidget::mouseMoveEvent(ev);
    }
    
    void MyVideoObject::mouseReleaseEvent(QMouseEvent *ev)
    {
        rect = rubberBand->geometry();
        update();
        QVideoWidget::mouseReleaseEvent(ev);
    }
    
    void MyVideoObject::paintEvent(QPaintEvent *ev)
    {
        QVideoWidget::paintEvent(ev);
        QPainter painter(this);
        painter.save();
        painter.setBrush(Qt::red);
        if(!rect.isNull())
            painter.drawRect(rect);
        painter.restore();
    }
    

    So how can I fix this problem ?


  • Qt Champions 2018

    I'm not sure I understand your problem but if you won't draw the rectangle after the mouseReleaseEvent you should make your rect invalid so your check in paintEvent() (!rect.isNull()) will jump in.



  • @Christian-Ehrlicher How can I make rect invalid? Btw my problem is basically I want to draw a red rectangle on selected area but QRubberband Selection Rectangle doesn't disappear. Sorry for my poor English :)


  • Qt Champions 2018

    @onurcevik said in Can't draw rectangle on a Custom Video Widget with Paint Event:

    How can I make rect invalid?

    rect = QRect()


  • Lifetime Qt Champion

    Hi
    As i read your post, your issue is that QRubberBand stays when you release mouse button?
    If yes to that, you just need
    rubberBand->hide();
    in mouseReleaseEvent



  • @mrjj sadly thats not the only problem. It does hide the QRubberband but the main problem is void MyVideoObject::paintEvent(QPaintEvent *ev) doesnt work. So no rectangle is drawn by that method.


  • Lifetime Qt Champion

    @onurcevik
    Hi
    Are you running live video also on the widget ?
    Code looks fine.
    You can try with fixed rect to see if can draw at all.
    painter.drawRect(QRect(0,0,200,200));



  • @mrjj said in Can't draw rectangle on a Custom Video Widget with Paint Event:

    painter.drawRect(QRect(0,0,200,200));

    I do. Even with fixed rect code it doesn't draw at all. But 5 min ago when I clicked run button with no change in code a red square appeared for a sec then disappeared.!

    Here is a screenshot of current problem this is without using rubberBand->hide();


  • Lifetime Qt Champion

    @onurcevik
    I wonder about all the QPainter warnings you get.

    If you remove
    QVideoWidget::paintEvent(ev);

    does it then work ?



  • @mrjj nope it changes nothing :(


  • Lifetime Qt Champion

    @onurcevik
    Then something else is wrong.
    This must paint something or we have issue else where

    void MyVideoObject::paintEvent(QPaintEvent *ev)
    {
      //   QVideoWidget::paintEvent(ev);
        QPainter painter(this);    
        painter.setBrush(Qt::red);
       painter.drawRect(QRect(0,0,100,100));
    }
    


  • @mrjj Still no rectangle. Problem is probably at somewhere else like you said


  • Lifetime Qt Champion

    @onurcevik
    I was wondering when you do
    // QVideoWidget::paintEvent(ev);
    does video stop being showed ?



  • @mrjj no It didn't . I do the video selecting and playing part on mainwindow.cpp and mainwindow.h which I didn't share here but if you want to take a look at here is the pastebin link : https://pastebin.com/1rk7GJc9


  • Lifetime Qt Champion

    @onurcevik
    Im starting to think the video is not actually drawn via paintEvent but is an overlay
    drawn on top of the widget.
    Searching forum showed post where poster could not get paintEvent to work either.
    https://forum.qt.io/topic/1024/paint-over-qvideowidget/9

    Also, adding an overlay widget to it seems not to work either.
    But we should make a fast test to try it

    QLabel *label = new QLabel(MyVideoObject);
    label->setText("Text over video!");
    label->raise();
    

    does this show?



  • @mrjj Sorry for late reply. Sadly It did not work again . I added that piece of code in mainwindow.cpp where I select and play video with openfiledialog. like this:

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        mediaPlayer = new QMediaPlayer(this);
    
        videoObject = new MyVideoObject(this);
        ui->horizontalLayout_5->addWidget(videoObject);
        videoObject->resize(500,400);
        mediaPlayer->setVideoOutput(videoObject);
        QLabel *label = new QLabel(videoObject);
        label->setText("Text over video!");
        label->raise();
    
    
    
    }
    

    My guess is for some reason video always appears in front of label maybe ?


  • Lifetime Qt Champion

    @onurcevik

    Hi
    Super with test.

    The video must be an overlay
    and we cant draw on it.

    so we could try a top level window and see if that can be over video, or
    the QGraphicsView way, that was reported to work.



  • @mrjj I will try to implement it the QGraphicsView way. I will post the results here :)



  • @mrjj Hey I implemanted the project the QGraphicsView way. But even though I can draw now. When I open a video I can only hear the audio but can't see the video. Can you help me with this now ?

    mygraphicsview.h

    #ifndef MYGRAPHICSVIEW_H
    #define MYGRAPHICSVIEW_H
    
    #include <QObject>
    #include <QWidget>
    #include <QGraphicsView>
    #include <QMouseEvent>
    #include <QPainter>
    #include <QRubberBand>
    #include <QLabel>
    
    class MyGraphicsView : public QGraphicsView
    {
        Q_OBJECT
    public:
        MyGraphicsView(QWidget *parent = nullptr);
    protected:
    
        void mouseMoveEvent(QMouseEvent *ev);
        void mousePressEvent(QMouseEvent *ev);
        void mouseReleaseEvent(QMouseEvent *ev);
        void paintEvent(QPaintEvent *ev);
    private:
           QRubberBand *rubberBand;
           QPoint origin;
           QRect rect;
    
    
    };
    
    #endif // MYGRAPHICSVIEW_H
    

    mygraphicsview.cpp

    #include "mygraphicsview.h"
    
    MyGraphicsView::MyGraphicsView(QWidget *parent):
        QGraphicsView (parent), rubberBand(nullptr){}
    
    void MyGraphicsView::mousePressEvent(QMouseEvent *ev)
    {
        origin = ev->pos();
            if(!rubberBand)
                rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
            rubberBand->setGeometry(QRect(origin,QSize()));
            rubberBand->show();
            QGraphicsView::mousePressEvent(ev);
    
    }
    
    void MyGraphicsView::mouseMoveEvent(QMouseEvent *ev)
    {
        rubberBand->setGeometry(QRect(origin,ev->pos()).normalized());
         QGraphicsView::mouseMoveEvent(ev);
    
    }
    
    void MyGraphicsView::mouseReleaseEvent(QMouseEvent *ev)
    {
        rect = rubberBand->geometry();
        update();
         QGraphicsView::mouseReleaseEvent(ev);
    
    }
    
    void MyGraphicsView::paintEvent(QPaintEvent *ev)
    {
    
        QGraphicsView::paintEvent(ev);
        QPainter painter(this->viewport());
    
        painter.setBrush(Qt::red);
         if(!rect.isNull())
            painter.drawRect(rect);
    
    }
    


  • @onurcevik Did you ever figure the solution for this? Working on it now