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


常用链接

留言簿(4)

随笔档案

相册

我的兄弟们

搜索

  •  

最新评论

阅读排行榜

评论排行榜

看来我们的JTextField之旅也到了一个阶段,已经很不错了,现在我们来改造JButton,让那个呆板的Swing看起来舒服一些。

还是先放上完成后的效果图:

普通的状态


鼠标滑过


鼠标按下

和代码:
  1 /**
  2  * @(#)RJButton.java  0.1.0  2007-9-11
  3  */
  4 package ruislan.rswing;
  5 
  6 import java.awt.AlphaComposite;
  7 import java.awt.Color;
  8 import java.awt.Font;
  9 import java.awt.GradientPaint;
 10 import java.awt.Graphics;
 11 import java.awt.Graphics2D;
 12 import java.awt.RenderingHints;
 13 import java.awt.Shape;
 14 import java.awt.event.MouseAdapter;
 15 import java.awt.event.MouseEvent;
 16 import java.awt.geom.RoundRectangle2D;
 17 
 18 import javax.swing.JButton;
 19 
 20 /**
 21  * Custom JButton
 22  * 
 23  * @version 0.1.0
 24  * @author ruislan <a href="mailto:z17520@126.com"/>
 25  */
 26 public class RButton extends JButton {
 27     private static final long serialVersionUID = 39082560987930759L;
 28     public static final Color BUTTON_COLOR1 = new Color(205255205);
 29     public static final Color BUTTON_COLOR2 = new Color(5115447);
 30     // public static final Color BUTTON_COLOR1 = new Color(125, 161, 237);
 31     // public static final Color BUTTON_COLOR2 = new Color(91, 118, 173);
 32     public static final Color BUTTON_FOREGROUND_COLOR = Color.WHITE;
 33     private boolean hover;
 34 
 35     public RButton() {
 36         setFont(new Font("system", Font.PLAIN, 12));
 37         setBorderPainted(false);
 38         setForeground(BUTTON_COLOR2);
 39         setFocusPainted(false);
 40         setContentAreaFilled(false);
 41         addMouseListener(new MouseAdapter() {
 42             @Override
 43             public void mouseEntered(MouseEvent e) {
 44                 setForeground(BUTTON_FOREGROUND_COLOR);
 45                 hover = true;
 46                 repaint();
 47             }
 48 
 49             @Override
 50             public void mouseExited(MouseEvent e) {
 51                 setForeground(BUTTON_COLOR2);
 52                 hover = false;
 53                 repaint();
 54             }
 55         });
 56     }
 57 
 58     @Override
 59     protected void paintComponent(Graphics g) {
 60         Graphics2D g2d = (Graphics2D) g.create();
 61         int h = getHeight();
 62         int w = getWidth();
 63         float tran = 1F;
 64         if (!hover) {
 65             tran = 0.3F;
 66         }
 67 
 68         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 69                 RenderingHints.VALUE_ANTIALIAS_ON);
 70         GradientPaint p1;
 71         GradientPaint p2;
 72         if (getModel().isPressed()) {
 73             p1 = new GradientPaint(00new Color(000), 0, h - 1,
 74                     new Color(100100100));
 75             p2 = new GradientPaint(01new Color(00050), 0, h - 3,
 76                     new Color(255255255100));
 77         } else {
 78             p1 = new GradientPaint(00new Color(100100100), 0, h - 1,
 79                     new Color(000));
 80             p2 = new GradientPaint(01new Color(255255255100), 0,
 81                     h - 3new Color(00050));
 82         }
 83         g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
 84                 tran));
 85         RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(00, w - 1,
 86                 h - 12020);
 87         Shape clip = g2d.getClip();
 88         g2d.clip(r2d);
 89         GradientPaint gp = new GradientPaint(0.0F0.0F, BUTTON_COLOR1, 0.0F,
 90                 h, BUTTON_COLOR2, true);
 91         g2d.setPaint(gp);
 92         g2d.fillRect(00, w, h);
 93         g2d.setClip(clip);
 94         g2d.setPaint(p1);
 95         g2d.drawRoundRect(00, w - 1, h - 12020);
 96         g2d.setPaint(p2);
 97         g2d.drawRoundRect(11, w - 3, h - 31818);
 98         g2d.dispose();
 99         super.paintComponent(g);
100     }
101 }
102 


注意代码中的几个部分:

首先是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哟。

整个源代码我连同Eclipse工程文件已经打包成zip放在我的文件里面,下载链接如下:
http://www.blogjava.net/Files/ruislan/rswing-0.1.0.zip

posted on 2007-09-11 12:24 ruislan 阅读(5526) 评论(20)  编辑  收藏

FeedBack:
# re: JButton大改造 2007-09-11 13:14 千里冰封
不错不错,写得很好
期待楼主更好的作品,有机会共同研究一下SWING:)  回复  更多评论
  
# re: JButton大改造[未登录] 2007-09-11 18:28 zc
楼主,源代码可以不带行号吗?这样直接COPY到编辑器里还要自己修改,非常的麻烦。  回复  更多评论
  
# re: JButton大改造 2007-09-11 18:34 ruislan
好好好
我就迁就你们这些懒人,下次不带行号了。  回复  更多评论
  
# re: JButton大改造 2007-09-11 21:36 Rene
楼住能否公布一下你Blogspot的地址呢?
或者在页面上加个链接就更好了^_^  回复  更多评论
  
# re: JButton大改造 2007-09-11 23:32 BeanSoft
更好的方法是开发一个 ButtonUI. Swing 本身的 MVC 就是这样分的. 呵呵, 这样不影响原始的 JButton 的代码.

/**
* $ $ License.
*
* Copyright $ L2FProd.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.l2fprod.common.swing.plaf.blue;

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;

/**
* BlueishButtonUI. <br>
*
*/
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);
}

}
  回复  更多评论
  
# re: JButton大改造 2007-09-12 00:39 ruislan
BeanSoft兄,何必舍近求远去找一个L2fprod呢,JDK里面就有现成的Metal和windows等等LookAndFeel的范例。

不过我想问一下,LookAndFeel的这种设计是一种MVC吗?也许在下驽钝,理解的是一种策略模式,将组件的paint方式交给了各个LookAndFeel的实现来完成,然后由用户通过UIManager来决定装载的不同,从而调用不同的绘制策略。

“更好的”方法比“更适合”的方法获得的效率差太多了,如果采用了BeanSoft兄的方案,那不知道要有多少步才能看到在下这个界面了,继承LookAndFeel,写ButtionUI,...,启动程序的时候装载这个LookAndFeel类...,在下只是改造一下JButton,何必非要为了JButton弄一个LookAndFeel出来呢。其实为什么大家都喜欢Spring多过EJB呢,为了迎合一个框架我们做得无用功太多了,而Spring给了我们自由的选择,但为了Spring我们也做了很多无用的东西,所以才有了AppFuse(大师说代码生成是罪恶,所以我们也该反对AppFuse?),才有了ruby on rails。聪明的人虽然也会按照成规办事,但是他会选择最适合他的成规,如果没有他宁愿尝试创新,否则,也不会有这么多新的框架如春笋般冒出来了。

也许可能会觉得我太注重实际的结果,用户的感受而忽略了作为一名不断上进的开发人员需要的学者学术般的研究和讨论,这可能才是BeanSoft兄“更好的”含义吧。我会多多改进的。

P.S 怎么感觉像是DDL和蝎在讨论什么才是艺术?嗯  回复  更多评论
  
# re: JButton大改造 2007-09-12 06:58 BeanSoft
我倒... 我有没说你要开发 Look and Feel, 实际上ButtonUI 类和任何 L&F 无关, 用 L2fprod 也只是懒得写更多代码而已. 我也是跟你讨论 Swing 呢, 不是吗? 只需要一步就能看到效果, 不需要多少步. PS 我以前可是狠狠学过一阵 Swing, 理解的不对的地方还可以继续讨论. 我这也不是学术般的讨论, 也是实用出发. 我不喜欢高谈阔论, 只喜欢代码说话.

Swing 的 MVC 我不想赘述, 我想说的是要改外观用 ButtonUI 会更方便一些而已, 不用对原来的界面逻辑代码做太多改动. 刚才那个例子用法很简单,
button.setUI(new BlueishButtonUI()); 即可改变单个按钮的外观, 而 L&F 是为了改变所有组件的外观.

用法示例:
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();
}
}

}
  回复  更多评论
  
# re: JButton大改造 2007-09-12 08:52 交口称赞
一个SWT死忠幸福的看着楼上一群人

呵呵。  回复  更多评论
  
# re: JButton大改造 2007-09-12 13:28 BeanSoft
呵呵, SWT 啥时候能换肤作出像 Office 2003, 2007 那样漂亮的界面就好了. 说实话 SWT 也土的掉渣.  回复  更多评论
  
# re: JButton大改造 2007-09-12 13:36 ruislan
我也改造过SWT的,是有点古板,土的掉渣这个就有点...  回复  更多评论
  
# re: JButton大改造 2007-09-12 13:39 darkhe
又顶。  回复  更多评论
  
# re: JButton大改造 2007-09-12 15:22 交口称赞
@BeanSoft

SWT是跟本地操作系统界面一致,这是他最大的优点啊
比如你用XP换个什么苹果主题,swt自动就是这个主题的样子。

楼主的代码,放到swt里也差不多。
也能定义一堆PP的swt控件。  回复  更多评论
  
# re: JButton大改造 2007-09-12 21:58 天若无情
楼主有时间的话可以考虑用Graphics直接在AWT上绘制些控件并加上Event处理,Swing虽然以AWT为基础,但很多地方都被优化了,图像缓存也不用考虑太多,如果要在AWT开发的系统使用还需要很多修改(或者说,我习惯重写JRE发布[反正Sun犯不上告我……],能将Swing部分包去掉就可以节省不少的资源,既然重绘界面,干脆彻底点,只留AWT作基础就好了。)。即使不考虑版本的兼容性与大小,也是尽量用Graphics绘制从界面到事件触发的算法比较值得学习。  回复  更多评论
  
# re: JButton大改造 2007-09-13 09:34 Matthew Chen
UI delegate 是swing在mvc基础上加的一些提高灵活性的扩展,外观同样是随操作系统本地的外观呈现的,awt只是swing最底层的基础,老实说这个基础薄弱而且过于依赖平台对等体,swing就好像借awt这只鸡生的蛋,用的只是那个壳,而绘制了其他的一切来确保了几乎没有平台差异,可能用惯了swt的对awt不会怎么反感,但是用惯了swing的却不会想去用awt。
觉得setUI的方法确实比在button上编码修改好,起码可以动态装卸。其实swing只对平台共有的个性化组件使用了UI delegate,自然是认为这些组件才被用户视为理当呈现为平台上的样子,而如楼主的这个例子,使得任何平台和任何laf下按钮都会是同一个样子,谈不上有什么问题,这个看项目的需要。
swing是个不错的平台差异化下桌面解决方法。  回复  更多评论
  
# re: JButton大改造 2007-09-13 11:04 天若无情
Swing和AWT的关系其实非常微妙,Swing的基础组件,都是以AWT的底层白板组件实现,或者说绘制的。它以一种理论上的纯Java方式,将AWT中所有无用部分加以摒弃。也就是说,AWT可以做到的,Swing一定可以做到,而Swing做得到的,AWT不一定可以做到。但是对Swing特性的依赖,一定会某种程度减少代码的可移植性。比如说,我现在有一组完全以Graphics在AWT白板上绘制的图形控件,那么在C#中使用它的话,大体只是算法的移植,只需要很少的代码修改就可以在C#中实现相同的效果。但是以Swing为基础的话,由于其自父类JComponent起便开始加入自己的本地化算法,转为C#平台就需要更多的事件与参数转换(主要体现在图象的缓存与变更上)。

事实上是,如果我有完全AWT为基础开发的一组控件,我想将其转为Swing,需要做什么呢?很简单,将所有awt包转为swing包,并且加上j开头就好,别无其他,因为Swing底层继承自JComponent起便继承自Container,而反之则是不可能的。

从SWT完全摒弃Swing这种做法上,我们就已经可以感知这种行为的意义何在,他为将来的扩充和发展提供了坚实的基础。

本人开源项目:
http://looframework.sourceforge.net/

www.open-open.com

虽然不是一个Java控件项目,但是原理上是非常类似的,完全以AWT开发。(或者说,近乎完全绘制的界面,不需要Swing。)

  回复  更多评论
  
# re: JButton大改造 2007-09-13 11:27 天若无情
我要说的是,这类以绘制而非继承Swing组件为主的应用,完全可以采用AWT作为底层,这样效率上会更高,而且算法更容易移植。  回复  更多评论
  
# re: JButton大改造 2007-10-21 21:25 classic20082003@163.com
楼主知道怎么样把图片变成控件么。比如说frame
window 之类的!  回复  更多评论
  
# re: JButton大改造 2007-12-17 18:14 lan
有人编过计算器吗  回复  更多评论
  
# re: JButton大改造 2008-01-25 01:08 damagegod
@天若无情
非常不错。呵呵。  回复  更多评论
  
# re: JButton大改造 2008-07-24 12:41 法法
楼主的文章很不错,非常感谢。  回复  更多评论
  

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


网站导航: