JButton大改造之二 - 五芒星之辉
嗯,BeanSoft的话很有道理,令我敬佩,也许是昨天在下对那个“更好的”三个字感到一时愤慨,所以看到UI就自己扩大了问题,想到迎合LookAndFeel上面去了,在此说句对不起了。你的回帖里面偏重于从整个组件的设计和重用性上,我的文章主要讲的是如何将2D绘制和组件的绘制结合起来,看客如果既了解了如何绘制自己想要的组件,又能设计得体,重用性高的话也算是对我抛砖引玉的欣慰了。
多话不说,接着昨天的,现在我们来试想一下做一个MP3的播放软件上的几个播放按钮,“上一首”是左边有圆顶角而右边没有的方形按钮,“下一首”是右边有圆顶角而左边没有的方形按钮,而播放和暂停是一个圆形的按钮,再放上一个五角星的按钮来评分,现在我们来绘制他们(当然我们还有一个解决方案为每个Button换成图片,每个Button得有三张:普通状态,划过,按下,不过这不是重点)。还是先放上图片:
和代码:
/**
* @(#)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]"/>
*/
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);
}
}
* @(#)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]"/>
*/
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);
}
}
这个代码的其他地方我就不多说了,今天主要是讲一下如何来clip内容,从而弄出我们想要的按钮形状(当然其他组件也可以)
如图所示,假设我们的按钮是黑色的框,我们想要的是红色的框,那么我们首先绘出我们想要的Shape,然后得到这个按钮的Shape,然后进行合并剪裁,也就是说将两个Shape合起来,然后交集部分留下,其余的去除,这样就得到了我们所想要的图形(五角星那个图我们对五角星进行了封闭closePath)。
图示:
我们还可以通过几个Area进行合并图形,反剪等等操作来勾勒我们想要的图形,从而勾画组件的图形,如果你有闲情逸致的话,也有美感和足够的素材的话可以写一个StarCraft或者War3屏幕下角的操作区哟。