随笔 - 18  文章 - 96  trackbacks - 0
<2007年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456


常用链接

留言簿(4)

随笔档案

相册

我的兄弟们

搜索

  •  

最新评论

阅读排行榜

评论排行榜

嗯,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:z17520@126.com"/>
 
*/
public class RButton extends JButton {
    
private static final long serialVersionUID = 39082560987930759L;
    
public static final Color BUTTON_COLOR1 = new Color(205255205);
    
public static final Color BUTTON_COLOR2 = new Color(5115447);
    
// 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(4242));
        } 
else if (STAR == style) {
            setPreferredSize(
new Dimension(4242));
        }
        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(00new Color(000), 0, h - 1,
                    
new Color(100100100));
            p2 
= new GradientPaint(01new Color(00050), 0, h - 3,
                    
new Color(255255255100));
        } 
else {
            p1 
= new GradientPaint(00new Color(100100100), 0, h - 1,
                    
new Color(000));
            p2 
= new GradientPaint(01new Color(255255255100), 0,
                    h 
- 3new Color(00050));
        }
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
                tran));
        GradientPaint gp 
= new GradientPaint(0.0F0.0F, BUTTON_COLOR1, 0.0F,
                h, BUTTON_COLOR2, 
true);
        g2d.setPaint(gp);
        
switch (style) {
        
case ROUND_RECT: {
            RoundRectangle2D.Float r2d 
= new RoundRectangle2D.Float(00,
                    w 
- 1, h - 12020);
            Shape clip 
= g2d.getClip();
            g2d.clip(r2d);
            g2d.fillRect(
00, w, h);
            g2d.setClip(clip);
            g2d.setPaint(p1);
            g2d.drawRoundRect(
00, w - 1, h - 12020);
            g2d.setPaint(p2);
            g2d.drawRoundRect(
11, w - 3, h - 31818);
            
break;
        }
        
case LEFT_ROUND_RECT: {
            RoundRectangle2D.Float r2d 
= new RoundRectangle2D.Float(00,
                    (w 
- 1+ 20, h - 12020);
            Shape clip 
= g2d.getClip();
            g2d.clip(r2d);
            g2d.fillRect(
00, w, h);
            g2d.setClip(clip);
            g2d.setPaint(p1);
            g2d.drawRoundRect(
00, (w - 1+ 20, h - 12020);
            g2d.setPaint(p2);
            g2d.drawRoundRect(
11, (w - 3+ 20, h - 31818);
            g2d.setPaint(p1);
            g2d.drawLine(w 
- 11, w - 1, h);
            g2d.setPaint(p2);
            g2d.drawLine(w 
- 22, w - 2, h - 1);
            
break;
        }
        
case RIGHT_ROUND_RECT: {
            RoundRectangle2D.Float r2d 
= new RoundRectangle2D.Float(-200,
                    (w 
- 1+ 20, h - 12020);
            Shape clip 
= g2d.getClip();
            g2d.clip(r2d);
            g2d.fillRect(
00, w, h);
            g2d.setClip(clip);
            g2d.setPaint(p1);
            g2d.drawRoundRect(
-200, (w - 1+ 20, h - 12020);
            g2d.setPaint(p2);
            g2d.drawRoundRect(
-191, (w - 3+ 20, h - 31818);
            g2d.setPaint(p1);
            g2d.drawLine(
010, h);
            g2d.setPaint(p2);
            g2d.drawLine(
121, h - 1);
            
break;
        }
        
case BALL: {
            Arc2D.Float a2d 
= new Arc2D.Float(00, w, h, 0360, Arc2D.CHORD);
            Shape clip 
= g2d.getClip();
            g2d.clip(a2d);
            g2d.fillRect(
00, w, h);
            g2d.setClip(clip);
            g2d.setPaint(p1);
            g2d.drawOval(
00, w - 1, h - 1);
            g2d.setPaint(p2);
            g2d.drawOval(
11, 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(
00, 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屏幕下角的操作区哟。

posted on 2007-09-12 13:36 ruislan 阅读(2293) 评论(11)  编辑  收藏

FeedBack:
# re: JButton大改造之二 - 五芒星之辉 2007-09-12 13:40 darkhe
再顶。  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-09-12 15:20 交口称赞
不错,还能写出空心按钮。  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-09-12 16:56 wqq
版主:
把测试代码放出来吧。谢谢。  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-09-12 19:35 千里冰封
太牛了,楼主,以后我会经常光顾你的blog
你SWING研究的不错哦  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-09-13 08:46 zht
现在做Swing的很少了,赞一个
顺便问一下,工作就是做这个?  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-09-13 09:30 ruislan
NO、NO、NO,我的工作是JavaEE,天天都伺候着Spring、Hibernate、SpringMVC、DWR……  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-09-13 09:34 zht
@ruislan
呵呵,我现在天天做,感觉越做选择面越窄。。。  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-09-13 10:00 ruislan
一般人天天都做了一个东西,即便是再喜欢久而久之也会产生审美疲劳,唉。
例如Hibernate吧,第一次接触它就喜欢上了ORM,那个时候还在上大学,然后天天就捣鼓这个,课也不上,兴致高昂得连什么hbm文件,事务之类都是亲历亲为,但是自从工作就是跟它打交道的不久之后,就开始用生成工具来生成hbm,然后不久之后开始用AppFuse了,就连hibernate那几个CRUD操作长什么样都不知道了。  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2007-10-22 16:41 Eastsun
看了下楼主改造的JButton,效果确实不错.
不过还有个小小的缺陷:button显示的形状虽然变了,但其接受鼠标事件的范围还是原来那个矩形框.
譬如那个五角星button,理想的效果应该是鼠标放到五角星里面,button才会做出各种反应,但楼主的却不是这样.
解决方法也很简单,复写父类的boolean contains(int x,int y)方法,在应该起效果的地方返回ture就可以了.  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2008-01-19 17:07 hanjs
问个问题

frame.setUndecorated(true);

怎么增加frame的拖动和可变大小?

我想实现千千静听那样的3个窗口合在一起的  回复  更多评论
  
# re: JButton大改造之二 - 五芒星之辉 2008-01-27 17:00 hanjs
按钮改完可以改变形状?

可改panel后,还需要怎么处理frame才能支持呢?

我现在是改变panel的形状后,如使用圆角矩形后(加到frame后),可是上面的两个角显示不了,下面的角可以显示,但是圆角外默认是白色,不能实现理想的形状!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: