Dominika
Dominika

Reputation: 187

Java: Paint application, the code doesn't work, what am I doing wrong?

I'm new to Java and I'm learning by myself. I got stuck at this point. I created a very basic paint application, but my friend told me that as I put everything in one *.java file that you can tell that I'm a beginning programmer, since I'm not really using object-oriented programming :D So I decided to divide my code into various files. But now the code is not working (obviously).

So I have the Main.java file which creates a window for the program (JFrame) and inside of that JFrame there are 2 panels, one on the BorderLayout.WEST, and secong in the CENTER. The one on the .WEST is the SideBar (with buttons etc.) and the one in the .CENTER is the main drawing board:

The Main.java file (public class Main):

import java.awt.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.*;

public class Main {

    private Paint myPaint;
    private menuSideBar sidePanel;

Main(){

    JFrame ramka = new JFrame("Paint Application");

    sidePanel = new menuSideBar(); //this is the sidebar
    myPaint = new Paint(); // this is the drawing board

    ramka.getContentPane().add(sidePanel, BorderLayout.WEST);
    ramka.getContentPane().add(myPaint, BorderLayout.CENTER);
    ListenForWindow lForWindow = new ListenForWindow();
    ramka.addWindowListener(lForWindow);
    ramka.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    ramka.setSize(1400, 800);
    ramka.setLocationRelativeTo(null);
    ramka.setVisible(true);

}

private class ListenForWindow implements WindowListener{

    public void windowOpened(WindowEvent e) {
    }

    public void windowClosing(WindowEvent e) {
        int closing = JOptionPane.showConfirmDialog(null, "Exit program?", "Exit", JOptionPane.YES_NO_OPTION);
        if (closing == JOptionPane.YES_OPTION){
            System.exit(0);
        }
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }

}


public static void main(String[] args){
    new Main();
}

}

Then I have the drawing board, in file Paint.java (public class Paint):

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class Paint extends JComponent {

private static final long serialVersionUID = 1L;
private BufferedImage bimage;
private Graphics2D g2;
private int whichShape;
private int oldX, oldY, newX, newY;
private int w, h;
private Color cColor;

Paint() {


    ListenForMouse lForMouse = new ListenForMouse();
    this.addMouseListener(lForMouse);
    this.addMouseMotionListener(lForMouse);

}

public void paintComponent(Graphics g){


    if (bimage == null){
        bimage = new BufferedImage(getSize().width, getSize().height, BufferedImage.TYPE_INT_ARGB);
        g2 = (Graphics2D) bimage.getGraphics();
        g2.setBackground(Color.WHITE);
        g2.setColor(Color.BLACK);
        clear();
    }

    g.drawImage(bimage, 0, 0, null);
}

public void clear(){
    g2.clearRect(0, 0, getSize().width, getSize().height);
    repaint();
}


public void draw(){

    w = newX - oldX;
    h = newY - oldY;

    if (w<0){
        w = w * (-1);
    }
    if (h<0){
        h = h * (-1);
    }


    switch (whichShape) {

    case 1:
        check();
        g2.drawRect(oldX, oldY, w, h);
        repaint();
        break;
    case 2:
        check();
        g2.drawRoundRect(oldX, oldY, w, h, 40, 40);
        repaint();
        break;
    case 3:
        check();
        g2.drawOval(oldX, oldY, w, h);
        repaint();
        break;
    case 4:
        check();
        g2.fillRect(oldX, oldY, w, h);
        repaint();
        break;
    case 5:
        check();
        g2.fillRoundRect(oldX, oldY, w, h, 20, 20);
        repaint();
        break;
    case 6:
        check();
        g2.fillOval(oldX, oldY, w, h);
        repaint();
        break;
    }
}



public void rectangle(){

    whichShape = 1;

}

public void roundedrectangle(){
    whichShape = 2;
}

public void oval(){
    whichShape = 3;
}

public void filledrectangle(){
    whichShape = 4;
}

public void filledroundedrectangle(){
    whichShape = 5;
}

public void filledoval(){
    whichShape = 6;
}

public void colorChooser(){
    cColor = JColorChooser.showDialog(null, "Choose color", Color.black);
    g2.setColor(cColor);
}


public void check(){
    if (oldX > newX){
        int z;
        z = oldX;
        oldX = newX;
        newX = z;
    }
    if (oldY > newY){
        int z;
        z = oldY;
        oldY = newY;
        newY = z;
    }
}



public class ListenForMouse implements MouseListener, MouseMotionListener{

    public void mouseDragged(MouseEvent e) {

    }

    public void mouseMoved(MouseEvent e) {
    }

    public void mouseClicked(MouseEvent e) {
    }

    public void mousePressed(MouseEvent e) {

        if (whichShape == 1 || whichShape == 2 || whichShape == 3 || whichShape == 4 || whichShape == 5 || whichShape == 6){
            oldX = e.getX();
            oldY = e.getY();    
        }

    }

    public void mouseReleased(MouseEvent e) {

        if (whichShape == 1 || whichShape == 2 || whichShape == 3 || whichShape == 4 || whichShape == 5 || whichShape == 6){
        newX = e.getX();
        newY = e.getY();
        draw();
        }

    }

    public void mouseEntered(MouseEvent e) {
    }

    public void mouseExited(MouseEvent e) {
    }

}

}

Later there is sidebar, which is in the menuSideBar.java file (public class menuSideBar), this class reads in 4 other classes (there are 4 different menus I want to add, here I will just show one example):

import javax.swing.*;

public class menuSideBar extends JPanel {

    private static final long serialVersionUID = 1L;
    sideBar1 sb1;
    //sideBar2 sb2;
    //sideBar3 sb3;
    //sideBar4 sb4;

menuSideBar(){


    this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

    sb1 = new sideBar1();
    //sb2 = new sideBar2();
    //sb3 = new sideBar3();
    //sb4 = new sideBar4();

    this.add(sb1);
    //this.add(sb2);
    //this.add(sb3);
    //this.add(sb4);


}   
}

And this sideBar1.java file (public class sideBar1) contains JButtons with ActionListeners referring to methods in Paint.java file:

import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;


public class sideBar1 extends JPanel {

private static final long serialVersionUID = 1L;
Paint myPaint;

JButton pencilBut, brushBtn, bckpaintBtn, eraserBtn, textBtn, rectBtn, roundedrectBtn, ovalBtn, frectBtn, fovalBtn, froundedrectBtn, lineBtn;

sideBar1(){


    Border border = BorderFactory.createTitledBorder("Paint");
    this.setBorder(border);
    this.setLayout(new GridLayout(0,3));
    myPaint = new Paint();

    ListenForButton lForButton = new ListenForButton();

    pencilBut = new JButton("pencil");
    pencilBut.addActionListener(lForButton);
    brushBtn = new JButton("brush");
    brushBtn.addActionListener(lForButton);
    bckpaintBtn = new JButton("background paint");
    bckpaintBtn.addActionListener(lForButton);
    eraserBtn = new JButton("eraser");
    eraserBtn.setIcon(icon_eraser);
    eraserBtn.addActionListener(lForButton);
    textBtn = new JButton("text");
    textBtn.addActionListener(lForButton);
    lineBtn = new JButton("line");
    lineBtn.addActionListener(lForButton);
    rectBtn = new JButton("rectangle");
    rectBtn.addActionListener(lForButton);
    roundedrectBtn = new JButton("rounded rectangle");
    roundedrectBtn.addActionListener(lForButton);
    ovalBtn = new JButton("oval");
    ovalBtn.addActionListener(lForButton);
    frectBtn = new JButton("filled rectangle");
    frectBtn.addActionListener(lForButton);
    froundedrectBtn = new JButton("filled rounded rectangle");
    froundedrectBtn.addActionListener(lForButton);
    fovalBtn = new JButton("filled oval");
    fovalBtn.addActionListener(lForButton);



    this.add(pencilBut);
    this.add(brushBtn);
    this.add(bckpaintBtn);
    this.add(eraserBtn);
    this.add(textBtn);
    this.add(lineBtn);
    this.add(rectBtn);
    this.add(roundedrectBtn);
    this.add(ovalBtn);
    this.add(frectBtn);
    this.add(froundedrectBtn);
    this.add(fovalBtn);





}

public class ListenForButton implements ActionListener{

    @Override
    public void actionPerformed(ActionEvent e) {


        if (e.getSource() == brushBtn){

        } else if (e.getSource() == bckpaintBtn){

        } else if (e.getSource() == eraserBtn){

        } else if (e.getSource() == textBtn){

        } else if (e.getSource() == lineBtn){

        } else if (e.getSource() == rectBtn){
            System.out.println("rectangle");
            myPaint.rectangle();
        } else if (e.getSource() == roundedrectBtn){
            myPaint.roundedrectangle();
        } else if (e.getSource() == ovalBtn){
            myPaint.oval();
        } else if (e.getSource() == frectBtn){
            myPaint.filledrectangle();
        } else if (e.getSource() == froundedrectBtn){
            myPaint.filledroundedrectangle();
        } else if (e.getSource() == fovalBtn){
            myPaint.filledoval();
        } 


    }

}


}

Now, when I execute the code everything loads in smoothly, I can see all the panels and and all the components inside, but when I click the buttons nothing happens. I'm guessing it has to do with the inheritance, or actually I have a few questions:

  1. Did I understand my friend correctly? Should I divide my code into various *.java files and have every class in a different file, in the same package? Or should I include those various classes in one *.java file? (if the latter option is ok, can somebody modify at least a fragment of my code, so I would know how to properly incorporate inheritance?, some of the classes extend JPanels and JComponents, and I've read that you should not mix up extending JPanels etc. (views) with models(?)
  2. Is it ok to read into Main.java file JPanels which are in another file menuSideBar.java and then reading into menuSideBar.java panels that are inside of sideBar1.java? Or should I define which panel goes into which panel in the Main class?
  3. Why is the Paint.java not reading the ActionListener of the JButtons of sideBar1.java? What am I doing wrong?

Thank you! Sorry if that seems obvious to you, but all the examples in the books or tutorials have very short examples of inheritance and very simple ones and somehow I cannot transfer those simple examples into my code. Thank you!

Upvotes: 1

Views: 185

Answers (1)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285401

Your main problem is that you're creating two Paint objects when you only need and should have one. To check this for yourself, search this page for how many times you see new Paint(). You should only see it once in the code, and you're seeing it twice.

Why does this matter? Well one Paint object is displayed in the GUI, and the other is not displayed, but its methods are being called when buttons are pressed in the ActionListener. Calling methods on the non-displayed object will not translate into a visible response in the displayed one.

An easy solution that is wrong is to make your paint variable static and share it everywhere. This is wrong as you lose the benefits of OOP and increase the risk of bugs. Better is to pass a reference from the visualized Paint object into the ActionListener where it is needed, so that only one Paint object is created, and methods are called in the listener on the same Paint object as the one that's displayed.

More concrete, change this:

sidePanel = new menuSideBar(); //this is the sidebar
myPaint = new Paint(); // this is the drawing board

to this:

myPaint = new Paint(); // call this first
sidePanel = new menuSideBar(myPaint); // and pass it in

In the sideBar constructor (the class should be renamed SideBar), use the parameter:

public sideBar(Paint myPaint) {
    this.myPaint = myPaint;
    // .... all other constructor code
}

and get rid of new Paint() from sideBar.

Upvotes: 2

Related Questions