Java - Custom Shape Panels?
I am working on an application that involves the user requiring to hover over several moving dots on the screen in order to launch specific popups. At the moment, i am listening for mouseMoved
events on the JPanel
onto which the dots are rendered, and then launching the required pop ups whenever the cursor is 开发者_如何学Gowithin a specific distance of a dot.
When i have hundreds of dots - this probably becomes quite expensive.
Wouldnt the ideal solution be to represent my 'dots' as small components and register a mouse listener with each dot?
Does anyone know how i might represent a small ellipse with a JComponent
?
Many thanks
Here is some old code which shows how to create a "round" JButton. I would extend JComponent instead and the important methods to override are paintComponent() and contains():
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
public class RoundButton extends JButton {
public RoundButton(String label) {
super(label);
// These statements enlarge the button so that it
// becomes a circle rather than an oval.
Dimension size = getPreferredSize();
size.width = size.height = Math.max(size.width, size.height);
setPreferredSize(size);
// This call causes the JButton not to paint the background.
// This allows us to paint a round background.
setContentAreaFilled(false);
}
// Paint the round background and label.
protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
// You might want to make the highlight color
// a property of the RoundButton class.
g.setColor(Color.lightGray);
} else {
g.setColor(getBackground());
}
g.fillOval(0, 0, getSize().width-1, getSize().height-1);
// This call will paint the label and the focus rectangle.
super.paintComponent(g);
}
// Paint the border of the button using a simple stroke.
protected void paintBorder(Graphics g) {
g.setColor(getForeground());
g.drawOval(0, 0, getSize().width-1, getSize().height-1);
}
// Hit detection.
Shape shape;
public boolean contains(int x, int y) {
// If the button has changed size, make a new shape object.
if (shape == null || !shape.getBounds().equals(getBounds())) {
shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
}
return shape.contains(x, y);
}
// Test routine.
public static void main(String[] args) {
// Create a button with the label "Jackpot".
JButton button = new RoundButton("Jackpot");
button.setBackground(Color.green);
button.setBounds(0, 0, 100, 100);
JButton button2 = new RoundButton("Jackpot2");
button2.setBackground(Color.red);
button2.setBounds(50, 50, 100, 100);
// Create a frame in which to show the button.
JFrame frame = new JFrame();
frame.getContentPane().setBackground(Color.yellow);
frame.getContentPane().setLayout(null);
frame.getContentPane().add(button);
frame.getContentPane().add(button2);
// frame.getContentPane().setLayout(new FlowLayout());
frame.setSize(200, 200);
frame.setVisible(true);
MouseListener mouseListener = new MouseAdapter() {
public void mouseEntered( MouseEvent e )
{}
public void mouseExited( MouseEvent e )
{}
public void mouseClicked( MouseEvent e )
{
System.out.println( "clicked " );
}
public void mousePressed( MouseEvent e )
{
System.out.println( "pressed " );
}
public void mouseReleased( MouseEvent e )
{
System.out.println( "released " );
}
};
button.addMouseListener( mouseListener );
}
}
This simplifies the hit detection easily since there is no custom code. Also it allows you to control overlapping of compnents easily since you can control the Z-Order of each component.
You write "this probably becomes quite expensive"
Whether you code the "isMouseCloseToDot" method yourself, or whether you use something built into Swing, in either case the work still needs to be performed by the computer to find out whether a dot is activated.
I recommend sticking with your current approach unless you have determined that this approach is indeed too expensive. Do a small test with a couple of hundred dots. Is the response time acceptable?
Not sure which approach is more expensive, but component based approach is definitely easier to implement.
All you have to do is to create your own component, override paint
and contains
methods. Add it to the specific position in the container (using absolute layout or any other depending on your needs). Your listeners will become part of your new component providing components behavior.
From the design and program organization point of view this is much more superior approach.
精彩评论