看来我们的JTextField之旅也到了一个阶段,已经很不错了,现在我们来改造JButton,让那个呆板的Swing看起来舒服一些。
还是先放上完成后的效果图:
普通的状态
鼠标滑过
鼠标按下
和代码:
/** * @(#)RJButton.java 0.1.0 2007-9-11 */ package ruislan.rswing; import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.geom.Arc2D; import java.awt.geom.GeneralPath; import java.awt.geom.RoundRectangle2D; import javax.swing.JButton; /** * Custom JButton * * @version 0.1.0 * @author ruislan <a href="mailto:[email protected]" mce_href="mailto:[email protected]"></a> */ public class RButton extends JButton { private static final long serialVersionUID = 39082560987930759L; public static final Color BUTTON_COLOR1 = new Color(205, 255, 205); public static final Color BUTTON_COLOR2 = new Color(51, 154, 47); // public static final Color BUTTON_COLOR1 = new Color(125, 161, 237); // public static final Color BUTTON_COLOR2 = new Color(91, 118, 173); public static final Color BUTTON_FOREGROUND_COLOR = Color.WHITE; private boolean hover; private int style; public static final int ROUND_RECT = 0; public static final int LEFT_ROUND_RECT = 1; public static final int RIGHT_ROUND_RECT = 2; public static final int BALL = 3; public static final int STAR = 4; public RButton() { this(ROUND_RECT); } public RButton(int style) { this.style = style; if (BALL == style) { setPreferredSize(new Dimension(42, 42)); } else if (STAR == style) { setPreferredSize(new Dimension(42, 42)); } setFont(new Font("system", Font.PLAIN, 12)); setBorderPainted(false); setForeground(BUTTON_COLOR2); setFocusPainted(false); setContentAreaFilled(false); addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { setForeground(BUTTON_FOREGROUND_COLOR); hover = true; repaint(); } @Override public void mouseExited(MouseEvent e) { setForeground(BUTTON_COLOR2); hover = false; repaint(); } }); } @Override protected void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g.create(); int h = getHeight(); int w = getWidth(); float tran = 1F; if (!hover) { tran = 0.3F; } g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); GradientPaint p1; GradientPaint p2; if (getModel().isPressed()) { p1 = new GradientPaint(0, 0, new Color(0, 0, 0), 0, h - 1, new Color(100, 100, 100)); p2 = new GradientPaint(0, 1, new Color(0, 0, 0, 50), 0, h - 3, new Color(255, 255, 255, 100)); } else { p1 = new GradientPaint(0, 0, new Color(100, 100, 100), 0, h - 1, new Color(0, 0, 0)); p2 = new GradientPaint(0, 1, new Color(255, 255, 255, 100), 0, h - 3, new Color(0, 0, 0, 50)); } g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, tran)); GradientPaint gp = new GradientPaint(0.0F, 0.0F, BUTTON_COLOR1, 0.0F, h, BUTTON_COLOR2, true); g2d.setPaint(gp); switch (style) { case ROUND_RECT: { RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(0, 0, w - 1, h - 1, 20, 20); Shape clip = g2d.getClip(); g2d.clip(r2d); g2d.fillRect(0, 0, w, h); g2d.setClip(clip); g2d.setPaint(p1); g2d.drawRoundRect(0, 0, w - 1, h - 1, 20, 20); g2d.setPaint(p2); g2d.drawRoundRect(1, 1, w - 3, h - 3, 18, 18); break; } case LEFT_ROUND_RECT: { RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(0, 0, (w - 1) + 20, h - 1, 20, 20); Shape clip = g2d.getClip(); g2d.clip(r2d); g2d.fillRect(0, 0, w, h); g2d.setClip(clip); g2d.setPaint(p1); g2d.drawRoundRect(0, 0, (w - 1) + 20, h - 1, 20, 20); g2d.setPaint(p2); g2d.drawRoundRect(1, 1, (w - 3) + 20, h - 3, 18, 18); g2d.setPaint(p1); g2d.drawLine(w - 1, 1, w - 1, h); g2d.setPaint(p2); g2d.drawLine(w - 2, 2, w - 2, h - 1); break; } case RIGHT_ROUND_RECT: { RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(-20, 0, (w - 1) + 20, h - 1, 20, 20); Shape clip = g2d.getClip(); g2d.clip(r2d); g2d.fillRect(0, 0, w, h); g2d.setClip(clip); g2d.setPaint(p1); g2d.drawRoundRect(-20, 0, (w - 1) + 20, h - 1, 20, 20); g2d.setPaint(p2); g2d.drawRoundRect(-19, 1, (w - 3) + 20, h - 3, 18, 18); g2d.setPaint(p1); g2d.drawLine(0, 1, 0, h); g2d.setPaint(p2); g2d.drawLine(1, 2, 1, h - 1); break; } case BALL: { Arc2D.Float a2d = new Arc2D.Float(0, 0, w, h, 0, 360, Arc2D.CHORD); Shape clip = g2d.getClip(); g2d.clip(a2d); g2d.fillRect(0, 0, w, h); g2d.setClip(clip); g2d.setPaint(p1); g2d.drawOval(0, 0, w - 1, h - 1); g2d.setPaint(p2); g2d.drawOval(1, 1, w - 3, h - 3); break; } case STAR: { int x = w / 2; int y = h / 2; int r = w / 2; // 计算五个顶点 Point[] ps = new Point[5]; for (int i = 0; i <= 4; i++) { ps[i] = new Point((int) (x - r * Math.sin((i * 72 + 36) * 2 * Math.PI / 360)), (int) (y + r * Math.cos((i * 72 + 36) * 2 * Math.PI / 360))); } GeneralPath star = new GeneralPath(); star.moveTo(ps[3].x, ps[3].y); star.lineTo(ps[0].x, ps[0].y); star.lineTo(ps[2].x, ps[2].y); star.lineTo(ps[4].x, ps[4].y); star.lineTo(ps[1].x, ps[1].y); star.lineTo(ps[3].x, ps[3].y); star.closePath(); Shape clip = g2d.getClip(); g2d.clip(star); g2d.fillRect(0, 0, w, h); g2d.setClip(clip); g2d.setPaint(p1); g2d.draw(star); g2d.setPaint(p2); g2d.draw(star); break; } default: break; } g2d.dispose(); super.paintComponent(g); } }
注意代码中的几个部分:
首先是paintComponent方法中最后一行,我们调用了父类的paintComponent方法,这是因为我们要靠父类来绘制字符,但是父类的这个方法除了绘制字符之外还会绘制其他的,所以我们需要关闭掉其他的(当然我们也可以自己来绘制字符,但是JButton提供了方法为什么不用呢),所以我们在构造方法那里调用了:
setBorderPainted(false);
setFocusPainted(false);
setContentAreaFilled(false);
告诉父类不用绘制边框,不用绘制焦点,不用绘制内容部分,这部分我们自己来搞*o*。
然后就是这一句了g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)告诉绘制API我们需要平滑一点,否则绘制出来会有很多锯齿哟。
接下来的这一句g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,tran))告诉绘图API我们需要绘制一个有透明度的,tran就是透明度(0-1)。
然后就是将边框的边角变直角为圆角,我们绘制一个RoundRectangle2D,这个就是边角都为圆角的方形,然后我们根据这个方形来clip我们的方形,这样方形就被RoundRectangle2D的圆角方形包裹,从而变成了圆角方形。
最后就是绘制外边线和内边线,通过改变内边线和外边线的色变从而造成陷入或者突出效果。
整个JButton改造完毕,如果你能够活用clip的话,你也可以做一个五角星的JButton哟。
上面的是采用集成Jbutton的实现,我们都知道Swing的UI是秉承MVC模式的,下面我们来重写UI层次;
下面重新实现了UI:
package org.corey.main; import java.awt.Color; import java.awt.Graphics; import javax.swing.AbstractButton; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.plaf.basic.BasicButtonUI; public class BlueishButtonUI extends BasicButtonUI { private static Color blueishBackgroundOver = new Color(224, 232, 246); private static Color blueishBorderOver = new Color(152, 180, 226); private static Color blueishBackgroundSelected = new Color(193, 210, 238); private static Color blueishBorderSelected = new Color(49, 106, 197); public BlueishButtonUI() { super(); } public void installUI(JComponent c) { super.installUI(c); AbstractButton button = (AbstractButton) c; button.setRolloverEnabled(true); button.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); } public void paint(Graphics g, JComponent c) { AbstractButton button = (AbstractButton) c; if (button.getModel().isRollover() || button.getModel().isArmed() || button.getModel().isSelected()) { Color oldColor = g.getColor(); if (button.getModel().isSelected()) { g.setColor(blueishBackgroundSelected); } else { g.setColor(blueishBackgroundOver); } g.fillRect(0, 0, c.getWidth() - 1, c.getHeight() - 1); if (button.getModel().isSelected()) { g.setColor(blueishBorderSelected); } else { g.setColor(blueishBorderOver); } g.drawRect(0, 0, c.getWidth() - 1, c.getHeight() - 1); g.setColor(oldColor); } super.paint(g, c); } }
下面JButton设置UI样式:
package org.corey.main; import java.awt.FlowLayout; import javax.swing.JButton; import javax.swing.WindowConstants; public class NewJFrame extends javax.swing.JFrame { private JButton jButton1; private JButton jButton2; public static void main(String[] args) { NewJFrame inst = new NewJFrame(); inst.setVisible(true); } public NewJFrame() { super(); initGUI(); // 设置 UI 来加入不同的绘制方法, 可以切换不同的绘制方法, 例如换肤 jButton1.setUI(new BlueishButtonUI()); } private void initGUI() { try { FlowLayout thisLayout = new FlowLayout(); getContentPane().setLayout(thisLayout); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); { jButton1 = new JButton(); getContentPane().add(jButton1); jButton1.setText("自定义外观,需要UI吗?需要"); } { jButton2 = new JButton(); getContentPane().add(jButton2); jButton2.setText("默认外观"); } pack(); setSize(400, 300); } catch (Exception e) { e.printStackTrace(); } } }
截图: