Полиморфизм - OOP (объектіге бағытталған бағдарламалау) парадигмаларының бірі. Полиморфизм базалық класстың іске асырылуы осы сыныптан мұра болатын болашақ сыныптарға белгісіз қасиеттер мен әдістерді қамтамасыз ету мүмкіндігін жүзеге асырады. Яғни, бұл жағдайда базалық сыныпта тапсырмаларды жүзеге асыру үшін барлық қажетті әдістер жиынтығы бар, бірақ белгілі бір әдістерді нақты жүзеге асыру ұрпақ кластарына жүктеледі. Және, әдетте, базалық класс абстрактілі, яғни одан объектілер жасалмайды.
Мысалы, ағымдағы пішінді таңдай отырып, графикалық көрініс тінтуірмен бірнеше геометриялық фигураларды салуға болатын бағдарламаны іске асыру қажет. қолданбадағы түймелерді пайдалану. Мұны істеу үшін сіз бірнеше сыныптарды жасай аласыз, олардың әрқайсысы барлық қажетті функционалдылықты жүзеге асырады және шын мәнінде әр сыныптағы кодтың көп бөлігін қайталайды, бұл дамуды қиындатады және шатастырады. Немесе бір базалық класс жасай аласыз, мысалы, QGraphicsItem ішінен мұраға алынатын Сурет және осында барлық негізгі функционалдылықты жүзеге асыруға болады. класс, содан кейін қазірдің өзінде осы сыныптан мұра болатын үш класс жасаңыз, бірақ оларда тек фигураның өзін салу әдісін жүзеге асырыңыз: Romb, Square, Triangle.
Келесі суретте Figure базалық класы үшін мұрагерлік логика көрсетілген. Figure класының көп мұрасы сигналдар мен слоттармен жұмысты орындау үшін де қолданылды.
Жоба құрылымы - Мысал бойынша полиморфизм
- PaintFigure.pro - жоба профилі;
- mainwindow.h - қолданбаның негізгі терезесінің тақырып файлы;
- mainwindow.cpp - қолданбаның негізгі терезесі үшін бастапқы код файлы;
- paintscene.h - графикалық көрініс тақырыбының файлы;
- paintscene.cpp - графикалық көріністің бастапқы код файлы;
- figure.h - фигуралардың негізгі класының тақырып файлы;
- figure.cpp - фигуралар класының бастапқы код файлы;
- romb.h - Rhombus класының тақырып файлы;
- romb.cpp - Ромб класының бастапқы код файлы;
- square.h - Square/Rectangle класының тақырып файлы;
- square.cpp - Шаршы/Тіктөртбұрыш класының бастапқы код файлы;
- triangle.h - Triangle класының тақырып файлы;
- triangle.cpp - үшбұрыш сыныбының бастапқы код файлы;
- mainwindow.ui - қолданбаның негізгі терезесінің пішіні.
mainwindow.ui - PaintFigure.pro - main.cpp
Негізгі қолданба терезесінің келесі пішінін конструкторда сызыңыз. Ал PaintFigure.pro және main.cpp файлдары әдепкі бойынша жасалған болып қалады және өзгертілмейді.
mainwindow.h
Қолданбаның негізгі терезесінің тақырып файлында геометриялық фигураларды салуға жауапты болатын теңшелген PaintScene графикалық көрінісін жариялау керек. Біз сондай-ақ resizeEvent() әдісін қайта анықтаймыз, онда қолданба терезесінің өлшеміне байланысты графикалық көріністің өлшемін қайта есептейміз. Бұл таза косметикалық.
#ifndef MAINWINDOW\_H #define MAINWINDOW\_H #include <QMainWindow> #include <QTimer> #include <QResizeEvent> #include "paintscene.h" namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q\_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: Ui::MainWindow *ui; PaintScene *scene; // Объявляем кастомную графическую сцену QTimer *timer; /* Определяем таймер для подготовки актуальных размеров * графической сцены * */ private: /* Переопределяем событие изменения размера окна * для пересчёта размеров графической сцены * */ void resizeEvent(QResizeEvent * event); private slots: // Таймер для изменения размеров сцены при изменении размеров Окна приложения void slotTimer(); void on\_pushButton\_clicked(); // Включаем отрисовку Ромба void on\_pushButton\_2\_clicked(); // Включаем отрисовку Квадрата void on\_pushButton\_3\_clicked(); // Включаем отрисовку Треугольника }; #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); scene = new PaintScene(); // Инициализируем графическую сцену ui->graphicsView->setScene(scene); ui->graphicsView->setRenderHint(QPainter::Antialiasing); // Устанавливаем сглаживание ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по вертикали ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по горизонтали timer = new QTimer(); // Инициализируем таймер connect(timer, &QTimer::timeout, this, &MainWindow::slotTimer); timer->start(100); // Запускаем таймер } MainWindow::~MainWindow() { delete ui; } void MainWindow::slotTimer() { /* Переопределяем размеры графической сцены в зависимости * от размеров окна * */ timer->stop(); scene->setSceneRect(0,0, ui->graphicsView->width() - 20, ui->graphicsView->height() - 20); } void MainWindow::resizeEvent(QResizeEvent *event) { timer->start(100); QMainWindow::resizeEvent(event); } // Ромб void MainWindow::on\_pushButton\_clicked() { scene->setTypeFigure(PaintScene::RombType); } // Квадрат void MainWindow::on\_pushButton\_2\_clicked() { scene->setTypeFigure(PaintScene::SquareType); } // Треугольник void MainWindow::on\_pushButton\_3\_clicked() { scene->setTypeFigure(PaintScene::TriangleType); }
paintscene.h
Теңшелетін графикалық көріністің тақырып файлы. Бұл көріністе кескіннің ағымдағы түрін көрсету үшін сақтауға жауап беретін Q_PROPERTY қасиеті бар. Түрлер тізімі enum FigureTypes арқылы көрсетіледі. Сондай-ақ Figure класының данасы болып табылатын tempFigure нысанының мәлімдемесі бар. Бұл класс полиморфизм парадигмасына сәйкес базалық класс болып табылады, сондықтан ол графикалық сахнада сызылған фигураны уақытша сақтау үшін қолданылады, өйткені тінтуірдің көмегімен фигураның өлшемін орнатудың барлық негізгі әдістері базада жүзеге асырылады. сынып Сурет.
Тінтуір оқиғасының әдістері де қайта анықталған. mousePressEvent әдісінде сурет салу үшін геометриялық фигура құрылады, ал mouseMoveEvent әдісінде тінтуірдің батырмасы босатылғанша тінтуір курсорының орнына байланысты пішін қайта сызылады.
#ifndef PAINTSCENE\_H #define PAINTSCENE\_H #include <QGraphicsScene> #include <QGraphicsSceneMouseEvent> #include "figure.h" class PaintScene : public QGraphicsScene { Q\_OBJECT // Свойство текущего типа используемой фигуры Q\_PROPERTY(int typeFigure READ typeFigure WRITE setTypeFigure NOTIFY typeFigureChanged) public: explicit PaintScene(QObject *parent = 0); ~PaintScene(); int typeFigure() const; // Возвращение текущего типа void setTypeFigure(const int type); // Установка текущего типа // Перечисление типов используемых фигур enum FigureTypes { SquareType, RombType, TriangleType }; signals: void typeFigureChanged(); // Сигнал об изменении типа текущей фигуры private: /* Объект для временного хранения рисуемой фигуры * Является объектом базового класса для всех трёх типов фигур в примере * */ Figure *tempFigure; int m\_typeFigure; // текущий тип фигуры private: // Для рисования используем события мыши void mousePressEvent(QGraphicsSceneMouseEvent * event); void mouseMoveEvent(QGraphicsSceneMouseEvent *event); }; #endif // PAINTSCENE\_H
paintscene.cpp
#include "paintscene.h" #include "romb.h" #include "triangle.h" #include "square.h" PaintScene::PaintScene(QObject *parent) : QGraphicsScene(parent) { } PaintScene::~PaintScene() { } int PaintScene::typeFigure() const { return m\_typeFigure; } void PaintScene::setTypeFigure(const int type) { m\_typeFigure = type; } void PaintScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { /* Устанавливаем конечную координату положения мыши * в текущую отрисовываемую фигуру * */ tempFigure->setEndPoint(event->scenePos()); /* Обновляем содержимое сцены, * необходимо для устранения артефактов при отрисовке фигур * */ this->update(QRectF(0,0,this->width(), this->height())); } /* Как только нажали кнопку мыши, создаём фигуру одного из трёх типов * и помещаем её на сцену, сохранив указатель на неё в переменной * tempFigure * */ void PaintScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { switch (m\_typeFigure) { case SquareType: { Square *item = new Square(event->scenePos()); item->setPos(event->pos()); tempFigure = item; break; } case RombType: { Romb *item = new Romb(event->scenePos()); item->setPos(event->pos()); tempFigure = item; break; } case TriangleType: { Triangle *item = new Triangle(event->scenePos()); item->setPos(event->pos()); tempFigure = item; break; } default:{ Square *item = new Square(event->scenePos()); item->setPos(event->pos()); tempFigure = item; break; } } this->addItem(tempFigure); }
сурет.сағ
Геометриялық фигураларды жасауға арналған негізгі класстың тақырып файлы. Ол полиморфизмді қамтамасыз ететін қай фигура сызылатынына қарамастан геометриялық фигураны салу шекараларын анықтаудың негізгі функционалдығын қамтамасыз етеді. Көрсету үшін екі нүкте пайдаланылады: бастау және соңы . Сызу бастапқы нүктеден басталады және ол өз орнын өзгертпейді, бірақ соңғы нүкте фигура салынған тікбұрышты аймақтың қарама-қарсы бұрышының координатасы болып табылады. Осы нүктелерге байланысты фигуралардың барлық басқа негізгі нүктелері және сәйкесінше осы фигуралардың шекаралары қайта сызылады.
#ifndef FIGURE\_H #define FIGURE\_H #include <QObject> #include <QGraphicsItem> #include <QDebug> class Figure : public QObject, public QGraphicsItem { Q\_OBJECT // Свойство стартовой точки, относительно которой отрисовываем фигуру Q\_PROPERTY(QPointF startPoint READ startPoint WRITE setStartPoint NOTIFY pointChanged) // Свойство конечной точки, до куда отрисовываем фигуру Q\_PROPERTY(QPointF endPoint READ endPoint WRITE setEndPoint NOTIFY pointChanged) public: explicit Figure(QPointF point, QObject *parent = 0); ~Figure(); QPointF startPoint() const; // Стартовая точка QPointF endPoint() const; // Конечная точка void setStartPoint(const QPointF point); // Установка стартовой точки void setEndPoint(const QPointF point); // Установка конечной точки signals: void pointChanged(); // Сигнал об изменении точки private: QPointF m\_startPoint; // Стартовая точка QPointF m\_endPoint; // Конечная точка QRectF boundingRect() const; // Область, в которой содержится фигура public slots: void updateRomb(); // Слот обновления области, в которой содержится фигура }; #endif // FIGURE\_H
цифр.cpp
#include "figure.h" #include <QPainter> Figure::Figure(QPointF point, QObject *parent) : QObject(parent), QGraphicsItem() { // Устанавливаем стартовую координату для отрисовки фигуры this->setStartPoint(mapFromScene(point)); this->setEndPoint(mapFromScene(point)); /* Подключаем сигнал изменения координат к слоту запуска обновления содержимого объекта * Сигнал и слот присутствуют в базовом классе * */ connect(this, &Figure::pointChanged, this, &Figure::updateRomb); } Figure::~Figure() { } QRectF Figure::boundingRect() const { /* Возвращаем область, в которой лежит фигура. * Обновляемая область зависит от стартовой точки отрисовки и от конечной точки * */ return QRectF((endPoint().x() > startPoint().x() ? startPoint().x() : endPoint().x()) - 5, (endPoint().y() > startPoint().y() ? startPoint().y() : endPoint().y()) - 5, qAbs(endPoint().x() - startPoint().x()) + 10, qAbs(endPoint().y() - startPoint().y()) + 10); } void Figure::updateRomb() { // Вызываем обновление области, в которой лежит фигура this->update((endPoint().x() > startPoint().x() ? startPoint().x() : endPoint().x()) - 5, (endPoint().y() > startPoint().y() ? startPoint().y() : endPoint().y()) - 5, qAbs(endPoint().x() - startPoint().x()) + 10, qAbs(endPoint().y() - startPoint().y()) + 10); } void Figure::setStartPoint(const QPointF point) { m\_startPoint = mapFromScene(point); emit pointChanged(); } void Figure::setEndPoint(const QPointF point) { m\_endPoint = mapFromScene(point); emit pointChanged(); } QPointF Figure::startPoint() const { return m\_startPoint; } QPointF Figure::endPoint() const { return m\_endPoint; }
romb.h
Бізге қажет фигура сыныбының тақырып файлында Figure базалық класынан мұра алу және -дан мұраланған paint(), әдісін қайта анықтау қажет. Сурет, класс атасы, яғни QGraphicsItem. Бұл әдіс осы геометриялық фигураны салу логикасын жүзеге асырады.
#ifndef ROMB\_H #define ROMB\_H #include <QObject> #include <QGraphicsItem> #include "figure.h" /* Наследуемся от класса Figure, * в котором реализован общий для всех фигур функционал * */ class Romb : public Figure { Q\_OBJECT public: explicit Romb(QPointF point, QObject *parent = 0); ~Romb(); private: // Для Ромба реализуем только саму отрисовку void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); }; #endif // ROMB\_H
rhombus.cpp
#include "romb.h" #include <QPainter> Romb::Romb(QPointF point, QObject *parent) : Figure(point,parent) { Q\_UNUSED(point) } Romb::~Romb() { } // Реализуем метод отрисовки void Romb::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->setPen(QPen(Qt::black, 2)); QPolygonF polygon; polygon << QPointF(startPoint().x() + (endPoint().x() > startPoint().x() ? + 1 : - 1)* abs((endPoint().x() - startPoint().x())/2), startPoint().y()) << QPointF(endPoint().x(), startPoint().y() + (endPoint().y() > startPoint().y() ? + 1 : - 1)* abs((endPoint().y() - startPoint().y())/2)) << QPointF(startPoint().x() + (endPoint().x() > startPoint().x() ? + 1 : - 1)* abs((endPoint().x() - startPoint().x())/2), endPoint().y()) << QPointF(startPoint().x(), startPoint().y() + (endPoint().y() > startPoint().y() ? + 1 : - 1)* abs((endPoint().y() - startPoint().y())/2)); painter->drawPolygon(polygon); Q\_UNUSED(option) Q\_UNUSED(widget) }
Үшбұрыш және Шаршы сыныптары
Класс деректерінің файлдарының құрылымы Romb класына ұқсас, айырмашылығы тек фигуралық сызбаны жүзеге асыру логикасында.
Барлығы
Полиморфизм парадигмасын шебер қолдану нәтижесінде бағдарлама кодының көлемін айтарлықтай азайтуға, сонымен қатар оны қайта пайдалану жиілігін арттыруға болады, әсіресе егер сіз геометриялық сияқты көптеген ұқсас объектілердің болуын білдірсеңіз. пішіндер.
Алынған қосымшаның демонстрациясы бейне оқулықта берілген.
Жобаны zip-архивте жүктеп алу сілтемесі: PaintFigure
Здравствуйте!
В программировании новичок и есть пара вопросов. Буду очень благодарен за ответ.
Не совсем понимаю как:
1) реализовать подобным образом рисование эллипса(конкретно выбор точек по типу как 22-29 строка в romb.cpp);
2) выбор цвета фигур через диалоговое окно выбора цвета (присваиваю переменной Color цвет, после его выбора в QColorDialog и вместо Qt::black пишу Color, но цвет остается черным).
Добрый день!
Огромное спасибо!
Добрый день, начал только изучать Qt C++.
Здесь скорее нужно использовать стек из указателей, чтобы хранить поочерёдно добавляемые элементы. Например, QVector в конец которого будете добавлять элементы, которые были добавлены на графическую сцену.
Крутой урок! Но как только захотел добавить функцию выделение объекта ( подразумевается перемещение и изменение размера) ничего не получается . Читал что нужно включить флаги ItemIsSelected и ItemIsMovable , и сделал точно также ка к в вашем примере при перетаскивании мышью(23 урок) , но ничего не заработало.Не подскажите как это должно выглядить?
Ну не видя вашего кода, сказать, где у вас ошибка невозможно.
А что касается перетаскивания и разных манипуляций, то можете распотрошить код векторного редактора из этой статьи Qt/C++ - Урок 072. Пример векторного редактора на Qt .
Там достаточно примеров кода по интересующим вас вопросам.
А писать какие-то ещё примеры на эту тему у меня сейчас очень сильно нет времени.
Здравствуйте! Очень нужна помощь, как сделать так чтобы выбранный пользователем цвет границ фигуры применялся только к новой фигуре(которую только собираешься нарисовать), а не ко всем фигурам(уже нарисованным)? Пожалуйста помогите, никак не могу наладить
Внутри класса создайте переменную, которая будет отвечать за цвет объекта и при создании объекта устанавливайте его цвет.