Тема: «Области отсечения»

Пример 1: программа, которая рисует 6-угольник, цвет которого можно изменять с помощью немодального диалогового окна с на­бор­ными счетчиками (Spin). Диалоговое окно появляется при нажатии кнопки «Диалог».

Создайте проект на базе главного окна.

Добавьте дочернее диалоговое окно, описы­ваемое классом Dialog (выберите в меню Файл | Новый файл или проект..., в появившемся диа­логовом окне выберите Qt | Класс формы Qt De­signer).

Спроектируйте окно как показано на рисун­ке, добавив элемент spinBox.

В файл main.cpp добавьте подчеркнутую строку:

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

 

MainWindow w;

w.move(400, 250); // перемещает окно к центру экрана

w.show();

return a.exec();

}

В файлe dialog.h в описание класса добавьте подчеркнутые строки:

#ifndef DIALOG_H

#define DIALOG_H

#include <QDialog>

namespace Ui {

class Dialog;

}

class MainWindow; // С помощью этого класса объявим указатель на родительское окно

class Dialog: public QDialog

{

Q_OBJECT

public:

// Измените тип указателя на MainWindow

explicit Dialog(MainWindow *parent = 0);

 

~Dialog();

  MainWindow* Parent; /* С помощью этого указателя диалоговое окно будет переда­вать новое значение цвета главному окну */

 // объявление слота, который будет передавать новое значение цвета главному окну:

public slots:

void setN(int);

private:

Ui::Dialog *ui;

};

#endif // DIALOG_H

В файл dialog.cpp добавьте подчеркнутые строки:

 

#include "dialog.h"

#include "ui_dialog.h"

#include "mainwindow.h"

 // обеспечивает возможность использования класса MainWindow

Dialog::Dialog(MainWindow *parent):

QDialog(parent),

ui(new Ui::Dialog)

{

ui->setupUi(this);

ui->spinBox->setRange(0, 255);

 // Задаем диапазон изменнения значений наборного счетчика

ui->spinBox->setSingleStep(5);  

// при щелчке по стрелочке значение счетчика будет изменяться на 5

Parent = parent;  

// Указатель, объявленный в классе, становится равным значению локального указателя

ui->spinBox->setValue(Parent->n);

 /* Устанавливаем начальное значение счетчика так, чтобы оно было равно начальному значению цвета, установленного в конструкторе главного окна */

connect(ui->spinBox, SIGNAL(valueChanged(int)),
       this, SLOT(setN(int)));
 /* связываем сигнал об изменении значения счетчика со слотом, который передает новое значение цвета главному окну */

}

Dialog::~Dialog()

{

delete ui;

}

 

void Dialog::setN(int n) /* значение n автоматически передается слоту от наборного счетчика с помощью сигнала valueChanged(int)

{

Parent->n = n;

// передаем значение цвета переменной, объявленной в классе гланого окна

Parent->update(); // посылаем сигнал «перерисовать окно»

}

Добавьте в файл mainwindow.h подчеркнутые строки:

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include <QMainWindow>

#include "dialog.h"  // Обеспечивает возможность использования класса Dialog

#include <QtGui> // обеспечивает возможность использования графических функций

namespace Ui {

class MainWindow;

}

class MainWindow: public QMainWindow

{

Q_OBJECT

public:

explicit MainWindow(QWidget *parent = 0);

~MainWindow();

void paintEvent(QPaintEvent *);

 // функция, которая автоматически вызывается при перерисовывании окна

 Dialog* dlg; // объект, описывающий диалоговое окно

int n; // значение яркости цвета

private:

Ui::MainWindow *ui;

private slots:

void on_actionDialog_triggered();

};

#endif // MAINWINDOW_H

В режиме проектирования формы с помощью редактора действий добавьте действие actionDialog с текстом «Диалог» (это будет командой меню, которая вы­зы­вает вспомогатель­ное диалоговое окно).

В файл mainwindow.cpp добавьте код, показанный ниже:

#include "mainwindow.h"

#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent):

QMainWindow(parent),

ui(new Ui::MainWindow)

{

ui->setupUi(this);

n = 100;  // начальное значение цвета

dlg = new Dialog(this);  // создаем объект класса Dialog

ui->menuBar->addAction(ui->actionDialog);

 // В меню создаем кнопку, соответствующую команде «Диалог» (без выпадающего меню)

}

MainWindow::~MainWindow()

{

delete ui;

}

 // В режиме проектирования формы добавьте слот для действия actionDialg:

void MainWindow::on_actionDialog_triggered()

{

dlg->move(400+width(), 250);

 // размещаем диалоговое окно на правой границе главного окна

dlg->show(); // рисуем окно на экране

dlg->activateWindow(); // делаем диалоговое окно активным

}

// Описываем, что нужно нарисовать в окне

void MainWindow::paintEvent(QPaintEvent *)

{

QPainter painter(this);// Объект для рисования

QString str = QString::number(n);/* Строка, с помощью которой на экране будет отоб­ражаться текущая яркость цвета */

painter.drawText(20,70, str);// Отображаем на экране значение яркости цвета

QBrush brush(QColor(n,0,0));/* объявляем кисть, число n в данном случае будет опре­елять яркость красного цвета */

painter.setBrush(brush);// побключаем кисть

QPolygonF polygon; // Объявляем многоугольник

qreal r = 100; // радиус окружности, в которую будет вписан многоугольник

qreal x0 = 200, y0 = 150; // центр окружности

qreal dfi = M_PI / 3; // угол между вершинами 6-угольника

for (int i = 0; i< 6; ++i) // рисуем 6-угольник

{

   qreal fi = dfi * i; // угол, соответствующий очередной вершине

// определяем координаты вершины

   qreal x = x0 + r*cos(fi);

   qreal y = y0 + r*sin(fi);

   polygon << QPointF(x,y);// добавляем координаты вершины к полигону

}

painter.drawPolygon(polygon);// рисуем многоугольник (6-угольник)

}


Пример 2: программа, которая расчерчивает окно правильными 6-угольниками («пчелиными сотами»); размер шестиугольника — 1 / 5 меньшей стороны окна (но не меньше 2); при щелчке мышью внутри шестиугольника, он закрашивается цветом, выбранным с помощью специального окна для выбора цвета.

Создайте приложение на базе главного окна. В файле mainwindow.h добавьте объявления как показано ниже.

#ifndef MAINWINDOW_H

#define MAINWINDOW_H

#include <QMainWindow>

#define maxR 500 // максимальное количество строк

#define maxC 700 // максимальное количество столбцов

namespace Ui {

class MainWindow;

}

class MainWindow: public QMainWindow

{

Q_OBJECT

public:

explicit MainWindow(QWidget *parent = 0);

~MainWindow();

void paintEvent(QPaintEvent *);

// автоматически вызывается при перерисовке окна

void createMatrices();

// функция, размещающая в памяти матрицы полигонов и регионов

void createNet(); // формирование сетки в рабочей области окна

void createPolygon(int, int); // создание одной ячейки с заданными номерами

void mousePressEvent(QMouseEvent *);

 // автоматически вызыватся при щелчке мышью

void resizeEvent(QResizeEvent *);

// автоматически вызывается при создании окни и при изменении его размеров

QPolygon** Polygon; // Указатель на матрицу полигонов

QRegion** Region; // Указатель на матрицу областей

QColor Color[maxR][maxC]; /* матрица для хранения цвета в каждой ячейке, она должна быть максимальных размеров, поскольку мы заранее не знаем размеры окна */

int previousRows, rows, columns; /* количество строк для предыдущего состояния окна, текущее количество строк, количество столбцов */

double w, h; // размеры рабочего поля

double size, x0, y0, r; // размер одной ячейки, центр и радиус окружности, в которую вписан многоугольник

QBrush brush; // кисть

private:

Ui::MainWindow *ui;

private slots:

void on_actionOpen_triggered();

void on_actionSave_triggered();

};

#endif // MAINWINDOW_H

В файле mainwindow.cpp напишите код, показанный ниже:

#include "mainwindow.h"

#include "ui_mainwindow.h"

#include <QtGui>

MainWindow::MainWindow(QWidget *parent):

QMainWindow(parent),

ui(new Ui::MainWindow)

{

ui->setupUi(this);

for (int i = 0; i < maxR; ++i)

     for (int j = 0; j<maxC; ++j)

         Color[i][j] = QColor(0, 100, 100);

// Заполняем матрицу начальным цветом

previousRows = rows = columns = 0; // начальные размеры сетки

}

MainWindow::~MainWindow()

{

delete ui;

}

 // Виртуальная функция, которая вызывается при изменении размеров окна

void MainWindow::resizeEvent(QResizeEvent *)

{

w = width(); // ширина рабочего поля

y0 = centralWidget()->y(); // Верхняя граница клиентской области

h = height() - y0; // высота рабочего поля

size = qMin(w, h) / 5;

 // размер одной ячейки (расстояние между двумя противоположными вершинами)

if (size<2) size = 2;

// размер не может оказаться равным нулю, чтобы не произошло деление на ноль

// qDebug() << "size = " << size;

r = size/2; // радиус окружности, в которую вписана ячейка

x0 = r * sqrt(3)/2;

// расстояние от левой границы окна до центра первого 6-угольника (красная линия на рисунке)

/* длина стороны правильного 6-угольника = r, а расстояние между ценрами ячеек (вертикаль­ный катет светлого треугольника) = r+r/2 = 3*r / 2 */

rows = int(2*h/(3*r)) +2; // количество полных рядов равно частному от деления высоты рабочей области на расстояние между центрами ячеек; к этому количеству нужно добавить 2 — неполные ряды на верхней и нижней границах окна

if (rows>maxR) rows = maxR;

// но количество рядов не может превышать задданый максимум

 // qDebug() << "rows = " << rows;

columns = int(w / (r*sqrt(3)))+2;

/* расстояние между центрами окружностей по горизонтали = (r*sqrt(3)/2) * 2 = r*sqrt(3), количество столбцов равно частному от деления ширины окна на расстояние между рядами + 2 неполных ряда на левой и правой границе */

if (columns>maxC) columns = maxC;

// количество столбцов неможет превышать заданный максимум

 // qDebug() << "columns = " <<columns;

createMatrices(); /* при каждом изменении размеров окна создаем новые матрицы ячеек и соответствующих им областей */

createNet(); // заполняем матрицы данными

}

 

 

void MainWindow::paintEvent(QPaintEvent *)

{

QPainter painter(this);

 // рисуем многоугольники цветом, который записан в матрице цветов:

for (int i = 0; i < rows; ++i)

     for (int j = 0; j < columns; ++j)

   {

       painter.setBrush(QBrush(Color[i][j]));

       painter.drawPolygon(Polygon[i][j]);

   }

}

 // размещаем матрицы в памяти:

void MainWindow::createMatrices()

{

if (previousRows)

 // удаляем предидущие матрицы из памяти, если они ненулевого размера

{

   for (int i = 0; i < previousRows; ++i) // освобождаем память по строкам

   {

       delete[] Polygon[i]; // освобождаем память, выделенную для данных

       delete[] Region[i];

   }

   delete Polygon;  // удаляем массивы указателей

   delete Region;

}

previousRows = rows; // запоминаем текущее количество строк

// создаем массивы указателей на строки данных:

Polygon = new QPolygon* [rows];

Region = new QRegion* [rows];

// захватываем память для строк данных:

for (int i = 0; i < rows; ++i)

{

   Polygon[i] = new QPolygon[columns]; // для координат 6-угольников

   Region[i] = new QRegion[columns]; // для областей

}

}

void MainWindow::createNet() // заполняем матрицы данными

{

double dx = r*sqrt(3); // расстояние между центрами ячеек по горизонтали

double dy = r*3 / 2; // расстояние между центрами ячеек по вертикали

for (int i = 0; i <rows; ++i) // проходим по строкам

{

     for (int j = 0; j<columns; ++j) // проходим по одной строке

     {

         createPolygon(i, j);

// создаем ячейку в i-ой строке и в j — м столбце (вызываем функцию)

         x0+=dx; // переходим в следующий столбец

     }

     y0 += dy; // переходим к следующей строке

     if (i % 2 == 0) x0 = 0;

// начало следующего ряда, если текущая строка - четная

     else x0 = r*sqrt(3)/2; // если текущая строка - нечетная

}

}

void MainWindow::createPolygon(int i, int j) // определяем координаты одной ячейки

{

double x, y; // координаты вершин многоугольника

double da = M_PI/3; // угол между вершинами

double angle = da/2; // начальный угол

Polygon[i][j].clear(); // очищаем контейнер

for (int k = 0; k<6; ++k) // определяем вершины 6-угольника

{

       // вычисляем координаты очередной вершины как точки на окружности

   x = x0 + r*cos(angle);

   y = y0 + r*sin(angle);

   Polygon[i][j] << QPoint(x,y);

// добавляем координаты очередной точки к полигону

   angle += da; // переходим к следующей вершине

}

Region[i][j] = QRegion(Polygon[i][j]);

// когда 6-угольник определен, создаем соответствующую область

}

 // Слот, обрабатывающий щелчки мышью:

void MainWindow::mousePressEvent(QMouseEvent * event)

{

QPoint point = event->pos(); // координаты курсора мыши

 // проверяем, в какой регион (в какой 6-угольник) попадает курсор мыши

  for (int i = 0; i<rows; ++i) // проходим по строкам матрицы

   for(int j = 0; j<columns; ++j) // по столбцам

       if (Region[i][j].contains(point)) // если курсор попадает в область

       {

           Color[i][j] = QColorDialog::getColor(); // выбираем цвет

           brush = QBrush(Color[i][j]); // создаем кисть

           update(Region[i][j]); // перерисовываем 6-угольник

           goto exit; // выходим из циклов

       }

exit:;

}

 // слот для команды Save:

void MainWindow::on_actionSave_triggered()

{

 // вызываем окно для выбора имени файла:

QString fileName = QFileDialog::getSaveFileName(this, "Сохранить файл", QString(),

QString("Файлы данных (*.dat);;Все файлы (*.*)"));

QFile rezFile; // Результирующий файл

if (!fileName.isEmpty()) // Если имя файла задано

{

      rezFile.setFileName(fileName);

// присваиваем физическое имя результирующему файлу

      rezFile.open(QIODevice::WriteOnly);

// открываем сохраняемый файл

     QDataStream out(&rezFile);

/* создаем поток, связанный с файлом (запись файла обычно выполняется с помощью потока) */

 // записываем матрицу цветов в файл:        

for (int i = 0; i < maxR; ++i)

          for (int j = 0; j<maxC; ++j)

              out <<Color[i][j]; // записываем цвет ячейки с номерами i и j

      rezFile.close();

}

}

 

 // Слот, обрабатывающий команду Open:

void MainWindow::on_actionOpen_triggered()

{

 //   вызываем окно для выбора имени файла:   

QString fileName = QFileDialog::getOpenFileName(

this,  //  указатель на родительское окно

"Открыть файл", // заголовок окна

QString(),  // выбор начинается с текущего каталога

QString("Файлы с данными (*.dat);;Все файлы (*.*)"));

// фильтры для списка файлов

if (! fileName.isEmpty())    // если имя файла выбрано

{

    QFile file;

    file.setFileName(fileName);

// связываем объект file с физическим файлом

    file.open(QIODevice::ReadOnly);

    QDataStream in(&file); // поток для чтения данных

       for (int i = 0; i < maxR; ++i)

           for (int j = 0; j<maxC; ++j)

               in >> Color[i][j]; // считываем цвет ячейки

       file.close();

   }

 /* Главное окно приложения автоматически перерисовывается при закрытии окна для выбора файла */

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: