Search code examples
javaswingjcomboboxjcomponent

JComboBox erases the JComponent over which it pops up


I am working on a program that will function similarly to Paint. It looks like this: program

The error occurs when I open the JComboBox(used to select brush size). It seems to erase whatever has been drawn under it. JComboBox opened. After closing the JComboBox it looks like this: JComboBox closed

Any ideas as to what might be causing this, and how to remedy it?

Code:

import javax.swing.*;
import java.awt.*;
import java.util.Scanner;
import java.io.File;
import java.io.IOException;
import java.awt.event.*;


public class Paint extends JFrame implements ActionListener {
    private JPanel topBar;
    private JComboBox<String> brushSizes;
    private DrawArea drawArea;

    public Paint() throws IOException {
        setTitle("Paint");
        setSize(500,500);
        setLayout(new BorderLayout());
        drawArea = new DrawArea();
        topBar = new JPanel(new FlowLayout());
        String[] sizes = {"1", "2", "3", "5", "8", "10", "25", "50", "100"};
        brushSizes = new JComboBox<String>(sizes);
        brushSizes.setSelectedIndex(0);
        brushSizes.setActionCommand("BrushSize");
        brushSizes.addActionListener(this);
        topBar.add(brushSizes);
        add(topBar, BorderLayout.NORTH);
        add(drawArea, BorderLayout.CENTER);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent event) {
        String command = event.getActionCommand();
        if (command.equals("BrushSize")) {
            drawArea.setBrushStroke(Integer.parseInt((String)brushSizes.getSelectedItem()));
        }
    }

    public static void main(String[] args) throws IOException {
        Paint paint = new Paint();
    }
}

More Code:

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

public class DrawArea extends JComponent implements MouseMotionListener,     MouseListener {
    private Color currentColor;
    private boolean dragging;
    private int toX;
    private int toY;
    private int brushSize;
    private Graphics drawer;

    public DrawArea() {
        currentColor = Color.BLACK;
        dragging = false;
        addMouseListener(this);
        addMouseMotionListener(this);
        toX = -1;
        toY = -1;
        brushSize = 1;
        repaint();
    }

    public void setBrushStroke(int size) {
        brushSize = size;
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.WHITE);
        g.fillRect(0,0,1000,1000);
        g.setColor(currentColor);
    }

    public void mousePressed(MouseEvent event) {
        dragging = true;
        toX = event.getX();
        toY = event.getY();
        drawer = getGraphics();
        drawer.setColor(currentColor);
    }

    public void mouseReleased(MouseEvent event) {
        dragging = false;
        drawer.dispose();
        drawer = null;
    }

    public void mouseDragged(MouseEvent event) {
        if (dragging) {
            int x = event.getX();
            int y = event.getY();

            Graphics2D drawerTo = (Graphics2D) drawer;
            drawerTo.setStroke(new BasicStroke(brushSize));
            drawerTo.drawLine(toX, toY, x, y);
            toX = x;
            toY = y;
        }
    }

    public void mouseClicked(MouseEvent event) {}
    public void mouseEntered(MouseEvent event) {}
    public void mouseExited(MouseEvent event) {}

    public void mouseMoved(MouseEvent event) {}
}

Solution

  • There are two common ways to do custom painting. Check out Custom Painting Approaches for examples of each approach:

    1. The DrawOnImage example shows how to paint to a BufferedImage using the Graphics object of the BufferedImage.

    2. The DrawOnComponent example shows how to use the Graphics object passed to the paintComponent(...) method of the component.

    The approach you use will depend on your exact requirement.