我遇到的具体问题与创建一个 java 应用程序有关,该应用程序显示一个带有按钮的框架,允许用户在屏幕上创建多个球,然后您可以通过单击它们来选择每个球。
我尝试添加一些小的修改,但没有一个可以工作,我删除了它,以便在找到解决方案时给你更多的自由。
你从来没有提到什么是错的/你想要实现什么......除了上面和标题:选择对象,已经重新绘制
但是我在给出的代码中看到了一些问题:
JFrame
1)在所有组件都添加完之前不要设置可见(否则会出现内容不可见等问题)
2)不要调用setSize
而JFrame
不是覆盖getPreferredSize()
和JPanel
返回Dimension
适合对象上的图纸Graphics
和/或使用适当的LayoutManager
. 比我们可以调用pack()
而不是setSize(...)
on JFrame
。
3) Swing 组件应该通过块在Event Dispatch Thread上创建和操作。阅读 Swing 中的并发了解更多信息。SwingUtilities.invokeLater(Runnable r)
4)当你使用validate()
它时,应该跟着一个调用repaint()
来反映所做的更改。
5)您还使用了一个默认JFrame
布局,BorderLayout
您向其中添加了一个面板,并且默认情况下,球(使用按钮侦听器)BorderLayout
将添加到其BorderLayout.CENTER
上,因此每次调用JFrame#add(Component c)
您都将旧球/替换为JPanel
另一个。
6)JPanel
如果 2 Ball
s 最终处于重叠位置Ball
,则它会像您一样使用,顶部JPanel
将覆盖底部Ball
......您需要一个透明面板,即JComponent#setOpaque(false)
.
7)当我做自定义绘画时,我很少使用JComponent
或其扩展。我宁愿创建一个虚拟表示我需要绘制/显示的内容或其他内容(可能是个人喜好)Object
。这些对象将在 my中可视化,它将调用它们的方法,将对象传递给每个对象,然后根据字段数据绘制自己。JPanel
paintComponent(..)
draw(..)
Graphics
JPanel
Ball
这是我制作的一个简短示例(考虑到上述内容):
所有绿色balls
都被选中,即点击,而红色没有。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
final DrawPanel drawPanel = new DrawPanel();
drawPanel.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent me) {
super.mouseClicked(me);
for (Ball b : drawPanel.getBalls()) {//iterate through each ball
if (b.getBounds().contains(me.getPoint())) {//get the ball bounds and check if mouse click was within its bounds
if (!b.isSelected()) {//check if ball has been clicked on
b.setSelected(true);
} else {
b.setSelected(false);
}
drawPanel.repaint();//so ball color change will be shown
}
}
}
});
JPanel controlPanel = new JPanel();
JButton createBallButton = new JButton("Add ball");
createBallButton.addActionListener(new ActionListener() {
Random rand = new Random();
private int counter = 1;
public void actionPerformed(ActionEvent e) {
int ballRadius = 10;
int x = rand.nextInt(drawPanel.getWidth());
int y = rand.nextInt(drawPanel.getHeight());
//check that we dont go offscreen by subtarcting its radius unless its x and y are not bigger than radius
if (y > ballRadius) {
y -= ballRadius;
}
if (x > ballRadius) {
x -= ballRadius;
}
drawPanel.addBall(new Ball(x, y, ballRadius, counter));//add ball to panel to be drawn
counter++;//increase the ball number
}
});
final JTextArea jtf = new JTextArea(5, 10);
jtf.setEditable(false);
JButton printSelectedBallButton = new JButton("Print selected balls");
printSelectedBallButton.addActionListener(new ActionListener() {
Random rand = new Random();
private int counter = 1;
public void actionPerformed(ActionEvent e) {
jtf.setText("");
for (Ball b : drawPanel.getBalls()) {
if (b.isSelected()) {
jtf.append("Selected: " + b.getNumber() + "\n");
}
}
}
});
controlPanel.add(createBallButton);
controlPanel.add(printSelectedBallButton);
JScrollPane jsp = new JScrollPane(jtf);
controlPanel.add(jsp);
frame.add(drawPanel);
frame.add(controlPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Test();
}
});
}
}
class DrawPanel extends JPanel {
ArrayList<Ball> balls = new ArrayList<>();
public void addBall(Ball b) {
balls.add(b);
repaint();
}
public ArrayList<Ball> getBalls() {
return balls;
}
@Override
protected void paintComponent(Graphics grphcs) {
super.paintComponent(grphcs);
Graphics2D g2d = (Graphics2D) grphcs;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Ball ball : balls) {
ball.draw(g2d);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
class Ball {
private Color color;
private int x, y;
private int radius;
private final int number;
private boolean selected;
Ball(int x, int y, int radius, int counter) {
this.x = x;
this.y = y;
this.radius = radius;
this.number = counter;
selected = false;
this.color = Color.RED;//default color of unselected ball
}
public void draw(Graphics2D g2d) {
Color prevColor = g2d.getColor();
g2d.drawString(number + "", x + radius, y + radius);//draw the number of ball
g2d.setColor(color);
g2d.fillOval(x, y, radius, radius);
g2d.setColor(prevColor);
}
public Rectangle2D getBounds() {
return new Rectangle2D.Double(x, y, radius, radius);
}
public void setSelected(boolean selected) {
this.selected = selected;
if (selected) {
color = Color.GREEN;
} else {
color = Color.RED;
}
}
boolean isSelected() {
return selected;
}
int getNumber() {
return number;
}
}