Тема: «Графические элементы и строки состояния» Пример 1: программа, которая вписывает N-угольник в окружность. При соединении вершин их можно проходить с шагом M, например через две или через три. Окружность задается двумя щелчками мыши (в центре и на окружности). Числа N и M считываются с клавиатуры в главном окне. Создайте проект на основе класса QMainWindow. Щелкните по центру заготовки окна и в свойствах окна (MainWindow) измените свойство palette : сделайте двойной щелчок справа от этого слова и в появившемся окне Edit Palette найдите в списке Window (это свойство определяет цвет поверхности окна). Сделайте двойной щелчок справа от этого слова, появиттся окно Select Color. Выберите белый цвет окна. Закройте окна, щелкнув по кнопке OK.
Запустите программу и посмотрите как выглядит окно.
Вставьте в файл main.cpp код, показанный ниже: #include
#include "mainwindow.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.resize(400,400); // задаем размер окна w.move(450,250); // перемещаем окно в центр экрана w.show(); return a.exec(); }
Вставьте в объявление класса MainWindow (файл mainwindow.h) объявления переменных:
int n, m; // количество вершин многоугольника и шаг прохождения через вершины QPoint p[2]; // точки, по которым мы щелкаем мышью int counter; // счетчик щелчков мышью QString str; // строка, которая хранит задаваемые числа bool flag; // признак окончания ввода QLabel *label1, *label2; // панели для строки состояния double koef; // масштабный коэффициент для перевода радиуса в см Добавьте сюда же объявления функций: void paintEvent(QPaintEvent *); // эта функция автоматически вызывается при перерисовке окна void mousePressEvent(QMouseEvent *); // вызывается при нажатии кнопки мыши void keyPressEvent(QKeyEvent *); // вызывается при нажатии клавиши на клавиатуре
Вставьте в файл mainwindow.cpp код, показанный ниже:
#include "mainwindow.h" #include "ui_mainwindow.h" #include // обеспечивает работу графического интерфейса MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf-8")); // обеспечиваем использование кириллицы m = n = 1; counter = 0; flag = false; label1 = new Qlabel(ui->statusBar); // создаем панель для строки состояния label1->setFrameStyle(QFrame::Panel | QFrame::Sunken); // задаем вид панели (утопленная) // то же самое для второй панели: label2 = new QLabel(ui->statusBar); label2->setFrameStyle(QFrame::Panel | QFrame::Sunken); // Определяем вид строки состояния: QPalette pal = ui->statusBar->palette(); // считывам палитру строки состояния pal.setColor(QPalette::Background, QСolor(215,220,210)); // задаем цвет фона строки состояния pal.setColor(QPalette::Foreground, QСolor(0,50,0)); // Задаем цвет текста в стороке состояния ui->statusBar->setPalette(pal); // Устанавливаем новую палитру ui->statusBar->setAutoFillBackground(true); // Нужно вызвать эту функцию, чтобы строка состояния закрасилась ui->statusBar->setSizeGripEnabled(false); // запрещаем показ маркера изменения размеров окна (это не обязательно) // Добавляем в правую часть строки состояния панели: ui->statusBar->addPermanentWidget(label1); ui->statusBar->addPermanentWidget(label2); /* Определим разрешение экрана для определения масштабного коэффициента для пересчета размеров в см: */ QDesktopWidget *desktop = QApplication::desktop(); int width = desktop->width(); // ширина экрана в точках int height = desktop->height(); // высота экрана в точках qDebug() << width <<" "<< height; // можно посмотреть, что получилось koef = 2.54*19/sqrt(width*width+height*height); /* вычисляем длину диагонали в см (в данном случае предполагается, что длина диагонали 19 дюймов) и делим на длину диагонали в точках */ qDebug()<<"koef = " << koef; // посмотрите значение масштабного коэффициента } MainWindow::MainWindow() { delete ui; } // функция, обрабатывающая щелчки мышью: void MainWindow::mousePressEvent(QMouseEvent* event) { if (event->button() == Qt::LeftButton) // если щелкнули левой кнопкой мыши { counter %= 2; // номер точки может быть равен 0 или 1 p[counter++] = event->pos(); // записываем координаты точки, в которой пользователь щелкнул мышью update(); // перерисовываем окно } } // функция, обрабатывающая нажатие клавиш на клавиатуре: void MainWindow::keyPressEvent(QKeyEvent *event ) { QRegExp reg("[0-9]{1,3} [0-9]{1}"); // позволим вводить первое число не более, чем из 3 цифр и второе - из одной QRegExpValidator* validator = new QRegExpValidator(reg, this); // создаем валидатор для проверки строки на основе регулярного выражения int pos = 0; // эта переменная нужна для вызова валидатора if (flag) // если клавиша уже была нажата { str.clear(); // начинаем ввод сначала flag = false; } else { switch (event->key()) // проверяем, какая клавиша была нажата { case Qt::Key_Return: // если : { QTextStream in(&str,QIODevice::ReadOnly); // создаем поток из строки in >> n >> m; // считываем n и m flag = true; // запоминаем, что ввод выполнен } break; case Qt::Key_Backspace: // обеспечиваем возможность стирания: { int len = str.length(); // определяем длину строки str.remove(len-1, 1); // удаляем последний символ } break; default: QString ch = event->text(); // если обычный символ, считываем его QString tmp = str + ch; // попробуем добавить его к строке if (validator->validate(tmp, pos)) // если временная строка соответствует шаблону str += ch; // добавляем символ к используемой строке } } update(); // обновляем экран ui->statusBar->showMessage("Готово"); // Выводим сообщение в левой части строки состояния } // описываем, что нужно нарисовать в окне: void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); // объект для рисования painter.setBrush(QBrush(QColor(0,255,255))); // кисть QRect rect(0,0,width(), height()); // прямоугольник окна painter.setFont(QFont("Bitstream Charter",12)); // шрифт int r = 0; // радиус окружности if (counter == 2) // если окружность задана, рисуем ее { painter.setPen(QPen(QColor(0,255,0), 1)); // перо r = sqrt(pow(p[0].x() - p[1].x(), 2) + pow(p[0].y() - p[1].y(), 2)); // радиус окружности painter.drawEllipse(p[0], r, r); // рисуем окружность с центром в точке p[0] if (flag) // если числа заданы { QPoint* v = new QPoint[n]; // создаем массив для хранения вершин v[0] = p[0] + QPoint(r,0); // начальная вершина многоугольника double da = 2 * M_PI / n; // угол между вершинами double a = 0; // угол, соотвествующий очередной вершине for (int i = 1; i < n; ++i) // проходим вершины (кроме начальной) { a += m * da; // изменяем угол // вычисляем координаты: v[i].setX(p[0].x() + r*cos(a)); v[i].setY(p[0].y() - r*sin(a)); } painter.setBrush(Qt::darkCyan); // цвет многоугольника painter.drawPolygon(v, n, Qt::WindingFill); // рисуем закрашенный многоугольник } } // описываем вывод в зависимости от количества щелчков мышью: painter.setPen(QPen(QColor(100, 0, 100), 3));// цвет текста switch (counter) { case 0: painter.drawText(10, 40, "Задайте окружность двумя щелчками мыши"); break; case 1: painter.drawEllipse(p[0].x(), p[0].y(), 2, 2); break; case 2: if (flag) painter.drawText(10, 40, "Задайте число разбиений и шаг " + str); else painter.drawText(10, 40, "Задайте число разбиений и шаг " + str + '_'); } // Выводим информацию с помощью панелей строки состояния: QString text = QString("Координаты центра: %1, %2").arg(p[0].x()).arg(p[0].y()); label1->setText(text); double rsm = r*koef; // радиус в см text = QString(" радиус %1 см ").arg(rsm, 0,'f',1); // выводим радиус с точностью 1 знак после точки label2->setText(text); }
Пример 2: программа, в которой используется область отсечения QRegion и котекстное меню для выбора способа заливки этой области. Создайте проект на основе класса QMainWindow. Добавьте в класс MainWindow (файл mainwindow.h) объявления данных и функций:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include // обеспечивает программирование графического интерфейса namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); MainWindow(); void contextMenuEvent(QContextMenuEvent *event); // обрабатывет щелчок правой кнопкой мыши void paintEvent(QPaintEvent *); // перерисовывает окно QRegion region; // область отсечения QMenu* contextMenu; // указатель для создания контекстного меню QBrush brush; // кисть для закрашивания области отсечения qreal x, y; // начальная точка области рисования qreal width, height; // ширина и высота области рисования qreal cx, cy; // координаты центра области рисования bool diagcross; // признак диагональной заливки public slots: void Solid(); // для действия «Сплошная» void Semitransparent(); // «Полупрозрачная» void Gradient(); // «Градиентная» void DiagCross(); // «Сетка» p rivate: Ui::MainWindow *ui; }; #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); // обеспечиваем использование кириллицы: QTextCodec* codec = QTextCodec::codecForName("Utf-8"); QtextCodec::setCodecForCStrings(codec); contextMenu = new QMenu(this); // создаем контекстное меню // Действия для контекстного меню: QAction* actSolid = new QAction("Сплошная", this); contextMenu->addAction(actSolid); connect(actSolid, SIGNAL(triggered()), this, SLOT(Solid())); contextMenu->addSeparator(); QAction* actSemitransparent = new QAction("Полупрозрачная", this); contextMenu->addAction(actSemitransparent); connect(actSemitransparent, SIGNAL(triggered()), this, SLOT(Semitransparent())); contextMenu->addSeparator(); QAction* actGradient = new QAction("Градиентная", this); contextMenu->addAction(actGradient); connect(actGradient, SIGNAL(triggered()), this, SLOT(Gradient())); contextMenu->addSeparator(); QAction* actDiagcross = new QAction("Сетка", this); contextMenu->addAction(actDiagcross); connect(actDiagcross, SIGNAL(triggered()), this, SLOT(DiagCross())); brush = QBrush(Qt::darkGreen); // начальный цвет кисти diagcross = false; // в начале заливка - сплошная } MainWindow::MainWindow() { delete ui; } void MainWindow::paintEvent(QPaintEvent * e) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // установили режим сглаживания линий // Начальные координаты области рисования относительно главного окна: x = centralWidget()->x(); y = centralWidget()->y(); //qDebug() << x << y; // посмотрите значения этих координат width = centralWidget()->width(); // ширина области рисования height = centralWidget()->height(); // высота области рисования // Координаты центра области рисования: cx = x + width/2; cy = y + height/2; qreal right = x+width; // координата правой границы области рисования qreal bottom = y+height; // координата нижней границы области рисования // Закрашиваем область рисования: QColor color = QColor(200,150,100); painter.setBrush(color); QRectF rect(x,y,width, height); painter.drawRect(rect); // Отступы от границ для эллипса qreal dx = width/10; qreal dy = height/10; // определяем область в виде эллипса: QRegion ellipticRgn = QRegion(x+dx, y+dy, width-2*dx, height-2*dy, QRegion::Ellipse); // Определяем многоугольник: QPolygon polygon; // Отступы от границ области рисования dx = width/20; dy = height/20; // Определяем вершины многоугольника: polygon << QPoint(x+dx, y+dy) << QPoint(cx, cy) << QPoint (right - dx, y+dy) << QPoint(right - dx, bottom-dy) << QPoint(cx,cy) << QPoint(x+dx, bottom-dy); QRegion polygonRgn(polygon); // Область отсечения в виде двух треугольников region = ellipticRgn.xored(polygonRgn); // Объединяем области с помощью оперции «исключающее или» painter.setClipRegion(region); // устанвливаем область отсечения // Если выбрана «Сетка»: if (diagcross) painter.fillRect(e->rect(),QBrush(Qt::green)); // заливаем фон области отсечения (это не обязательно) painter.fillRect(e->rect(), brush); /* заливаем область отсечения выбранным способом (указываем весь прямоугольник окна, но закрашена будет только область отсечения) */ painter.setClipping(false); // Отменяем установку области отсечения /* рисуем диагонали области рисования (для проверки, что она восстановлена, и для проверки, что фигура центрирована) */ painter.drawLine(x,y,right, bottom); painter.drawLine(right,y, x, bottom ); } // Функция, которая выводит на экран void MainWindow::contextMenuEvent(QContextMenuEvent *event) { QPoint point = event->pos(); // определяем координаты курсора мыши if (region.contains(point)) // проверяем, щелкнули ли мы внутри области отсечения { contextMenu->exec(event->globalPos()); // выводим меню на экран } } // Слот для команды «Сплошная»: void MainWindow::Solid() { brush = QBrush(Qt::darkGreen); diagcross = false; update(); } // Слот для команды «Полупрозрачная» : void MainWindow::Semitransparent() { QColor color(0, 128, 0, 100); // последний параметр определяет прозрачность (255 — не прозрачный) diagcross = false; brush = QBrush(color); update(); } // Слот для команды «Градиентная»: void MainWindow::Gradient() { QRadialGradient gradient(QPoint(cx, cy),width/2,QPoint(cx, cy)); // параметры: центральная точка, радиус и точка фокуса // определяем цвета заливки, которые будут переходить друг в друга: gradient.setColorAt(0, Qt::yellow); QColor color(255, 100, 0); gradient.setColorAt(0.5, color); gradient.setColorAt(1, Qt::darkGreen); brush = QBrush(gradient); // устанавливаем кисть для градиентной заливки diagcross = false; update(); } void MainWindow::DiagCross() { brush = QBrush(Qt::darkGreen, Qt::DiagCrossPattern); // определяем кисть для заливки сеткой diagcross = true; /* устанавливаем признак заливки сеткой (чтобы предварительно залить фон для сетки) */ update(); }
Задания для самостоятельного выполнения Зарисовать окно «пчелиными сотами» (правильными шестиугольниками). Процесс зарисовки начинается при нажатии одной из кнопок мыши. Размер стороны шестиугольника - 1/n – ая часть длины меньшей стороны окна. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. В строке состояния вывести длину стороны шестиугольника и общее количество сот. Окружность разделить на N равных частей. Соединить все точки разбиения хордами. Число разбиений N ввести с клавиатуры. Диалоговое окно использовать нельзя! Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр окружности и одну точку, принадлежащую окружности, отметить нажатием левой кнопки мыши. В строке состояния вывести радиус окружности и длину хорды в точках и см. Каждую сторону квадрата разделить на N равных частей. Соединить все точки разбиения, включая вершины, отрезками. Число разбиений N ввести с клавиатуры. Диалоговое окно использовать нельзя! Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр квадрата и одну точку, принадлежащую стороне квадрата, отметить нажатием левой кнопки мыши. В строке состояния вывести координаты центра квадрата и длину стороны квадрата в точках и см. Каждую сторону равностороннего треугольника разделить на N равных частей. Соединить все точки разбиения, имеющие одинаковые номера, отрезками вписав, таким образом, N треугольников в исходный треугольник. Число разбиений N ввести с клавиатуры. Диалоговое окно использовать нельзя!Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр треугольника отметить нажатием левой кнопки мыши. Длину стороны взять максимально возможную для отмеченной точки, но чтобы треугольник не выходил за пределы окна. В строке состояния вывести координаты центра треугольника и длину его стороны в точках и см. Каждую сторону прямоугольника разделить на N равных частей. Соединить все точки разбиения, имеющие одинаковые номера, отрезками вписав, таким образом, N четырехугольников в исходный прямоугольник. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Диалоговое окно использовать нельзя! Центр прямоугольника и одну из его вершин отметить нажатием левой кнопки мыши. В строке состояния вывести координаты центра прямоугольника и длины его сторон в точках и см. Построить на экране дисплея произвольный прямоугольник, фиксируя его центр и одну из вершин с помощью кнопки мыши. Заштриховать внутреннюю область прямоугольника прямоугольной сеткой (горизонтальными и вертикальными отрезками, параллельными сторонам прямоугольника). Расстояние между линиями штриховки – 1/n – ая часть длины меньшей стороны прямоугольника. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра прямоугольника и длины его сторон в точках и см. Построить на экране дисплея произвольный прямоугольник, фиксируя его центр и одну из вершин с помощью кнопки мыши. Заштриховать внутреннюю область прямоугольника наклонной сеткой (отрезками с наклоном 45 и 135 градусов). Расстояние между линиями штриховки – 1/n – ая часть длины меньшей стороны прямоугольника. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра прямоугольника и длины его сторон в точках и см. На экране дисплея построить правильный N-угольник, вписанный в окружность. Число N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр многоугольника и одну точку на окружности зафиксировать с помощью кнопки мыши. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра окружности и площадь N-угольника в точках и см2. Окружность разделить на N равных частей. Из каждой точки разбиения, как из центра, провести окружность радиусом, равным половине радиуса исходной окружности. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр окружности и одну точку, принадлежащую окружности, отметить нажатием левой кнопки мыши. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра исходной окружности и площадь одной маленькой окружности в точках и см2. Каждую сторону квадрата разделить на N равных частей. Из каждой точки разбиения, включая вершины, как из центра, провести окружность радиусом, равным расстоянию от точки до центра квадрата. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр квадрата и одну точку, лежащую на стороне квадрата, отметить нажатием левой кнопки мыши. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра квадрата и его площадь в точках и см2. Каждую сторону квадрата разделить на N равных частей. Каждую точку разбиения, включая вершины, соединить с центром квадрата. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр квадрата и одну точку, являющейся вершиной квадрата, отметить нажатием левой кнопки мыши. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра квадрата и его площадь в точках и см2. Каждую сторону квадрата разделить на N равных частей. Соединить симметричные точки разбиения, лежащие на противоположных сторонах квадрата. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр квадрата и одну точку, являющейся вершиной квадрата, отметить нажатием левой кнопки мыши. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра квадрата и его площадь в точках и см2. Каждую сторону квадрата разделить на N равных частей. Соединить точки разбиения, лежащие на смежных сторонах квадрата и имеющие одинаковые номера. Число разбиений N ввести с клавиатуры. Обеспечить контроль правильности ввода и возможность стирания символов, которые введены ошибочно. Центр квадрата и одну точку, являющейся вершиной квадрата, отметить нажатием левой кнопки мыши. Диалоговое окно использовать нельзя! В строке состояния вывести координаты центра квадрата и его площадь в точках и см2.
Лабораторная работа № 7 Тема: «Рисование мышью»
Пример 1: программа, которая рисует траектории движения мыши при нажатой левой кнопке выбранным цветом и стирает рисунок при щелчке правой кнопкой мыши. Создайте проект на основе главного окна и задайте белый цвет фона в свойствах этого окна.
В файле mainwindow.h объявите функции:
void mousePressEvent(QMouseEvent *e); // функция, вызываемая при нажатии кнопки мыши void mouseMoveEvent(QMouseEvent *e); // функция, вызываемая при движении мыши void paintEvent(QPaintEvent *); // функция, автоматически вызываемая при перерисовке окна
Тамже объявите переменные и объекты:
QColor color; // цвет линий QPoint p[2]; // точки, определяющие линию (фрагмент траектории движения мыши) bool drawMode; // признак рисования QList DrawBuffer; // список для хранения линий QList ColorBuffer; // список для хранения цветов линий public slots: void showDialog(); // слот, вызываемый при нажатии кнопки в меню
Отредактируйте файл mainwindow.cpp как показано ниже:
#include "mainwindow.h" #include "ui_mainwindow.h" #include MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // обеспечиваем использование кириллицы: QTextCodec* codec = QTextCodec::codecForName("UTF-8"); QTextCodec::setCodecForCStrings(codec); // добавляем в меню кнопку без выпадающего списка QAction* act = ui->menuBar->addAction("Выбор цвета"); // устанавливаем акселератор: act->setShortcut(QString("Alt+C")); // при нажатии на кнопку в меню должно появиться окно для выбора цвета: connect(act, SIGNAL(triggered()), this, SLOT(showDialog())); // задаем начальные значения: p[0] = p[1] = QPoint(0,0); color = QColor(0,100,100); drawMode = false; } MainWindow::MainWindow() { delete ui; } void MainWindow::showDialog() { color = QColorDialog::getColor(); // считываем цвет } void MainWindow::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) // если нажата левая кнопка мыши { drawMode = true; // устанавливаем признак рисования p[0] = e->pos(); // запоминаем координаты начальной точки } if (e->button() == Qt::RightButton) // если нажата правая кнопка { color = QColor(0,100,100); // восстанавливаем первоначальный цвет DrawBuffer.clear(); // очищаем списки ColorBuffer.clear(); drawMode = false; // правой кнопкой запретим рисовать update(); // перерисовываем окно } } void MainWindow::mouseMoveEvent(QMouseEvent *e) { if (drawMode) // если установлен режим рисования { p[1] = e->pos(); // запоминаем текущую точку DrawBuffer.append(QLine(p[0],p[1])); // добавляем линию в список ColorBuffer.append(color); // добавляем текущий цвет в список p[0] = p[1]; // текущую точку делаем начальной для следующего фрагмента линии update(); } } void MainWindow::paintEvent(QPaintEvent *) { if (DrawBuffer.size() < 1) return; // если рисовать нечего, выходим из функции QPainter painter(this); // объявляем итераторы для работы со списками: QList::const_iterator it = DrawBuffer.begin(); QList::const_iterator cit = ColorBuffer.begin(); // перерисовываем линии: do { painter.setPen(*cit++); // определяем перо того цвета, которое хранится в списке painter.drawLine(*it++); // рисуем фрагмент линии } while (it!= DrawBuffer.end()); // повторяем рисование, пока не закончится список }
Пример 2: программа, которая рисует окружности с помощью мыши (окружность видима в процессе построения). Нарисованные окружности можно сохранить в файле и загрузить из файла. Создайте проект на основе главного окна и задайте белый цвет фона в свойствах этого окна.
По аналогии с предыдущим примером мы будем запоминать нарисованные окружности в списке. Но для того, чтобы использовать такие списки нам нужно определить класс, описывающий окружности.
Щелкните в окне, описывающем структуру проекта (слева), по имени проекта правой кнопкой мыши и в появившемся контекстном меню выберите Add New...
В появившемся диалоговом окне выберите С++ | C++ Class. Задайте имя класса Circle и завершите создание класса. К проекту будут добавлены файлы circle.h и circle.cpp, содержащие описание нашего класса.
Для описания окружности мы будем использовать координаты центра, радиус и цвет окружности. Хранить в списках можно только такие объекты, для которых определены конструктор по умолчанию, конструктор копирования и оператор присваивания. Кроме того нам потребуется основной коструктор.
Отредактируйте файл circle.h как показано ниже:
#ifndef CIRCLE_H #define CIRCLE_H #include // обеспечивает графическую систему class Circle { public: QPoint p; // координаты центра окружности int r; // радиус QColor color; // цвет Circle(); // конструктор по умолчанию Circle(QPoint& _p, int _r, QColor col); // основной конструктор Circle(const Circle& ); // конструктор копирования Circle& operator = (const Circle& ); // оператор присваивания }; #endif // CIRCLE_H
Отредактируйте файл circle.cpp как показано ниже:
#include "circle.h" Circle::Circle() { p = QPoint(0,0); r = 0; color = Qt::darkCyan; } Circle::Circle(QPoint &_p, int _r, QColor col = Qt::darkCyan) { p = _p; r = _r; color = col; } Circle::Circle(const Circle & circle) { p = circle.p; r = circle.r; color = circle.color; } Circle& Circle::operator =(const Circle & circle) { p = circle.p; r = circle.r; color = circle.color; return *this; }
Перейдите к редактированию дизайна окна. Добавьте в меню команду Файл.
В выпадающее меню добавьте действия: Открыть (actionOpen), Сохранить (actionSave) и Выход (actionQuit). Определите акселераторы для этих действий. Свяжите нажатие кнопки «Выход» со слотом close() главного окна.
Добавьте в меню команду Редактирование. В выпадающее меню добавьте действия: Выбрать цвет (actionColor), Отменить (actionAnnul), Очистить (actionClear).
Отредактируйте файл mainwindow.h как показано ниже:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include "circle.h" // обеспечивает использование типа Circle namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); MainWindow(); QPoint p[2]; // точки, которые определяют текущую окружность int r; // радиус bool drawMode; // признак рисования QList DrawBuffer; // список окружностей (ради этой строчки мы создали класс Circle) QColor color; // цвет текущей окружности void mousePressEvent(QMouseEvent *); // обрабатывает нажатие кнопки мыши void mouseMoveEvent(QMouseEvent *); // обрабатывает движение мыши void mouseReleaseEvent(QMouseEvent *); // обрабатывает отпускание кнопки мыши void paintEvent(QPaintEvent *); // описывает, что нужно нарисовать в окне public slots: void Annul(); // для кнопки «Отменить» void Clear(); // для кнопки «Очистить» void showDialog(); // для кнопки «Выбрать цвет» void save(); // для кнопки «Сохранить» void open(); // для кнопки «Открыть» private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
Отредактируйте файл mainwindow.cpp как показано ниже:
#include "mainwindow.h" #include "ui_mainwindow.h" /* Для того, чтобы можно было сохранить список окружностей, нужно научить программу сохранять каждый объект класса Circle: */ QDataStream& operator <<(QDataStream& ostream, const Circle& c) { ostream << c.p.x()<< c.p.y() << c.r << c.color ; return ostream; } // Описываем, как считывать из потока каждый объект класса circle: QDataStream& operator >> (QDataStream& istream, Circle& c) { int x, y; istream >> x >> y >> c.r >> c.color; c.p.setX(x); c.p.setY(y); return istream; } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); // связываем сигналы от команд меню с соответствующими слотами: connect(ui->actionAnnul, SIGNAL(triggered()), this, SLOT(Annul())); connect(ui->actionClear, SIGNAL(triggered()), this, SLOT(Clear())); connect(ui->actionColor, SIGNAL(triggered()), this, SLOT(showDialog())); connect(ui->actionSave, SIGNAL(triggered()), this, SLOT(save())); connect(ui->actionOpen, SIGNAL(triggered()), this, SLOT(open())); // инициализируем элементы данных класса MainWindow: drawMode = false; p[0] = p[1] = QPoint(0,0); r = 0; color = Qt::darkCyan; } MainWindow::MainWindow() { delete ui; } // Обрабатываем нажатие кнопки мыши: void MainWindow::mousePressEvent(QMouseEvent * e) { if (e->button() ==Qt::LeftButton) // если нажата левая кнопка { drawMode = true; // разрешаем рисование p[0] = e->pos(); // запоминаем центр окружности } } // Обрабатываем движение мыши: void MainWindow::mouseMoveEvent(QMouseEvent * e) { if (drawMode) // если прижата левая кнопка { p[1] = e->pos(); // запоминаем текущую точку на окружности r = sqrt(pow(p[1].x()-p[0].x(),2) + pow(p[1].y()-p[0].y(),2)); // вычисляем радиус окружности update(); // перерисовываем окно } } // Обрабатываем отпускание кнопки мыши: void MainWindow::mouseReleaseEvent(QMouseEvent *) { drawMode = false; // запрещаем рисование int r = sqrt(pow(p[1].x()-p[0].x(),2) + pow(p[1].y()-p[0].y(),2)); // вычисляем текущий радиус DrawBuffer.append(Circle(p[0], r, color)); // добавляем окружность в список update(); // перерисовываем окно } // Описываем, что нужно нарисовать в окне void MainWindow::paintEvent(QPaintEvent *) { QPainter painter(this); int size = DrawBuffer.size(); if (size) // Если список не пуст: { // рисуем окружности, сохраненные в списке: QList::const_iterator it = DrawBuffer.begin(); // итератор для прохода по списку do { Circle c = *it++; painter.setPen(c.color); painter.drawEllipse(c.p, c.r, c.r); } while (it!= DrawBuffer.end()); // рисуем окружности, пока список не закончится } /* рисуем текущую окружность: окружность изменяется в зависимости от движения мыши, поэтому мы ее будем рисовать отдельно в объекте pixmap и накладывать этот объект на окно, тогда не нужно стирать предыдущий вид этой окружности */ if (drawMode) // если прижата левая кнопка мыши { // определяем размеры области рисования: int w = width(); int h = height()-(ui->statusBar->height()); QPixmap pixmap(w, h); // создаем область, в которой мы будем рисовать текущую окружность pixmap.fill(Qt::transparent); // делаем фон прозрачным QPainter pntPixmap(&pixmap); // создаем объект для рисования pntPixmap.setRenderHint(QPainter::Antialiasing); // сглаживание pntPixmap.setPen(color); /* устанавливаем цвет пера (который мы можем выбрать с помощью специального окна) */ pntPixmap.drawEllipse(p[0],r,r); // рисуем текущую окружность в области pixmap painter.drawPixmap(0, 0, w, h, pixmap); // накладываем текущую окружность на ранее нарисованные } } // Слот для кнопки «Выбор цвета»: void MainWindow::showDialog() { color = QColorDialog::getColor(); // выводим на экран специальное окно и считываем цвет } // Слот для кнопки «Отменить»: void MainWindow::Annul() { DrawBuffer.removeLast(); // удаляем последний элемент из списка update(); } // Слот для кнопки «Очистить»: void MainWindow::Clear() { DrawBuffer.clear(); // Очищаем список update(); } // Слот для кнопки «Открыть» void MainWindow::open() { QFile file("picture.dat"); file.open(QIODevice::ReadOnly); // Создаем файл для чтения QDataStream in(&file); // Создаем поток на основе файла in>>DrawBuffer; // считываем список окружностей из потока update(); // отображаем окружности в окне } // Слот для кнопки «Сохранить» void MainWindow::save() { QFile file("picture.dat"); // создаем файл для записи file.open(QIODevice::WriteOnly); QDataStream out(&file); // создаем поток на основе файла: out << DrawBuffer; // записываем окружности в файл file.close(); // обязательно закрываемфайл }
Запустите программу, нарисуйте несколько окружностей разного цвета и проверьте работу команд меню.
Задания для самостоятельного выполнения Создайте приложение, которое позволяет рисовать отрезки прямых линий с помощью мыши. Создаваемая линия должна быть видима в процессе построения. Цвет линий должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое позволяет рисовать закрашенные прямоугольники с помощью мыши. Создаваемый прямоугольник должен быть видим в процессе построения. Цвет прямоугольников должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое позволяет рисовать закрашенные треугольники, задаваемые тремя щелчками мыши в вершинах. Цвет треугольников должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое позволяет рисовать закрашенные круги с помощью мыши. Создаваемая окружность должна быть видима в процессе построения. Цвет окружностей должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое рисует закрашенные пятиконечные звезды (вписанную в воображаемую окружность; центр окружности и одна точка на окружности задаются щелчками мыши). Цвет каждой звездочки должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое рисует закрашенные квадраты с помощью мыши так, что мышь проходит по диагонали квадрата от одной вершины к другой. Квадрат должен быть виден в процессе построения. Цвет линий должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое рисует дуги с помощью мыши так, что мышь определяет начало и конец дуги. Дуга должен быть видима в процессе построения. Цвет линий должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое рисует правильные треугольники с помощью мыши так, что указатель мыши находится в одной из вершин треугольника. Треугольник должен быть видим в процессе построения и может поворачиваться. Цвет линий должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. При отпускании мыши треугольник закрашивается. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте приложение, которое рисует правильные 8-конечные звездочки с помощью мыши так, что указатель мыши находится в одной из вершин звездочки. Звездочка должна быть видима в процессе построения и может поворачиваться. При отпускании мыши звездочка закрашивается. Цвет линий должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте однодокументное приложение, которое рисует правильные 5-конечные звездочки с помощью мыши так, что указатель мыши находится в одной из вершин звездочки. Звездочка должна быть видима в процессе построения и может поворачиваться. Цвет линий должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла. Создайте однодокументное приложение, которое рисует правильные шестиугольники с помощью мыши так, что указатель мыши находится в одной из вершин шестиугольника. Шестиугольник должен быть видим в процессе построения и может поворачиваться. Цвет линий должен определяться с помощью немодального диалогового окна с наборными счетчиками (Spin), которые позволяют установить интенсивности красной, зеленой и синей составляющих цвета. Предоставьте возможность сохранять изображение в файле и считывать его из файла..
Лабораторная работа № 8 |