Projeto: gerenciador de tela polimórfico usando a hierarquia Forma. Desenvolva um pacote gráfico básico. Use a hierarquia Forma implementada no Exercício 21.13. Limite-se a formas bidimensionais, como quadrados, retângulos, triângulos e círculos. Interaja com o usuário. Permita que o usuário especifique a posição, o tamanho, a forma e os caracteres de preenchimento a serem usados no desenho de cada forma. O usuário pode especificar mais de uma da mesma forma. Ao criar cada forma, coloque um ponteiro Forma * para cada novo objeto Forma em um array. Cada classe Forma agora deverá ter sua própria função-membro desenhar. Escreva um gerenciador de tela polimórfico que atravesse o array, enviando mensagens desenhar a cada objeto no array para formar uma imagem na tela. Redesenhe a imagem da tela toda vez que o usuário especificar uma forma adicional.

Passo 1

Vamos criar um aplicativo orientado a menus que permite ao usuário desenhar uma das quatro formas em uma matriz.

Vamos começar definindo as classes de forma.

Classe base de forma

A classe é uma classe abstrata pura que contém uma função usada para desenhar uma certa forma em uma matriz de um tamanho específico.

#ifndef H_SHAPE_H

#define H_SHAPE_H

#include

#include

using namespace std;

class Shape {

public:

virtual void draw(char**, int, int) const = 0;

};

#endif

Forma bidimensional

Essa classe conterá as propriedades de caractere de posição e preenchimento.

Declaração de classe:

#ifndef H_TWODIMENSIONALSHAPE_H

#define H_TWODIMENSIONALSHAPE_H

#include "Shape.h"

class TwoDimensionalShape : public Shape {

public:

TwoDimensionalShape(int xPos, int yPos,

char fillCharacter);

int getXPos() const;

void setXPos(int xPos);

int getYPos() const;

void setYPos(int yPos);

char getFillCharacter() const;

void setFillCharacter(char fillCharacter);

protected:

int xPos;

int yPos;

char fillCharacter;

};

#endif

Implementação da classe:

#include "TwoDimensionalShape.h"

TwoDimensionalShape::TwoDimensionalShape(

int xPos, int yPos, char fillCharacter)

: xPos(xPos), yPos(yPos),

fillCharacter(fillCharacter) {}

int TwoDimensionalShape::getXPos() const {

return xPos;

}

void TwoDimensionalShape::setXPos(int xPos) {

TwoDimensionalShape::xPos = xPos;

}

int TwoDimensionalShape::getYPos() const {

return yPos;

}

void TwoDimensionalShape::setYPos(int yPos) {

TwoDimensionalShape::yPos = yPos;

}

char TwoDimensionalShape::getFillCharacter() const {

return fillCharacter;

}

void TwoDimensionalShape::setFillCharacter(

char fillCharacter) {

TwoDimensionalShape::fillCharacter = fillCharacter;

}

Passo 2

Círculo

Esta classe contém o comprimento do raio do círculo, bem como sua própria implementação da função draw().

#ifndef H_CIRCLE_H

#define H_CIRCLE_H

#include "TwoDimensionalShape.h"

class Circle : public TwoDimensionalShape {

public:

explicit Circle(int xPos, int yPos, char fill,

double radius);

void draw(char** arr, int row, int col) const;

private:

double radius;

};

#endif

Usamos a fórmula do círculo para desenhar o círculo. Iremos percorrer as coordenadas da matriz, verificando se uma coordenada está dentro ou na borda do círculo.

Fórmula do círculo:

x - h 2 + y - k 2 = r 2

x - h 2 + y - k 2 = r 2

#include "Circle.h"

Circle::Circle(int xPos, int yPos,

char fill, double radius)

: TwoDimensionalShape(xPos, yPos, fill),

radius(radius) {}

void Circle::draw(char** arr, int row, int col) const {

for (int i = 0; i

for (int j = 0; j

if (pow(i - yPos, 2.0) + pow(j - xPos, 2.0)

arr[i][j] = fillCharacter;

}

Retângulo

Declaração de classe:

#ifndef H_RECTANGLE_H

#define H_RECTANGLE_H

#include "TwoDimensionalShape.h"

class Rectangle : public TwoDimensionalShape {

public:

Rectangle(int xPos, int yPos, char fill,

double a, double b);

void draw(char** arr, int row, int col) const;

protected:

double a;

double b;

};

#endif

Para desenhar retângulos, vamos iterar o comprimento e a largura do retângulo, definindo as coordenadas para o caractere de preenchimento (observe que estamos definindo o canto superior esquerdo do retângulo como nosso ponto de partida):

Implementação da classe:

#include "Rectangle.h"

Rectangle::Rectangle(int xPos, int yPos,

char fill, double a, double b)

: TwoDimensionalShape(xPos, yPos, fill), a(a), b(b) {}

void Rectangle::draw(char **arr, int row, int col) const {

for (int i = 0; i

for (int j = 0; j

if (yPos + i

arr[yPos + i][xPos + j] = fillCharacter;

else

{

cout

exit(1);

}

}

Passo 3

Praça

Essa classe herdará todos os comportamentos e propriedades necessários da classe Rectangle.

Declaração de classe:

#ifndef H_SQUARE_H

#define H_SQUARE_H

#include "Rectangle.h"

class Square : public Rectangle {

public:

explicit Square(int xPos, int yPos, char fill,

double a);

};

#endif

#include "Square.h"

Square::Square(int xPos, int yPos,

char fill, double a)

: Rectangle(xPos, yPos, fill, a, a) {}

Triângulo

Declaração de classe:

#ifndef H_TRIANGLE_H

#define H_TRIANGLE_H

#include "TwoDimensionalShape.h"

class Triangle : public TwoDimensionalShape {

public:

Triangle(int xPos, int yPos, char fill,

double a);

void draw(char** arr, int row, int col) const;

protected:

double a;

};

#endif

Para desenhar triângulos, vamos iterar pelas linhas para o comprimento do lado, incrementando o comprimento do tamanho da coluna a cada iteração.

Implementação da classe:

#include "Triangle.h"

Triangle::Triangle(int xPos, int yPos,

char fill, double a)

: TwoDimensionalShape(xPos, yPos, fill),

a(a) {}

void Triangle::draw(char **arr, int row, int col) const {

for (int i = 0; i

for (int j = 0; j

if (yPos + i

arr[yPos + i][xPos + j] = fillCharacter;

else

{

cout

exit(1);

}

}

Passo 4

Gerenciador de tela

Esta classe é uma interface para o usuário, também usada como classe de driver.

Funcionalidades:

clear() aloca nova memória para a matriz arr (desaloca antes, se necessário)

draw() desenha formas atuais dentro do vetor de formas na matriz arr

display() gera a matriz (os "gráficos")

função de driver run()

Declaração de classe:

#ifndef H_SCREENMANAGER_H

#define H_SCREENMANAGER_H

#include

#include "Shape.h"

class ScreenManager {

public:

ScreenManager();

void clear();

void draw();

void display();

bool run();

private:

char** arr;

vector shapes;

const int ROW = 30;

const int COL = 30;

};

#endif

Agora, vamos implementar a classe.

Em primeiro lugar, o cabeçalho do arquivo junto com a implementação do construtor:

#include

#include "ScreenManager.h"

#include "Circle.h"

#include "Triangle.h"

#include "Square.h"

using namespace std;

ScreenManager::ScreenManager() {

clear();

}

...

A implementação da função clear():

void ScreenManager::clear() {

if (arr != nullptr)

{

for (int i = 0; i

delete[] arr[i];

delete[] arr;

}

arr = new char*[ROW];

for (int i = 0; i

arr[i] = new char[COL]();

}

Para exibir a matriz:

Limpe a matriz (caso já haja algo escrito nela)

Escreva formas atuais

Saída

void ScreenManager::display() {

clear();

for (Shape* shape : shapes)

shape->draw(arr, ROW, COL);

for (int i = 0; i

{

for (int j = 0; j

cout

cout

}

}

A implementação da função draw().

Em primeiro lugar, solicite ao usuário informações básicas:

void ScreenManager::draw() {

cout

> ";

int shape, xPos, yPos;

char fill;

cin >> shape;

cout > ";

cin >> xPos >> yPos;

cout > ";

cin >> fill;

cin.ignore();

...

}

Com base na forma inserida, solicite informações adicionais ao usuário e, por fim, insira uma forma correspondente no vetor:

void ScreenManager::draw() {

...

if (shape == 1)

{

double radius;

cout > ";

cin >> radius;

shapes.push_back(

new Circle(xPos, yPos, fill, radius)

);

}

else if (shape == 2)

{

double a, b;

cout > ";

cin >> a >> b;

shapes.push_back(

new Rectangle(xPos, yPos, fill, a, b)

);

}

else if (shape == 3 || shape == 4)

{

double a;

cout > ";

cin >> a;

if (shape == 3)

shapes.push_back(

new Square(xPos, yPos, fill, a)

);

else

shapes.push_back(

new Triangle(xPos, yPos, fill, a)

);

}

else

cout

}

Por fim, a função do driver que exibe as opções básicas do menu e solicita que o usuário insira uma opção:

bool ScreenManager::run() {

cout

> ";

int choice;

cin >> choice;

if (choice == 1)

draw();

else if (choice == 2)

display();

else if (choice == 3)

shapes.clear();

else if (choice == 0)

return false;

else

cout

return true;

}

Observação: o valor de retorno é usado para determinar se o aplicativo deve terminar.

O main:

#include "ScreenManager.h"

using namespace std;

int main()

{

ScreenManager screenManager;

while(screenManager.run());

}

Resposta

Ver todo o desenvolvimento.