Methods in Java which can change pixel values

2019-06-14 19:23发布

问题:

I am working on an animation kind of program in java and for visualization. I am using the swing and awt libraries. I looked at a dozen implementations of this and all of them use a paint Component method and then repaint() when they want to draw shapes on the JFrame.

Is there some method that I can call from any class that I want that can for example change a single pixel value?

I also want to make an array list with shapes:

ArrayList<Rectangle> rectangles = new ArrayList<Rectangle>(); 

And I am curious how to add things to it. I was thinking:

Rectangle rect = "something"
rectangles.add(rect);

But I'm not sure what something should be. I am relatively new to this, so feel free to express your views if I'm missing something obvious.

回答1:

Is there some method that I can call from any class that I want that can for example change a single pixel value?

You could create a BufferedImage, which has a setRGB(...) method that would achieve what you wanted by drawing the image within the paintComponent(...) method with Graphics drawImage(...) method.

With regard to Rectangle rect = "something" -- just look up the Rectangle constructors available to you in the Rectangle API and use the most appropriate one for you.



回答2:

It's been suggested the you should use getGraphics over paintComponent, let's take a look at that for a second...

Opps, oh, that didn't quite work the way we'd expect! Let's even ignore why you shouldn't paint directly to top level containers (cause that's painting under the title bar)

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

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

                JButton draw = new JButton("Draw");

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());
                frame.add(draw);
                frame.setSize(150, 150);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

                draw.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        drawARectangle(frame.getGraphics());
                    }
                });
            }
        });
    }

    public void drawARectangle(Graphics g) {
        g.setColor(Color.RED);
        g.fillRect(20, 20, 100, 100);
    }

}

Okay, let's have a look at paintComponent and repaint

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

    public Test() {
        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.setLayout(new GridBagLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private boolean drawBox;

        public TestPane() {
            setLayout(new GridBagLayout());
            JButton draw = new JButton("Draw");
            add(draw);
            draw.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    drawBox = !drawBox;
                    repaint();
                }
            });
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (drawBox) {
                g.setColor(Color.RED);
                g.fillRect(20, 20, 100, 100);
            }
        }

    }

}

Swing has well documented painting process, have a look at Painting in AWT and Swing and Performing Custom Painting for more details and one should work within the design of the API.

Before anyone jumps down my throat and suggest you could use a WindowListener or ContainerListener or some other listener, the answer is, why? paintComponent works just fine.

Swing uses a passive rendering engine, meaning that a paint might occur for any number of reasons, most of the time which you don't instantiate or know about, so unless your linked into the painting process, you won't know that it's occurred, resizing is just a really good way to demonstrate it

So can we please stop suggesting bad approaches like using getGraphics or using null layouts or KeyListener or DocumentListener for real time filtering of text components and maybe we can save a bunch of people a bunch of head aches



回答3:

Apparently I was ranting when I called everyone an idiot for using repaint(); here's the better way. Say I wanted to create a rectangle or image or line or oval on the jframe,

public JFrame frame = new JFrame();
public void paintingHome(){
//set up the jframe and stuff
System.out.println("This is a rectangle");
paintARectangle(frame.getGraphics(), 42, 256);
}
public void paintARectangle(Graphics g, int xCoord, int yCoord, int width, int height){
g.fillRact(xCoord, yCoord, width, height);
//simple as that
}
//and you can have as many as you want
public void paintWhatever(Graphics g, Something whatever){
g.doSomethingWith(whatever);
//that won't actually work until oracle releases version 238249.3432.4
}
//the key is using the frame.getGraphics() method
//repaint is unnecessary and restrictive