Evgenii Legotckoi
21 сентября 2015 г. 20:44

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

Во фреймворке Qt имеется возможность рисовать как на графической сцене , так и прямо на виджетах. Для этого используется класс QPainter. Рисование объектов на виджетах может производится в функции paintEvent(*event) , которая вызывается при отрисовке виджета.

В данном уроке будет производится работа именно с этой функцией. В ней будет создаваться объект класса QPainter, и с его помощью будет рисоваться круг. При этом рисование круга будет зависеть от трех объектов класса QRadioButton. В зависимости от того, какой радиобаттон выбран, будет выбираться и цвет круга, если же ни один радиобаттон не будет выбран, то круг будет рисоваться белого цвета.


Структура проекта для QPainter

Проект содержит следующие файлы:

  • painter.pro - профайл проекта;
  • widget.h - заголовочный файл класса, в котором и производится работа с QPainter;
  • widget.cpp - файл исходных кодов по работе с QPainter;
  • main.cpp - запускающий файл проекта;
  • widget.ui - интерфейс приложения.

widget.ui

В дизайнере форм добавляем в виджет GroupBox с радиобаттонами и вертикальный spacer.

Внешний вид приложения

widget.h

В данном файле только определяем метод paintEvent() .

  1. #ifndef WIDGET_H
  2. #define WIDGET_H
  3.  
  4. #include <QWidget>
  5. #include <QPainter>
  6.  
  7. namespace Ui {
  8. class Widget;
  9. }
  10.  
  11. class Widget : public QWidget
  12. {
  13. Q_OBJECT
  14.  
  15. public:
  16. explicit Widget(QWidget *parent = 0);
  17. ~Widget();
  18.  
  19. protected:
  20. /* Определяем виртуальный метод родительского класса
  21. * для отрисовки содержимого виджета
  22. * */
  23. void paintEvent(QPaintEvent *event);
  24.  
  25. private slots:
  26. void on_radioButton_red_clicked();
  27.  
  28. void on_radioButton_green_clicked();
  29.  
  30. void on_radioButton_blue_clicked();
  31.  
  32. private:
  33. Ui::Widget *ui;
  34.  
  35. };
  36.  
  37. #endif // WIDGET_H

widget.cpp

А вот логика работы приложения полностью помещается в данный файл. В методе paintEvent() реализуем опрос радиобаттонов и по их состоянию рисуем круг на основном виджете.

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3.  
  4. Widget::Widget(QWidget *parent) :
  5. QWidget(parent),
  6. ui(new Ui::Widget)
  7. {
  8. ui->setupUi(this);
  9. }
  10.  
  11. Widget::~Widget()
  12. {
  13. delete ui;
  14. }
  15.  
  16. /* Метод, в котором происходит рисование
  17. * */
  18. void Widget::paintEvent(QPaintEvent *event)
  19. {
  20. Q_UNUSED(event);
  21. QPainter painter(this); // Создаём объект отрисовщика
  22. // Устанавливаем кисть абриса
  23. painter.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap));
  24.  
  25. /* Проверяем, какой из радиобаттонов выбран
  26. * */
  27. if(ui->radioButton_red->isChecked()){
  28. // Если красный, то отрисовываем красный круг
  29. painter.setBrush(QBrush(Qt::red, Qt::SolidPattern));
  30. painter.drawEllipse(100, 50, 150, 150);
  31. } else if(ui->radioButton_green->isChecked()){
  32. // Если зелёный, то отрисовываем зеленый круг
  33. painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
  34. painter.drawEllipse(100, 50, 150, 150);
  35. } else if(ui->radioButton_blue->isChecked()){
  36. // Если синий, то отрисовываем синий круг
  37. painter.setBrush(QBrush(Qt::blue, Qt::SolidPattern));
  38. painter.drawEllipse(100, 50, 150, 150);
  39. } else {
  40. // Если ничего не выбрано, то отрисовываем белый круг
  41. painter.setBrush(QBrush(Qt::white, Qt::SolidPattern));
  42. painter.drawEllipse(100, 50, 150, 150);
  43. }
  44. }
  45.  
  46. /* Как только один из радиобаттонов оказывается нажатым,
  47. * вызываем перерисовку содержимого виджета,
  48. * с которым работаем.
  49. * */
  50. void Widget::on_radioButton_red_clicked()
  51. {
  52. repaint();
  53. }
  54.  
  55. void Widget::on_radioButton_green_clicked()
  56. {
  57. repaint();
  58. }
  59.  
  60. void Widget::on_radioButton_blue_clicked()
  61. {
  62. repaint();
  63. }

Итог

В результате у Вас получится приложение, показанное на ниже следующем рисунке. Демонстрация работы приложения присутствует в видеоуроке по данной статье.

Архив с исходниками: painter

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

И
  • 22 марта 2017 г. 22:12

Доброго времени суток. Подскажите, пожалуйста, следующую вещь: что такое private slots: void on_radioButton_red_clicked(); void on_radioButton_green_clicked(); void on_radioButton_blue_clicked(); Откуда они взялись??? Это какие - то предопределенные слоты класса radiobutton??? Почему они исполняются при нажатии переключателей??? Хоть убей, не пойму... Никакой инфы не нашел. Где они задаются привязанными к переключателям При попытке изменить имя слотов, они перестают работать... Сформулирую вопрос иначе: Где связываются переключатели и эти три слота???

И
  • 22 марта 2017 г. 22:19

Зы, т.е. если, я переименовываю слот, скажем,с void on_radioButton_blue_clicked() на void blue_clicked() в файлах widget.h и widget.cpp, все компилируется, но, переключатель radioButton_blue перестает работать ЗЫ: компилирую пример в Visual Studio. Creatorom и Designerom не пользуюсь... Эти слоты привязываются где - то в них?

Evgenii Legotckoi
  • 22 марта 2017 г. 23:02

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

Qt имеет этап предкомпиляции, когда создаются всякие мок файлы, и в данном случае привязка идёт по текстовому наименованию слота. Если слот не находится, то он не подключается во время компиляции.

Вы должны будете найти подключение этих слотов в ui_widget.h , который автоматически создаётя во время компиляции.

И
  • 23 марта 2017 г. 1:53

Понятно,спасибо,посмотрю...У нас,в виду исторических обстоятельств,весь код писан чисто в vs,без использования креатора(когда собирали qt под студии,креатор,даже,не компилировали),все интерфейсы писались через кодирование,и,все эти ui для меня темный лес... интересно расширить познания в этой области))

Evgenii Legotckoi
  • 23 марта 2017 г. 9:35

Проект, в котором я работаю на данный момент развивается уже более 5-ти лет. Я в нём работаю последние 8 месяцев. Интерфейс полностью написан на Ui, причём с использованием плагинов для Qt Designer, также над продуктом работает команда переводчиков. В продукте сотни диалоговых окон. И из своих наблюдений могу сказать, что если бы не использовались Ui, то в какой-то момент работать стало бы очень грустно, причём не только программистам, но и переводчикам, поскольку тот же самый Qt Linguist, поддерживает отображение Ui файлов, что гораздо удобнее, чем смотреть в код и не понимать, к какому всё-таки окну это относится.

И
  • 23 марта 2017 г. 13:16

У программы нас не имеют статических окошек, как таковых - окна могут быть совершенно различными в зависимости от множества условий, и, "лепятся", прямо, на лету, при запуске. Те, кто начинал проекты, выбрали чистый код, и, тем кто с ними работает сейчас, приходится делать все без использования ui, либо, все переписывать, а, это не на один год работы - проекты большие,ведутся лет 20, множество модулей написаны на всем, что можно только себе вообразить, начиная от ассемблера(работаем с железом и драйверами, в том числе) и заканчивая C#, и, все это завязано на кроссплатформенный qt, поскольку, поддерживается и Линупс. Старая команда отвалила, набрали новыю... Переписывать все жестоко, да, и, опыта у меня маловато

И
  • 23 марта 2017 г. 15:03

Увидел, еще, один интересный момент. Вы написали про редактирование слота clicked(), а, в дизайнере я этой возможности не нашел, но, тут такой момент... у меня qt собрана самостоятельно, без creator-a, есть, только, дизайнер. А, в дизайнере нет поддержки слотов(по правой клавише мыши). Потом, поставил Creator, а, там, дизайнер открывается в контексте проекта, вот, там создание слота clicked,уже есть... Про этот момент я не знал, поэтому, и, не нашел в дизайнере, как создать слот... В новых версиях qt создание слотов из дизайнера вынесли...

Evgenii Legotckoi
  • 23 марта 2017 г. 16:13

Но согласитесь, что отсутствие ui - это проблема того, что проекты давно развиваются, имеется много легаси кода и того, что на момента развития проектов и сам Qt не был так сильно развит. Например, Qt4 и Qt5 довольно сильно различаются, да даже Qt 5.6 очень отличается от Qt 5.8 по некоторым модулям, особенно если полезть в сторону QML. А после пары калымов я вовсе зарёкся браться за проекты с Qt4, особенно те, которые пишутся на устаревших версиях VS. Наверняка, многое можно стандартизировать и шаблонизировать. В нашем проекте сотни диалоговых окон с ui, но все они создаются и наполняются динамически. А также имеют всего несколько базовых классов. Просто различные вкладки интерфейса скрываются или добавляются в зависимости от этих самых условий, про которые вы сказали. Ну а так да. - Переписывать всё действительно жёстко, если проекты давно развиваются, но это уже немного другая история.

Evgenii Legotckoi
  • 23 марта 2017 г. 16:15

Думаю, что это вполне логичное развитие продукта. Без Креатора - это бесполезный функционал.

И
  • 23 марта 2017 г. 19:33

Это логично. Просто, именно, это ввело меня в ступор и заставило отписать в комментариях вчера. Причем, в дизайнере(который отдельно, открывается, без creator-a) есть редактор сигналов и слотов, но, он пуст. А, Creator-a у меня на тот момент не стояло

И
  • 24 марта 2017 г. 11:25

Соглашусь,там люди начинали с делфи,вообще,в свое время,когда все зарождалось потом,постепенно,постепенно,все облагораживалось,портировалось на более вменяемые средства разработки... Наши ребята-программисты(среди которых и я пятый помощник десятого стажера),говорят,что,ui вполне можно было использовать... у нас,еще,осложняется все тем,что,мы поддерживаем sdk,свои,на которой заказчики строят ПО,этих sdk несколько,если переписать,то,будет,еще на sdk больше,поскольку,старую никуда не денешь,а,заказчики консервативны.Сделали один раз и навсегда... у нас сфера промышленных систем,там еще компы на DOS,встречаются,до сих пор!!!)))))))

Комментарии

Только авторизованные пользователи могут публиковать комментарии.
Пожалуйста, авторизуйтесь или зарегистрируйтесь