我有一个带按钮的代码。按下按钮时,圆圈会随机出现在颜色随机的位置。只能有10个圆圈。
现在我添加了随机颜色功能,问题是在绘制每个圆圈后,它的颜色开始变得无用。
我怎样才能让颜色不变?
class Panel extends JPanel {
private JButton button;
private Ellipse2D.Double[] circles;
Integer count;
public Panel() {
setup();
}
private void setup() {
count=new Integer(0);
circles=new Ellipse2D.Double[10];
button=new JButton(count.toString());
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Random r=new Random();
//position circles with diameter 100 in a way
//that it would fit in a window's size
int highX=getWidth()-100;
int highY=getHeight()-100;
circles[count]=new
Ellipse2D.Double(r.nextInt(highX),
r.nextInt(highY), 100, 100);
count++;
button.setText(count.toString());
}
});
add(button);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
paintStuff(g);
repaint();
}
private void paintStuff(Graphics g) {
Graphics2D g2=(Graphics2D) g;
g2.setPaint(Color.RED);
if (count!=0) {
for (int i=0; i<count; i++) {
g2.draw(circles[i]);
Random r=new Random();
int red=r.nextInt(256);
int green=r.nextInt(256);
int blue=r.nextInt(256);
g2.setPaint(new Color(red, green, blue));
g2.fill(circles[i]);
}
}
}
}
public class Frame extends JFrame {
private Panel panel;
public Frame() {
panel=new Panel();
add(panel);
}
public static void main(String[] args) {
Frame frame=new Frame();
}
}
答案 0 :(得分:5)
永远不要在绘画方法中调用重绘,因为这会导致“穷人”#34;动画发生。而是在JButton的ActionListener中调用它。此外,不要在绘画方法中随机化,而是在ActionListener中执行此操作。绘画方法不在您的控制之下,您不想用它来改变对象的状态,而只是为了显示它。
其他建议:
public Dimension getPreferredSize()
并在添加JPanel之后但在显示它之前在JFrame上调用pack()
。HashMap<Shape, Color>
。例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.geom.Ellipse2D;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import javax.swing.*;
@SuppressWarnings("serial")
public class Panel2 extends JPanel {
// preferred size constants
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
// map to hold circles and colors
private Map<Shape, Color> shapeColorMap = new LinkedHashMap<>();
public Panel2() {
add(new JButton(new RandomColorAction()));
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// create *smooth* drawings
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
paintStuff(g2);
}
private void paintStuff(Graphics2D g2) {
// iterate through our map extracting all circles and colors
// and drawing them
for (Entry<Shape, Color> entry : shapeColorMap.entrySet()) {
Shape shape = entry.getKey();
Color color = entry.getValue();
g2.setColor(color);
g2.fill(shape);
}
}
// listener for our button
private class RandomColorAction extends AbstractAction {
private static final int CIRC_WIDTH = 100;
private Random random = new Random();
private int count = 0;
public RandomColorAction() {
super("Random Circle: 0");
putValue(MNEMONIC_KEY, KeyEvent.VK_R);
}
@Override
public void actionPerformed(ActionEvent e) {
// create our random ellipses
int x = random.nextInt(getWidth() - CIRC_WIDTH);
int y = random.nextInt(getHeight() - CIRC_WIDTH);
Shape shape = new Ellipse2D.Double(x, y, CIRC_WIDTH, CIRC_WIDTH);
// create our random color using HSB for brighter colors
float hue = random.nextFloat();
float saturation = (float) (0.8 + random.nextFloat() * 0.2);
float brightness = (float) (0.8 + random.nextFloat() * 0.2);
Color color = Color.getHSBColor(hue, saturation, brightness);
shapeColorMap.put(shape, color);
// increment count, place items into map, repaint
count++;
putValue(NAME, "Random Circle: " + count);
repaint();
}
}
private static void createAndShowGui() {
Panel2 mainPanel = new Panel2();
JFrame frame = new JFrame("Panel2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
在评论中,Camickr敏锐地指出:
绘制方法应绘制组件的当前状态。通过使用HashMap,您可以引入随机性的可能性。无法保证通过地图的迭代顺序。因此,当新条目添加到地图时,每个Shape的绘制顺序可能会发生变化。一般不是问题,但如果两个随机形状重叠,那么结果就是翻转,这种形状是相互重叠的。
当然,他是完全正确的,因为没有保证HashMap的顺序。幸运的是,变量本身被声明为Map类型,因此为了保持顺序,所有人需要做的是将实际的对象类型从HashMap更改为LinkedHashMap,这是一个每its API的类:
此实现使客户端免受HashMap(和Hashtable)提供的未指定的,通常混乱的排序,而不会导致与TreeMap相关的成本增加。
因此,对于TLDR,请更改:
private Map<Shape, Color> shapeColorMap = new HashMap<>();
到此:
private Map<Shape, Color> shapeColorMap = new LinkedHashMap<>();
修改了颜色计算。
只是为了它的乐趣,它引入Path2D和AffineTransform与MouseListener / MouseMotionListener以允许拖动圆圈:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import javax.swing.*;
@SuppressWarnings("serial")
public class Panel2 extends JPanel {
// preferred size constants
private static final int PREF_W = 600;
private static final int PREF_H = PREF_W;
// map to hold circles and colors
private Map<Shape, Color> shapeColorMap = new LinkedHashMap<>();
public Panel2() {
add(new JButton(new RandomColorAction()));
MyMouse myMouse = new MyMouse();
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
// create *smooth* drawings
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
paintStuff(g2);
}
private void paintStuff(Graphics2D g2) {
// iterate through our map extracting all circles and colors
// and drawing them
for (Entry<Shape, Color> entry : shapeColorMap.entrySet()) {
Shape shape = entry.getKey();
Color color = entry.getValue();
g2.setColor(color);
g2.fill(shape);
}
}
private class MyMouse extends MouseAdapter {
private Entry<Shape, Color> selected = null;
private Path2D path;
private Point p = null;
@Override
public void mousePressed(MouseEvent e) {
Set<Entry<Shape, Color>> entrySet = shapeColorMap.entrySet();
// get Shape pressed
for (Entry<Shape, Color> entry : entrySet) {
if (entry.getKey().contains(e.getPoint())) {
selected = entry;
}
}
if (selected != null) {
path = new Path2D.Double(selected.getKey());
// move it to the top
entrySet.remove(selected);
shapeColorMap.put(path, selected.getValue());
p = e.getPoint();
repaint();
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (selected != null) {
moveSelected(e);
}
selected = null;
}
@Override
public void mouseDragged(MouseEvent e) {
if (selected != null) {
moveSelected(e);
}
}
private void moveSelected(MouseEvent e) {
int x = e.getX() - p.x;
int y = e.getY() - p.y;
p = e.getPoint();
AffineTransform at = AffineTransform.getTranslateInstance(x, y);
path.transform(at);
repaint();
}
}
// listener for our button
private class RandomColorAction extends AbstractAction {
private static final int CIRC_WIDTH = 100;
private Random random = new Random();
private int count = 0;
public RandomColorAction() {
super("Random Circle: 0");
putValue(MNEMONIC_KEY, KeyEvent.VK_R);
}
@Override
public void actionPerformed(ActionEvent e) {
// create our random ellipses
int x = random.nextInt(getWidth() - CIRC_WIDTH);
int y = random.nextInt(getHeight() - CIRC_WIDTH);
Shape shape = new Ellipse2D.Double(x, y, CIRC_WIDTH, CIRC_WIDTH);
// create our random color using HSB for brighter colors
float hue = random.nextFloat();
float saturation = (float) (0.8 + random.nextFloat() * 0.2);
float brightness = (float) (0.8 + random.nextFloat() * 0.2);
Color color = Color.getHSBColor(hue, saturation, brightness);
shapeColorMap.put(shape, color);
// increment count, place items into map, repaint
count++;
putValue(NAME, "Random Circle: " + count);
repaint();
}
}
private static void createAndShowGui() {
Panel2 mainPanel = new Panel2();
JFrame frame = new JFrame("Panel2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
答案 1 :(得分:2)
paintStuff(Graphics g);
多次调用,每次刷新圆形颜色。这是设置颜色的错误位置,您需要在添加圆圈时进行设置。
创建一个java.awt.Color数组作为全局变量
private Color[] circlesColors;
然后只需在actionPerformed(...)
方法中填充此数组。这是带有更改的setup
方法
private void setup() {
count=new Integer(0);
circles=new Ellipse2D.Double[10];
circlesColors = new Color[10]; //Init the colors array to the same size of circles array
button=new JButton(count.toString());
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Random r=new Random();
int highX=getWidth()-100;
int highY=getHeight()-100;
circles[count]=new Ellipse2D.Double(r.nextInt(highX), r.nextInt(highY), 100, 100);
circlesColors[count] = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256)); //Assign random color
count++;
button.setText(count.toString());
}
});
add(button);
}
然后在您的paint(...)
方法
private void paintStuff(Graphics g) {
Graphics2D g2=(Graphics2D) g;
g2.setPaint(Color.RED);
if (count!=0) {
for (int i=0; i<count; i++) {
g2.draw(circles[i]);
g2.setPaint(circlesColors[i]); //Get and set the color associated to the circle
g2.fill(circles[i]);
}
}
}