1)打造输入框的毛玻璃效果:
package org.corey.main; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Font; import java.awt.Insets; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; /** * Custom JTextField. * * @version 0.1.2, 2007-9-8 * @author ruislan <a href="mailto:[email protected]" mce_href="mailto:[email protected]"></a> */ public class RTextField extends JTextField { private static final long serialVersionUID = -3438563085728628986L; private static final Color TIP_COLOR = new Color(255, 255, 225); private static final Color HOVER_BACKGROUND_COLOR = new Color(255, 255, 225); private static final Color BACKGROUND_COLOR = new Color(255, 255, 255); private static final Color HOVER_BORDER_COLOR = new Color(215, 215, 215, 255); private static final Color BORDER_COLOR = new Color(125, 125, 125, 100); private int limit = Integer.MAX_VALUE; private boolean numberOnly; private CoolToolTip numberTip; private CoolToolTip limitTip; private ImageIcon tipIcon; private Border hoverBorder; private Border border; public RTextField() { initComponents(); initEventListeners(); } private void initComponents() { tipIcon = new ImageIcon(RTextField.class.getResource("tip.gif")); numberTip = new CoolToolTip(this, TIP_COLOR, getColumns(), 10); numberTip.setText("aa"); numberTip.setIcon(tipIcon); numberTip.setIconTextGap(10); limitTip = new CoolToolTip(this, TIP_COLOR, getColumns(), 10); limitTip.setIcon(tipIcon); limitTip.setIconTextGap(10); hoverBorder = new CoolBorder(HOVER_BORDER_COLOR, 3); border = BorderFactory.createCompoundBorder(new LineBorder( BORDER_COLOR, 1), new EmptyBorder(new Insets(2, 2, 2, 2))); setBackground(BACKGROUND_COLOR); setBorder(border); } private void initEventListeners() { addKeyListener(new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { char input = e.getKeyChar(); // ESC27 ,Backspace 8 ,Enter 10, Del 127, must ignore boolean ignoreInput = input == (char) KeyEvent.VK_ESCAPE || input == (char) KeyEvent.VK_BACK_SPACE || input == (char) KeyEvent.VK_ENTER || input == (char) KeyEvent.VK_DELETE || (getSelectedText() != null && getSelectedText() .length() > 0); if (ignoreInput) { limitTip.setVisible(false); numberTip.setVisible(false); return; } if (getText().length() + 1 > limit) { Toolkit.getDefaultToolkit().beep(); deleteInputChar(e); limitTip.setVisible(true); return; } else { limitTip.setVisible(false); } if (numberOnly) { if (!Character.isDigit(input)) { numberTip.setVisible(true); Toolkit.getDefaultToolkit().beep(); deleteInputChar(e); } else { numberTip.setVisible(false); } } } private void deleteInputChar(KeyEvent source) { source.setKeyChar((char) KeyEvent.VK_CLEAR); } }); addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { setBorder(hoverBorder); setBackground(HOVER_BACKGROUND_COLOR); repaint(); } @Override public void mouseExited(MouseEvent e) { setBorder(border); setBackground(BACKGROUND_COLOR); repaint(); } }); } public void setMaxTextLength(int limit) { if (limit < 0) { return; } this.limit = limit; limitTip.setText(String.format("aa", limit)); } public int getMaxTextLength() { return limit; } public void setNumberOnly(boolean numberOnly) { this.numberOnly = numberOnly; } public boolean isNumberOnly() { return this.numberOnly; } private class CoolToolTip extends JPanel { private static final long serialVersionUID = 1186230002931874625L; private JLabel label = new JLabel(); private boolean haveShowPlace; private Component attachedComponent; public CoolToolTip(Component attachedComponent, Color fillColor, int borderWidth, int offset) { this.attachedComponent = attachedComponent; label.setBorder(new EmptyBorder(borderWidth, borderWidth, borderWidth, borderWidth)); label.setBackground(fillColor); label.setOpaque(true); label.setFont(new Font("system", 0, 12)); setOpaque(false); this.setBorder(new BalloonBorder(fillColor, offset)); this.setLayout(new BorderLayout()); add(label); setVisible(false); // if the attached component is moved while the balloon tip is // visible, we need to move as well attachedComponent.addComponentListener(new ComponentAdapter() { public void componentMoved(ComponentEvent e) { if (isShowing()) { determineAndSetLocation(); } } }); } private void determineAndSetLocation() { Point location = attachedComponent.getLocation(); setBounds(location.x, location.y - getPreferredSize().height, getPreferredSize().width, getPreferredSize().height); } public void setText(String text) { label.setText(text); } public void setIcon(Icon icon) { label.setIcon(icon); } public void setIconTextGap(int iconTextGap) { label.setIconTextGap(iconTextGap); } public void setVisible(boolean show) { if (show) { determineAndSetLocation(); findShowPlace(); } super.setVisible(show); } private void findShowPlace() { if (haveShowPlace) { return; } // we use the popup layer of the top level container (frame or // dialog) to show the balloon tip // first we need to determine the top level container... Container parent = attachedComponent.getParent(); JLayeredPane layeredPane; while (true) { if (parent instanceof JFrame) { layeredPane = ((JFrame) parent).getLayeredPane(); break; } else if (parent instanceof JDialog) { layeredPane = ((JDialog) parent).getLayeredPane(); break; } parent = parent.getParent(); } layeredPane.add(this, JLayeredPane.POPUP_LAYER); haveShowPlace = true; } } }
setBorder(hoverBorder)会为当鼠标进入textfield的时候加上边框
hoverBorder = new CoolBorder(HOVER_BORDER_COLOR, 3);
package org.corey.main; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import javax.swing.border.Border; /** * Custom Border. * * @version 0.1.2, 2007-9-10 * @author ruislan <a href="mailto:[email protected]" mce_href="mailto:[email protected]"></a> */ public class CoolBorder implements Border { private int thickness; private Insets insets; private Dimension lastComponentSize; private Color color; private Color color2; public CoolBorder(Color color, int thickness) { this.color = color; if (color == null) { this.color = color = Color.gray; } color2 = new Color(210, 210, 210, 0); this.thickness = thickness; } public Insets getBorderInsets(Component c) { Dimension currentComponent = c.getSize(); if (currentComponent.equals(lastComponentSize)) { return insets; } insets = new Insets(thickness, thickness, thickness, thickness); lastComponentSize = currentComponent; return insets; } public boolean isBorderOpaque() { return true; } public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { Graphics2D g2d = (Graphics2D) g.create(); //分别在这个textfield的四边用渐变的颜色画出了模糊的毛边 GradientPaint gp = new GradientPaint(x, y, color, x, y + thickness, color2); g2d.setPaint(gp); g2d.fillRect(x, y, width, thickness); gp = new GradientPaint(x, y + height - thickness - 1, color2, x, y + height, color); g2d.setPaint(gp); g2d.fillRect(x, y + height - thickness - 1, width, thickness); gp = new GradientPaint(x, y, color, x + thickness, y, color2); g2d.setPaint(gp); g2d.fillRect(x, y, thickness, height); gp = new GradientPaint(x + width - thickness - 1, y, color2, x + width, y, color); g2d.setPaint(gp); g2d.fillRect(x + width - thickness - 1, y, thickness, height); g2d.setPaint(color); g2d.drawRect(x, y, width - 1, height - 1); g2d.dispose(); } }
输入校验的提示框,其实是一个有特定的border的Jpanel:
package org.corey.main; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Point; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import javax.swing.Icon; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; /** * A balloon tip which is displayed above the attached component. The balloon * tip uses a <code>JLabel</code> to render its content. * * @author Bernhard Pauler */ public class BalloonTip extends JPanel { private BalloonBorder border; private JLabel label = new JLabel(); private Component attachedComponent; public BalloonTip(Component attachedComponent, Color fillColor, int borderWidth, int offset) { this.attachedComponent = attachedComponent; label.setBorder(new EmptyBorder(borderWidth, borderWidth, borderWidth, borderWidth)); label.setBackground(fillColor); label.setOpaque(true); setBorder(border = new BalloonBorder(fillColor, offset)); setOpaque(false); setLayout(new BorderLayout()); add(label); setVisible(false); // we use the popup layer of the top level container (frame or dialog) // to show the balloon tip // first we need to determine the top level container... Container parent = attachedComponent.getParent(); JLayeredPane layeredPane; while (true) { if (parent instanceof JFrame) { layeredPane = ((JFrame) parent).getLayeredPane(); break; } else if (parent instanceof JDialog) { layeredPane = ((JDialog) parent).getLayeredPane(); break; } parent = parent.getParent(); } layeredPane.add(this, JLayeredPane.POPUP_LAYER); // if the attached component is moved while the balloon tip is visible, // we need to move as well attachedComponent.addComponentListener(new ComponentAdapter() { public void componentMoved(ComponentEvent e) { if (isShowing()) { determineAndSetLocation(); } } }); } private void determineAndSetLocation() { Point location = attachedComponent.getLocation(); setBounds(location.x, location.y - getPreferredSize().height, getPreferredSize().width, getPreferredSize().height); } public void setText(String text) { label.setText(text); } public void setIcon(Icon icon) { label.setIcon(icon); } public void setIconTextGap(int iconTextGap) { label.setIconTextGap(iconTextGap); } public void setVisible(boolean show) { if (show) { determineAndSetLocation(); } super.setVisible(show); } }
他的border用画笔画出了语气的形状:
package org.corey.main; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; import javax.swing.border.Border; /** * Border which renders a balloon. * * @author Bernhard Pauler */ public class BalloonBorder implements Border { private Dimension lastComponentSize; private Insets insets = new Insets(0, 0, 0, 0); private Color fillColor; private int offset; /** * Creates a balloon border. * * @param fillColor color which is used to fill the balloon (currently only the triangular tip) * @param offset number of pixels between component and balloon body */ public BalloonBorder(Color fillColor, int offset) { this.fillColor = fillColor; this.offset = offset; } public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { width -= insets.left + insets.right; height -= insets.top + insets.bottom; Point iPoint = new Point(); // initial point Point ePoint = new Point(); // end point iPoint.x = x; iPoint.y = y; ePoint.x = x + width + 1; ePoint.y = y; printPoints(iPoint, ePoint); g.drawLine(iPoint.x, iPoint.y, ePoint.x, ePoint.y); iPoint.setLocation(ePoint); ePoint.x = x + width + 1; ePoint.y = y + height + 1; printPoints(iPoint, ePoint); g.drawLine(iPoint.x, iPoint.y, ePoint.x, ePoint.y); iPoint.setLocation(ePoint); ePoint.x = x + offset*2; ePoint.y = y + height + 1; printPoints(iPoint, ePoint); g.drawLine(iPoint.x, iPoint.y, ePoint.x, ePoint.y); iPoint.setLocation(ePoint); ePoint.x = x + offset; ePoint.y = y + height + offset + 1; printPoints(iPoint, ePoint); g.drawLine(iPoint.x, iPoint.y, ePoint.x, ePoint.y); iPoint.setLocation(ePoint); ePoint.x = x + offset; ePoint.y = y + height + 1; printPoints(iPoint, ePoint); g.drawLine(iPoint.x, iPoint.y, ePoint.x, ePoint.y); iPoint.setLocation(ePoint); ePoint.x = x; ePoint.y = y + height + 1; printPoints(iPoint, ePoint); g.drawLine(iPoint.x, iPoint.y, ePoint.x, ePoint.y); iPoint.setLocation(ePoint); ePoint.x = x; ePoint.y = y; printPoints(iPoint, ePoint); g.drawLine(iPoint.x, iPoint.y, ePoint.x, ePoint.y); int[] xPoints = {x+offset+1, x+offset*2/*-1?*/, x+offset+1 }; int[] yPoints = {y+height+1, y+height+1 , y+height+offset /*-1?*/}; printTrianglePoints(xPoints, yPoints); g.setColor(fillColor); g.fillPolygon(xPoints, yPoints, 3); } private void printPoints(Point iPoint, Point ePoint) { // System.out.println(iPoint.x + "/" + iPoint.y + "->" + ePoint.x + "/" + ePoint.y); } private void printTrianglePoints(int[] xPoints, int[] yPoints) { // System.out.println("Triangle points..."); // for (int i = 0; i < xPoints.length; i++) { // System.out.println(xPoints[i] + "/" + yPoints[i]); // } } public Insets getBorderInsets(Component c) { Dimension currentComponent = c.getSize(); if (currentComponent.equals(lastComponentSize)) { return insets; } insets = new Insets(1, 1, offset + 1 , 1); lastComponentSize = currentComponent; return insets; } public boolean isBorderOpaque() { return true; } }
截图如下: