Search code examples
c++qtqwidgetqpainter

How to draw with QPainter on a specific widget from a group of widgets in QMainWindow?


This is my code:

#include "mainwindow.h"
#include <QDebug>

#include <QCameraInfo>
#include <QHBoxLayout>
#include <fstream>
#include <assert.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    m_QPushButton_calibration = new QPushButton("Calibrate", this);
    connect(m_QPushButton_calibration, SIGNAL (released()),this, SLOT (handleButton()));

    QList<QCameraInfo> l_QListQCameraInfo_available_cameras = QCameraInfo::availableCameras();

    m_QWidget_viewfinder_holder    = new QWidget;
    m_QWidget_viewfinder_holder->setStyleSheet ("background-color: black");

    m_QCameraViewfinder_viewfinder = new QCameraViewfinder(m_QWidget_viewfinder_holder);

    if (l_QListQCameraInfo_available_cameras.length() >= 2)
    {
        m_QCamera_required_camera = new QCamera (l_QListQCameraInfo_available_cameras[1]);

        m_QCamera_required_camera->setViewfinder(m_QCameraViewfinder_viewfinder);
        m_QCamera_required_camera->start ();
    }

    m_QWidget_central     = new QWidget;
    m_QGridLayout_central = new QGridLayout;

    m_QWidget_central->setLayout (m_QGridLayout_central);

    m_QGridLayout_central->addWidget (m_QPushButton_calibration, 0, 0, 1, 1);
    m_QGridLayout_central->addWidget (m_QWidget_viewfinder_holder, 1, 0, 1, 1);

    this->setCentralWidget (m_QWidget_central);

    m_QCameraViewfinder_viewfinder->show();
}

void MainWindow::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setPen(Qt::white);
    painter.setFont(QFont("Arial", 30));
    painter.drawText(rect(), Qt::AlignCenter, "Qt");
}

MainWindow::~MainWindow()
{
    delete m_QPushButton_calibration;
    delete m_QCameraViewfinder_viewfinder;
    delete m_QCamera_required_camera;
    delete m_QGridLayout_central;
    delete m_QWidget_central;
}

void MainWindow::handleButton()
{
    qDebug() << "handleButton";
}

I actually wish to draw a line on m_QWidget_viewfinder_holder widget.

  1. How will that QPaintEvent function know where do I want it to draw line?

  2. Can I use QPaintEvent as a member function in a class inherited from QMainWindow?


Solution

  • How to draw with QPainter on a specific widget from a group of widgets in QMainWindow?

    You cannot draw on a widget from another widget. Each widget is responsible for drawing its own surface in the paintEvent() function.


    How will that QPaintEvent function know where do I want it to draw line?

    First, note that QPaintEvent is a class, not a function.

    Now you probably want to talk about the paintEvent() function. The function "knows" where to draw because it is part of a widget and the widget has a geometry.

    For instance if I want to create a Rectangle widget that draws a rectangle with a 5px margin, I would write something like:

    void Rectangle::paintEvent(QPaintEvent * e)
    {
        QRect rectangle(5, 5, width() - 5, height() - 5);
    
        QPainter painter(this);
        painter.drawRect(rectangle);
    }
    

    Can I use QPaintEvent as a member function in a class inherited from QMainWindow?

    You can reimplement the paintEvent() member function in any class that inherits QWidget. If you inherits from a class that already draws something you need to call your parent class function.

    void MainWindow::paintEvent(QPaintEvent *event)
    {
        QMainWindow::paintEvent(event); // Let QMainWindow draw itself
        QPainter painter(this);
        painter.setPen(Qt::white);
        painter.setFont(QFont("Arial", 30));
        painter.drawText(rect(), Qt::AlignCenter, "Qt");
    }
    

    However, please note that you are not likely willing to reimplement the painteEvent() of a MainWindow. What you generally want to do is to add a child widget to the MainWindow.


    I actually wish to draw a line on m_QWidget_viewfinder_holder widget.

    Create a ViewFinderHolder class like so:

    class ViewFinderHolder: public QWidget {
        Q_OBJECT
        public:
            explicit ViewFinder(QWidget *parent = 0)
        ...
    }
    
    Reimplement the paintEvent() function:
    
    
    class ViewFinderHolder: public QWidget {
        Q_OBJECT
        public:
            explicit ViewFinderHolder(QWidget *parent = 0)
        ...
        protected:
            void paintEvent(QPaintEvent *e);
    }
    
    void ViewFinderHolder::paintEvent(QPaintEvent *event)
    {
        QLineF line(10.0, 80.0, 90.0, 20.0);
    
        QPainter(this);
        painter.drawLine(line);
    }
    

    Finally in the MainWindow constructor replace:

    m_QWidget_viewfinder_holder    = new QWidget;
    

    by:

    m_QWidget_viewfinder_holder    = new ViewFinder();
    

    However, as m_QCameraViewfinder_viewfinder is a child of m_QWidget_viewfinder_holder, it will be drawn over it and may hide the drawing you did in ViewFinderHolder::paintEvent().


    On a side note, you can remove the delete statements in the destructor of MainWindow. Deleting an instance of MainWidow will delete its child widgets.