paintComponent() vs paint() and JPanel vs Canvas in a paintbrush-type GUI

删除回忆录丶 提交于 2019-11-26 15:27:51

I've been trying to find a workarounds, but have not found one, especially for the getGraphics() method: how else can the graphics be added to the panel?

You remember what needs to be painted as a variable and use that in paintComponent(). For example, what you seemed to be trying to do in your other question would look like:

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

public class PaintRectangle extends JPanel {

    private Point mouseLocation;

    public PaintRectangle() {
        setPreferredSize(new Dimension(500, 500));

        MouseAdapter listener = new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                updateMouseRectangle(e);
            }

            private void updateMouseRectangle(MouseEvent e) {
                mouseLocation = e.getPoint();
                repaint();
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                updateMouseRectangle(e);
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                mouseLocation = null;
                repaint();
            }
        };
        addMouseListener(listener);
        addMouseMotionListener(listener);
    }

    private Rectangle getRectangle() {
        if(mouseLocation != null) {
            return new Rectangle(mouseLocation.x - 5, mouseLocation.y - 5, 10, 10);
        }
        else {
            return null;
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Rectangle rectangle = getRectangle();
        if(rectangle != null) {
            Graphics2D gg = (Graphics2D) g;
            gg.setColor(Color.BLUE);
            gg.fill(rectangle);
            gg.setColor(Color.BLACK);
            gg.draw(rectangle);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                frame.getContentPane().add(new PaintRectangle());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

See also http://docs.oracle.com/javase/tutorial/uiswing/painting/

Heavy vs light weight

Basically speaking, a heavy weight component is linked to its own native peer, where light weight components share a common native peer.

In general, it's not a good idea to mix heavy and light weight components as there are issues with the z-order and in my experience (even though it's supposed to be better now) there are painting issues that can crop up.

This is the reason why you have been discouraged from using the Canvas class, probably because you were trying to place it onto a light weight component...I guess

The illusion of control

One of the biggest issues for newcomers to the Swing API is the illusion that you have some kind of control over the painting process, you don't. It's easier to just accept it.

The best you can do is request that the repaint manager perform an update at its earliest convenience.

Also, calling getGraphics is not guaranteed to return a non-null value.

The correct order of things

paint vs paintComponent

The problem here is paint does a number of important jobs, calling paintComponent is just one of them.

In Swing we are greatly encouraged to use paintComponent whenever we want to perform custom painting, this is, generally, the lowest level on the component and is called before the child components are painted.

If you override paint and then paint on the Graphics after the call to super.paint you will end up painting on top of everything, this isn't always the desired result

Even if it were, child components can be painted independently of their parent container, making the paint "over" any paint effects you might have added

Useful links

Parting thoughts

Only components that are actually added to a component, which is attached to a native peer will ever have there paint method called. So trying to paint to a component that hasn't been added to a container yet is rather pointless...

Andrew Thompson

..paintbrush-type GUI..

Use a BufferedImage as the painting surface. Display it in a JLabel. Put the label in the center of a panel inside a JScrollPane.

Call bufferedImage.getGraphics() as needed but remember to dispose() of it when done, and then call label.repaint().

Use Swing components throughout, and don't override anything.

Here is an example of using an image as painting surface.

And here is a better one!

I did not say the screen-shot was better, it is the code that is better. ;)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!