АД
30 августа 2016 г. 17:23

Знакомство с QPainter

paintEngine, QPainter, Qt

Доброго времени суток!
Заранее прошу простить мою некомпетентность в программировании.
Изучая урок, столкнулся с проблемой:при попытке нарисовать внутри QTabWidget линию с помощью QPainter, сталкиваюсь с тем, что ничего не отрисовывается, а в лог выскакивает сообщение
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active

Прошу помочь с решением данной задачи.
Самым великолепным будет проект с решением, т.к. мне намного проще разобраться с готовым решением, чем пытаться что-то синтезировать без наставника =)
.h

#ifndef WIDGET_H
#define WIDGET_H
 
#include <QMainWindow>
#include <QWidget>
#include <QPainter>
 
namespace Ui {
class Widget;
}
 
class Widget : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
 
protected:
    /* Определяем виртуальный метод родительского класса
     * для отрисовки содержимого виджета
     * */
    void paintEvent(QPaintEvent *event);
 
private slots:
    void on_pushButton_clicked();
 
private:
    Ui::Widget *ui;
};
 
#endif // WIDGET_H

.cpp

#include "widget.h"
#include "ui_widget.h"
 
Widget::Widget(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
}
 
Widget::~Widget()
{
    delete ui;
}
 
void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(ui->tab); // Создаём объект отрисовщика
 
    painter.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap));
    painter.drawEllipse(100, 50, 150, 150);
}
 
void Widget::on_pushButton_clicked()
{
    repaint();
}

1
Вопрос задан по статьеQt/C++ - Урок 020. QPainter - знакомство с рисованием в Qt

Вам это нравится? Поделитесь в социальных сетях!

5
Evgenii Legotckoi
  • 30 августа 2016 г. 18:09

Добрый день!

Здесь ошибка в том, что метод paintEvent должен вызываться в классе объекта,
который будет выступать в качестве ui->tab. В уроке передаётся указатель this, который указывается на сам виджет окна. То есть необходимо сделать класс, наследованный от QWidget. В нём уже переопределить метод paintEvent(QPaintEvent * event), и установить экземпляр данного класса в качестве вкладки в QTabWidget. В коде это будет выглядеть следующим образом:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include "formtab.h"
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
private slots:
    void on_pushButton_clicked();
 
private:
    Ui::MainWindow *ui;
    FormTab *m_formTab;
};
 
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_formTab = new FormTab(this);
    ui->tabWidget->addTab(m_formTab, "Paint Tab");
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
 
void MainWindow::on_pushButton_clicked()
{
    m_formTab->repaint();
}

formtab.h

#ifndef FORMTAB_H
#define FORMTAB_H
 
#include <QWidget>
#include <QPaintEvent>
 
namespace Ui {
class FormTab;
}
 
class FormTab : public QWidget
{
    Q_OBJECT
 
public:
    explicit FormTab(QWidget *parent = 0);
    ~FormTab();
 
protected:
    void paintEvent(QPaintEvent *event);
 
private:
    Ui::FormTab *ui;
};
 
#endif // FORMTAB_H

formtab.cpp

#include "formtab.h"
#include "ui_formtab.h"
 
#include <QPainter>
 
FormTab::FormTab(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FormTab)
{
    ui->setupUi(this);
}
 
FormTab::~FormTab()
{
    delete ui;
}
 
void FormTab::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
 
    painter.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap));
    painter.drawEllipse(100, 50, 150, 150);
}

А вообще класс QPainter имеет некоторые ограничения при использовании. Обычно экземпляр QPainter без проблем работает с тем объектом, который является для него родителем, то есть если в экземпляр QPainter передан указатель на тот объект, в котором объявлен QPainter, то всё работает, как правило. В противном случае вылазит сообщение об ошибке, как у Вас.

paintercheck.zip

    АД
    • 30 августа 2016 г. 18:24
    Благодарю за развёрнутый ответ.
    А как возможно передать массив в QPainter для отрисовки для данной задачи?
    Предполагается формировать массив в MainWindow.
      Evgenii Legotckoi
      • 30 августа 2016 г. 18:41

      В FormTab написать метод, который принимает массив. Передать этот массив в экземпляр FormTab, допустим в слоте обработчике нажатия QPushButton, который у Вас уже написан. Ну и присвоить этот массив той переменной, которая будет содержать данный массив в FormTab. А потом уже вызвать repaint(). Логику отрисовки с этим массивом организовать в переопределённом методе paintEvent(QPaintEvent *event).

      Но я бы порекомендовал использовать сразу контейнер, например, QVector, если требуется передать ряд значений для отрисовки ломанной линии, к примеру. Ну и использовать QPainterPath для отрисовки этой линии. Вот в этом уроке в методе paint() сделана отрисовка и через линии и через QPainterPath.

        АД
        • 30 августа 2016 г. 20:03
        • Ответ был помечен как решение.

        Евгений, спасибо большое за консультацию.
        Получилось сделать как хотелось.
        Скидываю проект (вдруг кому-то пригодиться).

        painter.rar

          СГ
          • 24 сентября 2020 г. 12:49

          Здравствуйте! В ваших проектах (paintercheck.zip, painter.rar) отсутствует "ui_formtab.h". Без него не компилируется проект. Я компилирую в Qt Creator 4.3.1 по ubuntu 16.04. Как бы получить этот файл?

            Комментарии

            Только авторизованные пользователи могут публиковать комментарии.
            Пожалуйста, авторизуйтесь или зарегистрируйтесь
            • Последние комментарии
            • IscanderChe
              12 апреля 2025 г. 17:12
              Добрый день. Спасибо Вам за этот проект и отдельно за ответы на форуме, которые мне очень помогли в некоммерческих пет-проектах. Профессиональным программистом я так и не стал, но узнал мно…
            • AK
              1 апреля 2025 г. 11:41
              Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
            • Evgenii Legotckoi
              9 марта 2025 г. 21:02
              К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
            • VP
              9 марта 2025 г. 16:14
              Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
            • ИМ
              22 ноября 2024 г. 21:51
              Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…