Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
486 views
in Technique[技术] by (71.8m points)

swing - Easier way to make a paint application in java?

So basically I have some code I was working on a couple of days ago that is kind of like Paint, which allows you to essentially draw on the screen using the mouse. I kind of discovered this property by accident, and I realized that it is really inefficient and i'm wondering if there is a more practical way to do this. There isn't really any reason to give all of my code, but here are the important parts

private static void createAndShowGui() {
    SimpleDraw mainPanel = new SimpleDraw();
    MenuBar.createMenuBar();
    JLabel label = new JLabel();
    label.setText("Drawing prototype 0.0.1");
     // label.setHorizontalTextPosition(JLabel.NORTH);
    label.setFont(new Font("Serif", Font.BOLD, 20));
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(mainPanel);
    frame.pack();
    frame.setLocationByPlatform(true);
    frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.PAGE_AXIS));
    frame.setVisible(true);
    frame.setJMenuBar(MenuBar.getMenuBar());
    frame.setBackground(Color.WHITE);
    frame.add(label);

The code block above sets up the jframe (the window)

 @Override
    public void mouseDragged(MouseEvent e)
    {
    // These console outputs are just so that I know what is happening
        System.out.println("Event: MOUSE_DRAG");
        System.out.println(e.getX());
        System.out.println(e.getY());
        System.out.println(e.getComponent());
        System.out.println(e.getWhen());
        System.out.println(e.getButton());
         MOUSE_X = e.getX() - 5;  //-5 so that the cursor represents the center of the square, not the top left corner.
         MOUSE_Y = e.getY() - 5;  //^
         rect = new Rectangle(MOUSE_X, MOUSE_Y, 10, 10 ); //This doesn't ever come into action.
         repaint();  

     }

The code above pretty much just sets the MOUSE_X and MOUSE_Y variables and the repaint(); method

@Override
    protected void paintComponent(Graphics g) {

    Graphics2D g2 = (Graphics2D) g;
    if (rect != null) {

        if (!colorChoice.equals("Default"))
        {
            g2.setColor(Color.BLACK);
        }

        switch(colorChoice) {

        case "GRAY":
            g2.setColor(Color.GRAY);
            break;
        case "CYAN":
            g2.setColor(Color.CYAN);
            break;
        case "BLUE":
            g2.setColor(Color.BLUE);
            break;
        case "RED":
            g2.setColor(Color.RED);
            break;
        case "PINK":
            g2.setColor(Color.PINK);
            break;
        case "YELLOW":
            g2.setColor(Color.YELLOW);
            break;
        case "GREEN":
            g2.setColor(Color.GREEN);
            break;
        case "PURPLE":
            g2.setColor(Color.MAGENTA);
            break;
        case "RESET":
            g2.setColor(Color.WHITE);
        case "WHITE":
            g2.setColor(Color.WHITE);

        }





        g2.fillRect(MOUSE_X, MOUSE_Y, 15, 15); 

        if (colorChoice.equals("RESET")) 
        resetColorOnCursor(); 

        }
    }

    public static void clearBoard()
    {
    tempColor = colorChoice;
    setColorChoice("RESET");
    frame.repaint();




    }


    public static void resetColorOnCursor()
    {
    setColorChoice(tempColor);
    }

This is the thing I came across accidentally. What I was trying to do when I found this out was basically make a square follow your cursor whenever you moved your mouse. But I forgot to type the code part paintComponent(g);, which turns this program into the thing that I originally intended. The bottom parts of this are essentially how I would clear the board. I'm 100% sure that this isn't the proper way to clear/reset a frame like this, but I couldn't find another way. If anyone has any tips or better methods to use to do this properly I would be very appreciative. Thanks! :D

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You're current approach is basically breaking the requirements of the paint chain, by not calling super.paintComponent. The paintComponent method does a set of operations, which you are not taking over and which could result in some very weird paint artifacts which are difficult to replicate consistently.

Graphics is a shared resource, so the Graphics context which was used to paint some other control will be the same which is used to paint your component, unless you are "cleaning" the context before hand, what was previously painted to the context will remain (which is why you code currently "seems" to work).

Instead, you should use a MouseListener to define a anchor point, which represents the point at which the mouse was pressed and then use the MouseMotionListener to define the extent of the selection area, for example...

Paint Selection

import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SelectExample {

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

    public SelectExample() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Rectangle selection;

        public TestPane() {
            MouseAdapter ma = new MouseAdapter() {

                private Point clickPoint;

                @Override
                public void mousePressed(MouseEvent e) {
                    clickPoint = e.getPoint();
                    selection = null;
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point dragPoint = e.getPoint();
                    int x = Math.min(clickPoint.x, dragPoint.x);
                    int y = Math.min(clickPoint.y, dragPoint.y);

                    int width = Math.max(clickPoint.x, dragPoint.x) - x;
                    int height = Math.max(clickPoint.y, dragPoint.y) - y;

                    if (selection == null) {
                        selection = new Rectangle(x, y, width, height);
                    } else {
                        selection.setBounds(x, y, width, height);
                    }
                    repaint();
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    selection = null;
                    repaint();
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (selection != null) {
                g.setColor(UIManager.getColor("List.selectionBackground"));
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
                g2d.fill(selection);
                g2d.dispose();
                g2d = (Graphics2D) g.create();
                g2d.draw(selection);
                g2d.dispose();
            }
        }

    }

}

Just to highlight the issue you will face if you continue to violate the requirements of the paintComponent method, this is what happens when I don't call super.paintComponent

Violated

I simply added two JButton's to the JFrame (so not even directly to the panel). paintComponent does a series of important jobs, which you neglected to perform, which is going to cause more problems and issues.

Free form line example...

A free form line is actually a illusion, it's a series of (small) lines drawn between a series of points, the reason for this is because the MouseListener won't report every mouse position it moves across, depending on the speed the mouse is moved, you might get lots of call backs or a few.

So, instead of drawing to just draw the points, we store the points in a List and draw lines between them, for example...

FreeForm

import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class FreeFormLines {

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

    public FreeFormLines() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private List<List<Point>> points;

        public TestPane() {
            points = new ArrayList<>(25);
            MouseAdapter ma = new MouseAdapter() {

                private List<Point> currentPath;

                @Override
                public void mousePressed(MouseEvent e) {
                    currentPath = new ArrayList<>(25);
                    currentPath.add(e.getPoint());

                    points.add(currentPath);
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point dragPoint = e.getPoint();
                    currentPath.add(dragPoint);
                    repaint();
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    currentPath = null;
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            for (List<Point> path : points) {
                Point from = null;
                for (Point p : path) {
                    if (from != null) {
                        g2d.drawLine(from.x, from.y, p.x, p.y);
                    }
                    from = p;
                }
            }
            g2d.dispose();
        }

    }

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...