问题
I am a student and having trubble making one of my projects this is only one bit of what my final project will actual be like but i am trying to compartmentalize it as much as possible.
the specific problem I have is related to creating a java application that displays a frame with a button allowing the user to create multiple balls on screen and then have you be able to select each one by clicking on them.
I have tryed to add small modifications but with non of them working i removed it so that it gives you more freedom when finding a solution.
Here is the code of Simulation
class:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Simulation {
int noOfBallClicks = 0;
Simulation() {
buildTheGUI();
}
JFrame frame = new JFrame();
JFrame frame2 = new JFrame();
JPanel panal = new JPanel();
JButton add = new JButton("add a new object");
public void buildTheGUI() {
frame.setVisible(true);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panal);
panal.add(add);
add.addActionListener(new ButtonClickHandler());
}
public static void main(String[] args) {
new Simulation();
}
class ButtonClickHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
noOfBallClicks = noOfBallClicks++;
frame.add(new Ball());
frame.validate();
}
}
}
Here is the code of Ball
class:
import javax.swing.*;
import java.awt.*;
import java.util.Random;
public class Ball extends JPanel {
private int x;
private int y;
private int w;
private int h;
Ball() {
this.x = 200;
this.y = 200;
this.w = 100;
this.h = 100;
}
Ball(int a) {
Random rand = new Random();
this.w = 100;
this.h = 100;
this.x = rand.nextInt(300);
this.y = rand.nextInt(300);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillOval(x, y, h, w);
}
}
回答1:
the specific problem I have is related to creating a java application that displays a frame with a button allowing the user to create multiple balls on screen and then have you be able to select each one by clicking on them.
I have tryed to add small modifications but with non of them working i removed it so that it gives you more freedom when finding a solution.
You never mention what is wrong/what you want to achieve... Besides the above and title: selecting objects, that have been repainted
However I see a few problems in the code given:
1) Dont set JFrame
visible until all components have been added (or you will have problems such as content not being visible)
2) Dont call setSize
on JFrame
rather override getPreferredSize()
of JPanel
and return Dimension
s which fit the drawings on Graphics
object and/or use an appropriate LayoutManager
. Than we can call pack()
instead of setSize(...)
on JFrame
.
3) Swing components should be created and manipulated on Event Dispatch Thread via SwingUtilities.invokeLater(Runnable r)
block. Read Concurrency in Swing for more.
4) When you use validate()
it should be followed by a call to repaint()
to reflect changes made.
5) You are also using a default JFrame
Layout of BorderLayout
to which you add a panel, and than balls (using the button listener) by default BorderLayout
will add to its BorderLayout.CENTER
so on each call to JFrame#add(Component c)
you are replacing the old ball/JPanel
with another.
6) As it stands using JPanel
like you have if 2 Ball
s end up in an overlapping position the top Ball
and its JPanel
will cover the bottom Ball
... You need a transparent panel i.e JComponent#setOpaque(false)
.
7) When I do custom painting, I rarely use JComponent
or its extensions. I rather create an Object
which will act as virtual representation of what I need to be drawn/displayed or whatever (maybe personal preference). These objects will than be visualized in my JPanel
paintComponent(..)
which will call their draw(..)
method passing the Graphics
object of the JPanel
to each Ball
which will than draw itself according to the the fields data.
Here is a short example I made (with the above in mind):
All green balls
have been selected i.e clicked on, while the red has not.

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;
}
}
来源:https://stackoverflow.com/questions/14911958/java-selecting-objects-that-have-been-repainted