Boa noite pessoal!
É o seguinte estou desenvolvendo um pequeno programa de desenho em java que se assemelha com o autoCAD usando Swing.Como faço para melhorar a codificação de programa pois acho que tem muito código duplicado e variáveis repetidas, e gostaria de melhorar o código antes de prosseguir com o programa.Como reduzir linhas de código nesse programa, pois esse código está difícil de dar manutenção
Abaixo as classes do projeto
Desenho.java
package miniCad
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class Desenho extends JPanel implements MouseMotionListener, MouseListener, ActionListener, KeyListener {
JPanel comandos;
JPanel menus;
JPanel areaDesenho;
JTextField txtBarraComandos;
final ArrayList<Point> pontos = new ArrayList<>();
//private final ArrayList<Linhas> linhas = new ArrayList<>();
final ArrayList<Boolean> linhasVisiveis = new ArrayList<>();
final ArrayList<Circulo> circulos = new ArrayList<>();
//int x1, y1, x2, y2;
// boolean pressionado = false;
JLabel coordenadas;
JLabel textoComandos;
JMenuBar barraMenu;
JMenu menuArquivo;
JMenu menuDesenhar;
JMenuItem itemArquivoSair;
JMenuItem itemDesenharLinha;
JMenuItem itemDesenharCirculo;
boolean clickInicial = true;
boolean clickFinal = false;
// int i=0;
boolean teclaL = false;
boolean linhaAtivada = false;
boolean click = false;
int indiceLinha = -1; //inicia com -1 pois quando incrementada dará indice vetor zero,depois um
boolean teclaC = false;
boolean circuloAtivado = false;
int xcentro, ycentro, xcontorno, ycontorno;
boolean proximoPonto = false;
int x1, y1, x2, y2; // variáveis marcador de linha
// variáveis distancia e angulo marcador de linha
double anguloGrausLinha=0;
double tamanhoLinha=0;
boolean marcadorLinha=false; // controla a exibição do marcador da linha
int localizacaoXMarcadorLinha=0;
int localizacaoYMarcadorLinha=0;
public Desenho() {
editarLayout();
editarMenu();
addMouseListener(this);
addMouseMotionListener(this);
}
public void editarLayout() {
/*Criando e configurando Layout dos paineis */
comandos = new JPanel();
menus = new JPanel();
setBackground(Color.BLACK);
setLayout(new BorderLayout());
menus.setLayout(new BorderLayout());
comandos.setLayout(new GridLayout(1, 3));
/*criando e adicionando componentes ao painel comandos*/
coordenadas = new JLabel("Coordenadas");
coordenadas.setForeground(Color.RED);
textoComandos = new JLabel("nenhum comando encontrado");
comandos.add(coordenadas);
comandos.add(textoComandos);
txtBarraComandos = new JTextField(20);
comandos.add(coordenadas);
comandos.add(textoComandos);
comandos.add(txtBarraComandos);
/*adicionando painel comandos ao painel principal*/
add(comandos, BorderLayout.SOUTH);
/*adicionando eventos keylistener ao campo de texto txtBarraComandos,quando
temos um txt field em uma janela acho que devemos adicionar um keylistener ao campo
de texto e não a janela,assim as teclas disparando um keyevent quando apertamos um tecla
no campo de texto*/
txtBarraComandos.addKeyListener(this);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// PINTANDO QUADRO DE DESENHO 1150PX POR 550 PX
g.setColor(Color.BLACK);
g.drawRect(20, 70, 1150, 550);
//PINTANDO LINHAS QUADRO DE DESENHO
g.setColor(new Color(50, 50, 50)); //cinza
for (int i = 0; i < 25; i++) { // linhas verticais 50 PIXELS linhas de 550 pixels comprimento
g.drawLine(50 + i * 50, 70, 50 + i * 50, 620); // coordenadas JPanel
}
for (int i = 0; i < 13; i++) {// linhas horizontais 50 PIXELS linhas de 1150 pixels comprimento
g.drawLine(50, 70 + i * 50, 1200, 70 + i * 50); // coordenadas JPanel
}
// DESENHANDO SISTEMA DE COORDENADAS
g.setColor(Color.YELLOW);
g.drawLine(50, 620, 100, 620); // eixo x // coordenadas JPanel
g.drawString("x", 110, 625);
g.drawLine(50, 620, 50, 570); // eixo y // coordenadas JPanel
g.drawString("y", 50, 560);
//DESENHANDO LINHAS
for (int i = 1; i < pontos.size(); i++) {
if (linhasVisiveis.get(i - 1)) { // se a linha for configurada como visível desenha linha
g.setColor(Color.WHITE);
int x1 = pontos.get(i - 1).x;
int y1 = pontos.get(i - 1).y;
int x2 = pontos.get(i).x;
int y2 = pontos.get(i).y;
g.drawLine(x1, y1, x2, y2);
}
}
// DESENHANDO CIRCULOS
if (clickFinal) {
g.setColor(Color.RED);
g.drawRect(xcentro - 2, ycentro - 2, 5, 5);
g.drawLine(xcentro - 5, ycentro, xcentro + 5, ycentro);
g.drawLine(xcentro, ycentro - 5, xcentro, ycentro + 5);
for (int i = 0; i < circulos.size(); i++) {
g.setColor(Color.RED);
int xce = circulos.get(i).xcentro;
int yce = circulos.get(i).ycentro;
int xco = circulos.get(i).xcontorno;
int yco = circulos.get(i).ycontorno;
int diametro = circulos.get(i).diametro;
int x = circulos.get(i).x;
int y = circulos.get(i).y;
g.drawRect(xce - 2, yce - 2, 5, 5);
g.drawLine(xce - 5, yce, xce + 5, yce);
g.drawLine(xce, yce - 5, xce, yce + 5);
g.setColor(Color.GREEN);
g.drawLine(xce, yce, xco, yco);
g.setColor(Color.WHITE);
g.drawOval(x, y, diametro, diametro);
g.setColor(Color.BLUE);
g.drawRect(x, y, diametro, diametro);
}
} else {
for (int i = 0; i < circulos.size(); i++) {
g.setColor(Color.RED);
int xce = circulos.get(i).xcentro;
int yce = circulos.get(i).ycentro;
int xco = circulos.get(i).xcontorno;
int yco = circulos.get(i).ycontorno;
int diametro = circulos.get(i).diametro;
int x = circulos.get(i).x;
int y = circulos.get(i).y;
g.drawRect(xce - 2, yce - 2, 5, 5);
g.drawLine(xce - 5, yce, xce + 5, yce);
g.drawLine(xce, yce - 5, xce, yce + 5);
g.setColor(Color.GREEN);
g.drawLine(xce, yce, xco, yco);
g.setColor(Color.WHITE);
g.drawOval(x, y, diametro, diametro);
g.setColor(Color.BLUE);
g.drawRect(x, y, diametro, diametro);
}
}
// pinta marcador linha
if(linhaAtivada && marcadorLinha==true){
/*verifica se o último ponto final do marcador linha(x2,y2) está fora da área de desenho
se estiver pinta de laranjado indicando que não podemos desenhar uma linha
naquela area
*/
if((this.x2>=50)&&(this.x2<=1200)&&(this.y2>=70)&&(this.y2<=620)){
g.setColor(new Color(128,255,128));// verde claro
}else{
g.setColor(new Color(255,128,128)); // vermelho claro
}
g.drawLine(this.x1, this.y1, this.x2, this.y2);
g.drawString(tamanhoLinha+"",localizacaoXMarcadorLinha,localizacaoYMarcadorLinha);
g.drawString("<"+anguloGrausLinha+"º",localizacaoXMarcadorLinha,localizacaoYMarcadorLinha+15);
}
//}
}
public int[] converteCoordenadas(int x, int y) {
x -= 20;
y = y + 480 + (y - 70) * (-2);
int[] coordenadas = {x, y};
return coordenadas;
}
public void editarMenu() {
//criando barra menu e adicionando ao painel
barraMenu = new JMenuBar();
/*para adicionar uma barra de menus a um Painel usamos o método add
especificando NORTH para o border Layout*/
add(barraMenu, BorderLayout.NORTH);
//criando menus e adicionando a barra de menus
menuArquivo = new JMenu("Arquivo");
barraMenu.add(menuArquivo);
menuDesenhar = new JMenu("Desenhar");
barraMenu.add(menuDesenhar);
// criando itens do menu de Arquivo e adicionando ao menu e adicionando evento
itemArquivoSair = new JMenuItem("Sair");
menuArquivo.add(itemArquivoSair);
// criando itens do menu Desenhar adicionando eventos e adicionando ao menu
itemDesenharLinha = new JMenuItem("Linha");
itemDesenharCirculo = new JMenuItem("Círculo");
menuDesenhar.add(itemDesenharLinha);
menuDesenhar.add(itemDesenharCirculo);
//TRATANDO EVENTOS DOS ITENS DE MENU
itemArquivoSair.addActionListener(this);
itemDesenharLinha.addActionListener(this);
itemDesenharCirculo.addActionListener(this);
}
@Override
public void mouseDragged(MouseEvent e) {
// reajustando cordenadas do jpanel e convertendo para a grade de coordenadas
int x = e.getX(); // panel coordenada x JPanel
int y = e.getY(); // panel coordenada y JPanel
// Painel 1150 por 550
// Panel canto inferior esquerdo (50,620)
// Panel canto superior esquerdo(50,70)
// Panel canto superior direito (1200,70)
// Panel canto inferior direito(1200,620)
// reajustando coordenadas do panel para o sistema de coordenadas x e y
x = x - 50;
//y=70+480; //550 se y=70
//y=71+478; // 549 se y=71
//y=72+476; // 548 se y=72
y = y + 480 + (y - 70) * (-2); // lei geral
// só exibe as coordenadas na área de desenho
if ((x >= 0) && (x <= 1150) && (y >= 0) && (y <= 550)) {
coordenadas.setText("[x:" + x + "]" + "[y:" + y + "]");
} else {
coordenadas.setText("Fora da área de desenho");
}
}
@Override
public void mouseMoved(MouseEvent e) {
// reajustando cordenadas do jpanel e
convertendo para a grade de coordenadas
int x = e.getX(); // panel coordenada x
int y = e.getY(); // panel coordenada y
// Painel 1150 por 550
// Panel canto inferior esquerdo (50,620)
// Panel canto superior esquerdo(50,70)
// Panel canto superior direito (1200,70)
// Panel canto inferior direito(1200,620)
// reajustando coordenadas do panel
para o sistema de coordenadas x e y
x = x - 50;
//y=70+480; //550 se y=70
//y=71+478; // 549 se y=71
//y=72+476; // 548 se y=72
y = y + 480 + (y - 70) * (-2); // lei geral
// só exibe as coordenadas na área de desenho
if ((x >= 0) && (x <= 1150) && (y >= 0) && (y <= 550)) {
coordenadas.setText("[x:" + x + "]" + "[y:" + y + "]");
} else {
coordenadas.setText("Fora da área de desenho");
}
/*se proximo ponto for verdadeiro significa que já devemos o primeiro clique na nova
linha e então podemos exibir o marcador linha*/
if(proximoPonto){
marcadorLinha=true;
}
/*
se a linha estiver ativada e proxima linha for verdadeira
reativa o marcador linha quando movimentamos o mouse*/
if (linhaAtivada && pontos.size() > 0) { // garantir que o array list não é vazio
this.x2 = e.getX();
this.y2 = e.getY();
this.x1 = pontos.get(pontos.size() - 1).x; // pega a coordenada x do último ponto da última linha
this.y1 = pontos.get(pontos.size() - 1).y; // pega a coordenada y do último ponto da última linha
double distanciaX=x2-x1;
double distanciaY=-(y2-y1); // inverter a distancia pois o eixo y conta de cima para baixo
double anguloRad=Math.atan(distanciaY/distanciaX);
tamanhoLinha=Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
// inverter a desigualdade no eixo y pois o eixo y conta de cima para baixo y1>y2 vira y1<y1
//1º quadrante
if((x2>x1)&&(y2<y1)){
anguloGrausLinha=(180*anguloRad)/Math.PI;
}
//2º quadrante
if((x2<x1)&&(y2<y1)){
anguloGrausLinha=180+(180*anguloRad)/Math.PI; // soma 180 graus pois o angulo é retornado no 4º pelo atan
}
//3º quadrante
if((x2<x1)&&(y2>y1)){
anguloGrausLinha=180+(180*anguloRad)/Math.PI; // soma 180 graus pois o angulo é retornado no 1º quadrante
}
//4º quadrante
if((x2>x1)&&(y2>y1)){
anguloGrausLinha=360+(180*anguloRad)/Math.PI;
}
//eixo x positivo
if((y1==y2)&&(x2>x1)){
anguloGrausLinha=0;
}
// eixo x negativo
if((y1==y2)&&(x2<x1)){
anguloGrausLinha=180;
}
// eixo y positivo
if((y2<y1)&&(x2==x1)){
anguloGrausLinha=90;
}
// eixo y negativo
if((y2>y1)&&(x2==x1)){
anguloGrausLinha=270;
}
localizacaoXMarcadorLinha=e.getX()+50;
localizacaoYMarcadorLinha=e.getY()+50;
repaint();
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
if (linhaAtivada) {
Point ponto = e.getPoint();
// verifica se o ponto está na área de desenho e apenas adiciona o ponto se estiver na area de desenho
if((ponto.x>=50)&&(ponto.x<=1200)&&(ponto.y>=70)&&(ponto.y<=620)){
proximoPonto = true;
if (proximoPonto) {
txtBarraComandos.setText("LINHA especifique o próximo ponto: ");
}
pontos.add(ponto);
linhasVisiveis.add(true);
indiceLinha++;// incrementa toda vez que um novo ponto é atribuido e um linha criada
// indice 0 para primeira linha
marcadorLinha=false; // desativa o marcador linha quando clicarmos em um ponto
repaint();
}
}
if (circuloAtivado) {
if (clickInicial) {
xcentro = e.getX();
ycentro = e.getY();
} else {
xcontorno = e.getX();
ycontorno = e.getY();
circulos.add(new Circulo(xcentro, ycentro, xcontorno, ycontorno));
}
if (clickInicial == true) {
clickInicial = false;
} else {
clickInicial = true;
}
if (clickFinal == false) {
clickFinal = true;
} else {
clickFinal = false;
}
}
repaint();
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == itemArquivoSair) {
System.exit(0);
}
if (e.getSource() == itemDesenharLinha) {
linhaAtivada = true;
circuloAtivado = false;
textoComandos.setText("LINHA ATIVADA");
textoComandos.setForeground(Color.RED);
txtBarraComandos.setText("LINHA especifique o primeiro ponto: ");
marcadorLinha=false;
proximoPonto=false; // volta variável proximoPonto para false quando a linha for desativada
if (indiceLinha >= 0) {
linhasVisiveis.set(indiceLinha, false);
System.out.println("Comando linha desativado");
System.out.println("Pressione L e a tecla ENTER para ativar o comando linha");
}
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
/*o operador igual não serve para compararmos se duas Strings são
iguais temos que usar o método equals ou equalIgnoreToCase para isso
O método equals da classe String compara se uma String passada entre parênteses
é igual a String que está sendo usada para acessar o método equals,esse método
método considera as diferenças entre letras maiusculas e letra minúsculas ou seja
a String "MARIA" será considerada diferente da String "maria" e o método retorna
true se as Strings forem iguais e retorna false se as Strings são diferentes
equalsIgnoreCase(String s) – igual ao equals,
porém ignora MAIÚSCULAS e minúsculas. Retorna
true ou false (boolean).*/
/*no nosso caso iremos passar como parâmetro para equalsIgnoreCase o retorno
da barra de comandos e eremos comparar com a String que está acessando o método
no caso a String "C"*/
if (("L".equalsIgnoreCase(txtBarraComandos.getText())) || ("LINHA".equalsIgnoreCase(txtBarraComandos.getText()))) {
linhaAtivada = true;
circuloAtivado = false;
textoComandos.setText("LINHA ATIVADA");
textoComandos.setForeground(Color.RED);
txtBarraComandos.setText("LINHA especifique o primeiro ponto: ");
marcadorLinha=false;// matém o marcador linha em false para ativar só quando clicar
}
if (("C".equalsIgnoreCase(txtBarraComandos.getText())) || ("CÍRCULO".equalsIgnoreCase(txtBarraComandos.getText()))) {
circuloAtivado = true;
linhaAtivada = false;
textoComandos.setText("CÍRCULO ATIVADO");
textoComandos.setForeground(Color.RED);
txtBarraComandos.setText("LINHA especifique o primeiro ponto: ");
marcadorLinha=false;
}
}
if (e.getKeyCode() == 27) { // tecla ESC
linhaAtivada = false;
circuloAtivado = false;
/*muda o índice atual da linha onde esc foi pressionado e muda para
false*/
/*o método set de um arraylist substitui o elemento na posição especificada
nesta lista pelo elemento especificado,o primeiro valor é o indice do elemento
que será substituído,o segundo valor é o novo elemento que será substituído,
neste caso iremos passar false para o array list já que está empacotado
num wrapper*/
if (indiceLinha >= 0) {
linhasVisiveis.set(indiceLinha, false);
}
txtBarraComandos.setText("");
textoComandos.setText("nenhum comando encontrado");
textoComandos.setForeground(Color.BLACK);
proximoPonto=false; // volta o proximoPonto para false quando a linha for desativada
marcadorLinha=false;
repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
}
DesenhoTeste.java
package miniCad4;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class DesenhoTeste {
public static void main(String[] args) {
JFrame janela = new JFrame("MiniCAD");
Desenho desenho = new Desenho();
janela.setSize(1260, 720); // 1200 700
janela.setVisible(true);
janela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
janela.setLocationRelativeTo(null);
janela.setResizable(false);
janela.add(desenho);
// System.out.println(Math.atan(1));
}
}
Circulo.java
package miniCad4;
public class Circulo {
double raio;
int x;
int y;
int diametro;
int xcentro;
int ycentro;
int xcontorno;
int ycontorno;
public Circulo(int xcentro, int ycentro, int xcontorno, int ycontorno) {
this.xcentro = xcentro;
this.ycentro = ycentro;
this.xcontorno = xcontorno;
this.ycontorno = ycontorno;
raio = Math.sqrt(Math.pow((xcentro - xcontorno), 2) + Math.pow((ycentro - ycontorno), 2));
/*Devemos arredondar o valor e fazer um cast para um inteiro pois draw oval só aceita
inteiros*/
x = (int) Math.round(xcentro - raio);
y = (int) Math.round(ycentro - raio);
diametro = (int) Math.round(2 * raio);
}
}