How to draw the component focus?
Hi, all.
When I use JBuilder to write a Swing application,
I can put a lot of swing component on the screen.
And I select one or many of them.
There will be focus point over the swing component.
Now, I want to write a function like that.
I try to use a border to paint the focus points.
But I didn't expected the result.
Can anybody help me?
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.border.AbstractBorder;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.event.MouseInputAdapter;
publicclass FocusBorderextends AbstractBorder{
public FocusBorder(){
super();
// TODO Auto-generated constructor stub
}
/**
* @param args
*/
publicstaticvoid main(String[] args){
final MouseInputAdapter _mouseMonitor =new MouseInputAdapter(){
publicvoid mouseClicked(MouseEvent e){
System.out.println("x:" + e.getX() +",y" + e.getY());
}
};
JFrame frame =new JFrame();
frame.getContentPane().setLayout(null);
JTextField text =new JTextField("BBB");
text.setBounds(10, 110, 100, 50);
text.setBorder(new CompoundBorder(new FocusBorder(), text.getBorder()));
JButton button =new JButton("AAA");
button.setBounds(10, 10, 100, 50);
button.setBorder(new FocusBorder());
button.addMouseListener(_mouseMonitor);
button.addMouseMotionListener(_mouseMonitor);
frame.getContentPane().add(button);
frame.getContentPane().add(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
publicvoid paintBorder(Component c, Graphics g,int x,int y,int width,
int height){
// TODO Auto-generated method stub
super.paintBorder(c, g, x, y, width, height);
Point2D[] _focusPoints =new Point2D[8];
_focusPoints[0] =new Point2D.Double(x, y);
_focusPoints[1] =new Point2D.Double(x + (width / 2), y);
_focusPoints[2] =new Point2D.Double(x + width, y);
_focusPoints[3] =new Point2D.Double(x + width, y + (height / 2));
_focusPoints[4] =new Point2D.Double(x + width, y + height);
_focusPoints[5] =new Point2D.Double(x + (width / 2), y + height);
_focusPoints[6] =new Point2D.Double(x, y + height);
_focusPoints[7] =new Point2D.Double(x, y + (height / 2));
Graphics2D dc = (Graphics2D) g.create();
dc.setColor(Color.BLACK);
for (int i = 0; i < 8; i++){
dc.fill(this.getControlPoint(_focusPoints[i]));
}
}
/**
* ...method getControlPoint documentation comment...
*
* @Version 1.00 31 Oct 2005
* @Author Stanley Lai
*/
protected Shape getControlPoint(Point2D p){
// Create a small square around the given point.
int side = 4;
returnnew Rectangle.Double(p.getX() - side / 2, p.getY() - side / 2,
side, side);
}
public Insets getBorderInsets(Component c, Insets insets){
// TODO Auto-generated method stub
return this.getBorderInsets(c);
}
public Insets getBorderInsets(Component c){
// TODO Auto-generated method stub
returnnew Insets(1, 1, 1, 1);
}
publicboolean isBorderOpaque(){
// TODO Auto-generated method stub
returnfalse;
}
}
Hi, KPSeal.
Your help solved my problem. Thank you.
But I have a new one.
When I put the FocusBorder in the JTextField, there are four write lines there.
I don't know how it happend. I have already overrided the isBorderOpaque() and let it return false. But it doesn't seem to work.
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.border.AbstractBorder;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
import javax.swing.event.MouseInputAdapter;
public class FocusBorder extends AbstractBorder {
int side = 4;
public FocusBorder() {
super();
// TODO Auto-generated constructor stub
}
/**
* @param args
*/
public static void main(String[] args) {
final MouseInputAdapter _mouseMonitor = new MouseInputAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("x:" + e.getX() + ",y" + e.getY());
}
};
JFrame frame = new JFrame();
frame.getContentPane().setLayout(null);
JTextField text = new JTextField("BBB");
text.setBounds(10, 110, 100, 50);
text.setBorder(new CompoundBorder(new FocusBorder(), text.getBorder()));
JButton button = new JButton("AAA");
button.setBounds(10, 10, 100, 50);
button.setBorder(new CompoundBorder(new FocusBorder(), new BevelBorder(
BevelBorder.RAISED)));
button.addMouseListener(_mouseMonitor);
button.addMouseMotionListener(_mouseMonitor);
frame.getContentPane().add(button);
frame.getContentPane().add(text);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setVisible(true);
}
public void paintBorder(Component c, Graphics g, int x, int y, int width,
int height) {
Insets insets = this.getBorderInsets(c);
Point2D[] _focusPoints = new Point2D[8];
_focusPoints[0] = new Point2D.Double(x, y);
_focusPoints[1] = new Point2D.Double(x + ((width - insets.right) / 2), y);
_focusPoints[2] = new Point2D.Double(x + width - insets.right, y);
_focusPoints[3] = new Point2D.Double(x + width - insets.right, y
+ ((height - insets.bottom) / 2));
_focusPoints[4] = new Point2D.Double(x + width - insets.right, y
+ height - insets.bottom);
_focusPoints[5] = new Point2D.Double(x + ((width - insets.right) / 2), y + height
- insets.bottom);
_focusPoints[6] = new Point2D.Double(x, y + height - insets.bottom);
_focusPoints[7] = new Point2D.Double(x, y + ((height - insets.bottom) / 2));
Graphics2D dc = (Graphics2D) g.create();
dc.setColor(Color.BLACK);
for (int i = 0; i < 8; i++) {
dc.fill(this.getControlPoint(_focusPoints[i]));
}
}
/**
* ...method getControlPoint documentation comment...
*
* @Version 1.00 31 Oct 2005
* @Author Stanley Lai
*/
protected Shape getControlPoint(Point2D p) {
// Create a small square around the given point.
return new Rectangle.Double(p.getX(), p.getY(), side, side);
}
public Insets getBorderInsets(Component c, Insets insets) {
// TODO Auto-generated method stub
return this.getBorderInsets(c);
}
public Insets getBorderInsets(Component c) {
// TODO Auto-generated method stub
return new Insets(side, side, side, side);
}
public boolean isBorderOpaque() {
// TODO Auto-generated method stub
return false;
}
}
The problem with the "white lines" is that the component draws its background right up to the edges of the component. Since you've got a transparent border you can see the background colour where there's no border.
It looks like you're trying to add move/size controls to a component. If that's the case then I don't think a border is the most appropriate way of doing that. I'd try adding control points to the frame's glass pane and getting those to respond to mouse events. They'll also need to track changes in the size/position of the component they're controlling (using ComponentListener).
I've put some code below for something I knocked together to demonstrate this approach. If it's not what you're after then just ignore it!
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;
import javax.swing.event.MouseInputListener;
public class FocusComponent extends JComponent implements FocusListener, ComponentListener {
private Control[][] controls;
private Component comp;
private int size = 5;
public FocusComponent() {
super();
controls = new Control[3][3];
controls[0][0] = new Control("NW", Cursor.NW_RESIZE_CURSOR, size);
controls[0][1] = new Control("N", Cursor.N_RESIZE_CURSOR, size);
controls[0][2] = new Control("NE", Cursor.NE_RESIZE_CURSOR, size);
controls[1][0] = new Control("W", Cursor.W_RESIZE_CURSOR, size);
controls[1][1] = new Control("C", Cursor.MOVE_CURSOR, size);
controls[1][2] = new Control("E", Cursor.E_RESIZE_CURSOR, size);
controls[2][0] = new Control("SW", Cursor.SW_RESIZE_CURSOR, size);
controls[2][1] = new Control("S", Cursor.S_RESIZE_CURSOR, size);
controls[2][2] = new Control("SE", Cursor.SE_RESIZE_CURSOR, size);
setLayout(new GridBagLayout());
Insets insets = new Insets(0, 0, 0, 0);
add(controls[0][0], new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, insets, 0, 0));
add(controls[0][1], new GridBagConstraints(1, 0, 1, 1, 1, 1, GridBagConstraints.NORTH, GridBagConstraints.NONE, insets, 0, 0));
add(controls[0][2], new GridBagConstraints(2, 0, 1, 1, 1, 1, GridBagConstraints.NORTHEAST, GridBagConstraints.NONE, insets, 0, 0));
add(controls[1][0], new GridBagConstraints(0, 1, 1, 1, 1, 1, GridBagConstraints.WEST, GridBagConstraints.NONE, insets, 0, 0));
add(controls[1][1], new GridBagConstraints(1, 1, 1, 1, 1, 1, GridBagConstraints.CENTER, GridBagConstraints.NONE, insets, 0, 0));
add(controls[1][2], new GridBagConstraints(2, 1, 1, 1, 1, 1, GridBagConstraints.EAST, GridBagConstraints.NONE, insets, 0, 0));
add(controls[2][0], new GridBagConstraints(0, 2, 1, 1, 1, 1, GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, insets, 0, 0));
add(controls[2][1], new GridBagConstraints(1, 2, 1, 1, 1, 1, GridBagConstraints.SOUTH, GridBagConstraints.NONE, insets, 0, 0));
add(controls[2][2], new GridBagConstraints(2, 2, 1, 1, 1, 1, GridBagConstraints.SOUTHEAST, GridBagConstraints.NONE, insets, 0, 0));
}
public void install(Component comp) {
comp.addFocusListener(this);
comp.addComponentListener(this);
if (comp.hasFocus()) {
updateControls(comp);
}
}
public void uninstall(Component comp) {
comp.removeFocusListener(this);
comp.removeComponentListener(this);
if (this.comp == comp) {
updateControls(null);
}
}
public void focusGained(FocusEvent e) {
updateControls(e.getComponent());
}
public void focusLost(FocusEvent e) {
updateControls(null);
}
public void componentResized(ComponentEvent e) {
if (e.getSource() == comp) {
updateControls(comp);
}
}
public void componentMoved(ComponentEvent e) {
if (e.getSource() == comp) {
updateControls(comp);
}
}
public void componentShown(ComponentEvent e) {
if (e.getSource() == comp) {
updateControls(comp);
}
}
public void componentHidden(ComponentEvent e) {
if (e.getSource() == comp) {
updateControls(comp);
}
}
protected void updateControls(Component controlledComponent) {
comp = controlledComponent;
if ((comp == null) || !comp.isVisible()) {
setVisible(false);
} else {
Rectangle bounds = SwingUtilities.convertRectangle(comp.getParent(), comp.getBounds(), getParent());
bounds.x -= size / 2;
bounds.y -= size / 2;
bounds.width += (size / 2) * 2;
bounds.height += (size / 2) * 2;
setBounds(bounds);
setVisible(true);
}
}
public static void main(String[] args) {
FocusComponent focusComponent = new FocusComponent();
JButton button = new JButton("Controlled");
JTextField text = new JTextField("Controlled");
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Setup the glass pane to be visible and support the control component
Container glassPane = (Container) frame.getGlassPane();
glassPane.setLayout(null);
glassPane.add(focusComponent);
glassPane.setVisible(true);
// Setup the frame's layout
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(button);
frame.getContentPane().add(text);
frame.getContentPane().add(new JButton("Not Controlled"));
// Should install these after the focus component is installed on the glass pane
focusComponent.install(button);
focusComponent.install(text);
frame.pack();
frame.setVisible(true);
}
/**
* A control point for a component - the action of which is yet to be implemented!
*/
private class Control extends JComponent implements MouseInputListener {
public Control(String name, int cursor, int size) {
setName(name);
setCursor(Cursor.getPredefinedCursor(cursor));
addMouseListener(this);
addMouseMotionListener(this);
setPreferredSize(new Dimension(size, size));
setBorder(new LineBorder(Color.BLACK));
setBackground(Color.BLUE);
}
protected void paintComponent(Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
System.out.println("Control point pressed: " + getName() + " for component: " + comp.getClass());
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) {
System.out.println("Control point dragged: " + getName() + " for component: " + comp.getClass());
}
public void mouseMoved(MouseEvent e) {
}
}
}
Hope this helps.