您好,欢迎来到投聚财经。
搜索
您的当前位置:首页swing 自定义组件之BUTTON

swing 自定义组件之BUTTON

来源:投聚财经




Swing自定义组件之Button

GUI组件要完成的任务有2个,展现与业务。对于按钮来说,文本、图标、边框、背景属于展现层,而这些元素在按钮不同状态下会不尽相同,一般来说至少有4种状态下的展现:普通、鼠标放在其上、被按下、被禁用,也就是按钮应该具备这4种状态。

下面给出的示例是swing 实现的自定义按钮。

通常swing自定义组件继承javax.swing.JComponent并重写protectedvoid paint Component(Graphics g)方法实现自定义绘制。重写paintComponent方法时通常要先去掉super.paintComponent(g),因为父方法调用会绘制背景色。不妨先看一下

源代码中的调用过程。

JComponent.javapaintComponent(Graphicsg)方法定义如下:protectedv

oid paintComponent(Graphics g) {
Graphics scratchGraphics = (g == null) ? null : g.create();
try { if (ui != null) {
scratchGraphics.dispose();

}
}
}

其中ui的声明如下
protectedtransient ComponentUI ui;
然后转向ComponentUIupdate(Graphicsg, JComponent c)方法:

publicvoid update(Graphics g, JComponent c) {
if(c.isOpaque()) {

g.setColor(c.getBackground());
g.fillRect(0, 0, c.getWidth(),c.getHeight()); }
paint(g, c);





}

可见如果发现组件是非透明的,就绘制背景,可以看出swing组件的setBackground方法如何绘制背景的。

一般简单的自定义组件,你可以只通过重写paintComponent 方法来实现绘制,对

于一般的组件这已经足够。对于自定义按钮一般的原则是准备4 张背景图对应上述4

种状态,这4 种状态都可通过鼠标****来感知,当状态改变时,调用repaint()使Button

重绘。除了背景,按钮文本、图标等的改变一样也必须调用repaint()来刷新。

然后重要的一点是你必须重写publicDimension getPreferredSize()来获得按钮的最佳尺寸。getPreferredSize方法对于布局管理器来说至关重要,布局管理器会通过getPreferredSize的判断组件的最佳大小,并进行布局。而对于本范例而言,getPr

eferredSize 的大小只和背景图片大小有关。
对于业务,尽量做到前台界面与后来业务分离。你可以自定义按钮动作****器来实现,
后交给Action 成员的actionPerformed(ActionEvent e)处理。
本例是沿用swing Action 实现,当鼠标抬起时,构造一个ActionEvent 对象,然
*

*Created on 2007 1111,下午6:30
*
* To change this template, choose Tools | Template Manager * and openthe template in the editor.

*/
packagedemo.swing;
importjava.awt.AlphaComposite;
importjava.awt.Color;
importjava.awt.Container;
importjava.awt.Dimension;

import java.awt.Font;
import java.awt.FontMetrics; import java.awt.Graphics;
import java.awt.Graphics2D;





importjava.awt.RenderingHints;
importjava.awt.Shape;
importjava.awt.event.ActionEvent;
importjava.awt.event.MouseEvent;
importjava.awt.font.TextAttribute;
importjava.awt.font.TextLayout;
importjava.awt.geom.AffineTransform;
importjava.util.HashMap;
importjavax.swing.Action;
importjavax.swing.Icon;
importjavax.swing.JComponent;
importjavax.swing.SwingConstants;
importjavax.swing.SwingUtilities;
importjavax.swing.event.MouseInputListener; /**

* 为需要具备专业外观的按钮提供方便的实现。通过此类提供的若干方
* @author 电玩
*/ 法可轻松实现专业外观。
* 通常状态下的背景图片

*/
private Icon backgroundImage;
/**
* 通常状态下的最佳尺寸
*/
private Dimension preferredSize;
/**
* 鼠标光标在上方时的背景图片
*/
private Icon rolloverBackgroundImage;

/**
* 鼠标光标在上方时的最佳尺寸
*/
private Dimension rolloverPreferredSize;





/**
* 按钮被按下时的背景图片
*/
private Icon pressedBackgroundImage;
/**
* 按钮被按下时的最佳尺寸
*/
private Dimension pressedPreferredSize;
/**
* 按钮被禁止时的背景图片
*/
private Icon disabledBackgroundImage;
/**
* 按钮被禁止时的最佳尺寸
*/

private Dimension disabledPreferredSize;
* 当前按钮的最佳尺寸
*/ /**
*/

private Icon icon;
/**
* 按钮被禁止时的图标
*/
private Icon disabledIcon;
/**
* 按钮图标出现的位置
*/
private IconOrientation iconOrientation = IconOrientation.WES T;

/**
* 按钮的默认尺寸 */






privatestatic final Dimension DEFAULT_SIZE = new Dimension(10

0,25);

/**

*水平偏移量

*/

privateint horizontalOffset = DEFAULT_HORIZONTAL_OFFSET;

/**

*默认的水平偏移量

*/

privatestatic final int DEFAULT_HORIZONTAL_OFFSET = 4;

/**

*垂直偏移量

*/

privateint verticalOffset = DEFALUT_VERTICAL_OFFSET;

/**

* 默认的垂直偏移量
private static final int DEFALUT_VERTICAL_OFFSET = 2;
/** */
/**

*按钮文本的字体

*/

privateFont font;

/**

*按钮文本的默认字体

*/

privatestatic final Font DEFAULT_FONT = Font.decode("Dialog-P

lain-14");

/**

*按钮被禁止时候文字的颜色

*/
private Color disabledForeground; /**
* 默认的按钮被禁止时文本的颜色





*/
private final Color DEFAULT_DISABLED_FOREGROUND = new Color(19 2,192, 192);
/**
* 按钮的状态
*/
private volatile Status status = Status.DEFAULT;
/**
* 按钮的颜色透明度
*/
private volatile float alpha = 1.0f;
private static HashMap< RenderingHints.Key, Object> renderingHints;
/**
* 按钮执行的动作

*/
static {
renderingHints = new HashMap(); private Action action;
Y);

renderingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
renderingHints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); renderingHints.put(RenderingHints.KEY_DITHERING,
RenderingHints.VALUE_DITHER_DISABLE);
renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS ,
RenderingHints.VALUE_FRACTIONALMETRICS_ON); renderingHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC ); renderingHints.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);



renderingHints.put(RenderingHints.KEY_TEXT_ANTIALIASING ,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
/** 创建一个ImageButton按钮的实例*/
public ImageButton() {
currentSize = DEFAULT_SIZE;
addMouseListener(this);
addMouseMotionListener(this);
}
/**
* 设置常规状态下按钮的背景。调用该方法会影响到按钮在常规状态下的最佳尺寸,
* 由传入的图标参数对应的图标尺寸决定
* @param backgroundImage 常规状态下背景图标对象

* @throws java.lang.IllegalArgumentException 如果传入的参数
public void setBackgroundImage(Icon backgroundImage) throws
*/ null
can't be null");

}
this.backgroundImage = backgroundImage;
preferredSize = new Dimension(backgroundImage.getIconWid th(),
backgroundImage.getIconHeight());
currentSize = preferredSize;
}
/**
* 设置被禁用状态下按钮的背景。调用该方法会影响到按钮在禁用状态下的最佳尺寸,

* 由传入的图标参数对应的图标尺寸决定
* @param disabledBackgroundImage 禁用状态下背景图标对象 * @throws java.lang.IllegalArgumentException 如果传入的参数为null




*/
public void setDisabledBackgroundImage(Icon disabledBackgrou ndImage)throws IllegalArgumentException {
if (disabledBackgroundImage == null) {
throw new IllegalArgumentException(
"disabledBackgroundImage can't be null"); }
this.disabledBackgroundImage = disabledBackgroundImage; disabledPreferredSize = new Dimension(disabledBackground Image
.getIconWidth(), disabledBackgroundImage.getIco nHeight());
}
/**
* 设置在被按下状态时按钮的背景。调用该方法会影响到按钮在被

按下状态时的最佳尺寸,
* @param pressedBackgroundImage 被按下时的背景图标对象
* @throws java.lang.IllegalArgumentException 如果传入的参数
* 由传入的图标参数对应的图标尺寸决定
Image)throws IllegalArgumentException {

if (pressedBackgroundImage == null) {
throw new IllegalArgumentException(
"pressedBackgroundImage can't be null"); }
this.pressedBackgroundImage = pressedBackgroundImage; pressedPreferredSize = new Dimension(pressedBackgroundIm age
.getIconWidth(), pressedBackgroundImage.getIcon Height());
}

/**
* 设置鼠标指针在其上方时按钮的背景。调用该方法会影响到按钮在鼠标指针在其上方
* 时的最佳尺寸,由传入的图标参数对应的图标尺寸决定




* @param rolloverBackgroundImage 鼠标指针在其上方时的背景图标对象
* @throws java.lang.IllegalArgumentException 如果传入的参数为null
*/
public void setRolloverBackgroundImage(Icon rolloverBackgrou ndImage)throws IllegalArgumentException {
if (rolloverBackgroundImage == null) {
throw new IllegalArgumentException(
"rolloverBackgroundImage can't be null"); }
this.rolloverBackgroundImage = rolloverBackgroundImage; rolloverPreferredSize = new Dimension(rolloverBackground Image
.getIconWidth(), rolloverBackgroundImage.getIco

nHeight());
/**
* 设置水平偏移量。 }
*/

public void setHorizontalOffset(int horizontalOffset) throwsIllegalArgumentException{
if(horizontalOffset < 0) {
throw
newIllegalArgumentException("horizontalOffset must >=0");
}
this.horizontalOffset = horizontalOffset;
}

/**

* 设置垂直偏移量
* @param verticalOffset 垂直偏移量
* @throws java.lang.IllegalArgumentException 如果参数小于0
抛出此异常




*/
public void setVerticalOffset(int verticalOffset) throws IllegalArgumentException{
if(verticalOffset < 0) {
throw new IllegalArgumentException("verticalOffset m ust>=0");
}
this.verticalOffset = verticalOffset;
}
/**
* 设置按钮的图标
* @param icon 图标对象
* @throws java.lang.IllegalArgumentException 如果传入的参数为null,抛出此异常
*/

public synchronized void setIcon(Icon icon) throws IllegalArgu
if(icon == null) {
throw new IllegalArgumentException(mentException {

}

/**
* 设置按钮在被禁用时显示的图标
* @param disabledIcon 图标对象
* @throws java.lang.IllegalArgumentException 如果传入的参数为null,抛出此异常
*/
public synchronized void setDisabledIcon(Icon disabledIcon) throwsIllegalArgumentException {
if(disabledIcon == null) {
throw new IllegalArgumentException(

}

"disabledIcon can't be null");

}
this.disabledIcon = disabledIcon;





public void setIconOrientation(IconOrientation iconOrientati on)throws IllegalArgumentException{
if(iconOrientation == null) {
throw new IllegalArgumentException(
"iconOrientation can't be null");
}
this.iconOrientation = iconOrientation;
}
public void setDisabledForeground(Color disabledForeground) {
this.disabledForeground = disabledForeground;
}
/**
* 设置按钮的透明度
*@paramalpha透明度。范围在0.0f~1.0f之间。0.0f为完全透明,

1.0f 为完全显示
f 之间会抛出此异常
*/
*@throwsjava.lang.IllegalArgumentException如果不在0.0f~1.0
throw new IllegalArgumentException(

"alpha value must between 0.0 and 1.0"); }
this.alpha = alpha;
repaint();
}
/**
* 设置按钮显示的文本
* @param text 显示的文本字符串
*/
public synchronized void setText(String text) {

if (text != null) { this.text = text; repaint();
}





}
/**
* 返回按钮的当前字体,如果之前没有设置字体,则返回默认字体 * @return 按钮的当前字体
*/
public Font getFont() {
if(font == null) {
return DEFAULT_FONT;
}
return font;
}
/**
* 设置按钮的当前字体
* @param font 字体实例
*/

public void setFont(Font font) {
}
super.setFont(font);
this.font = font;
*/

public void setAction(Action action) {
this.action = action;
}
/**
* 覆盖JComponent.setEnabled(booleanenabled),设置是否按钮可用或被禁止
* @param enabled 如果按钮可用则为true,否则为false
* @see java.awt.Component#isEnabled
*/
@Override

public void setEnabled(boolean enabled) {
super.setEnabled(enabled); if (isEnabled() != enabled) {
if (disabledPreferredSize != null




&& !disabledPreferredSize.equals(currentSiz e)) {
currentSize = disabledPreferredSize;
revalidate();
}
}
}
/**
* 绘制按钮边框
* @param g 图形上下文
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
@Override
protected void paintBorder(Graphics g) {
}

/**
* @param g 图形上下文
* @deprecated 此方法只在内部被调用,外部不要显式调用
* 绘制子组件
}

/**
* 绘制按钮
* @param g 图形上下文
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.addRenderingHints(renderingHints);
if(alpha < 1.0f) {

g2d.setComposite(AlphaComposite.getInstance(AlphaCo

mposite.SRC_OVER,

alpha));


}





drawBackgroundImage(g2d);
drawIcon(g2d);
drawText(g2d);
g2d.dispose();
}
private void drawIcon(final Graphics2D g2d) {
Icon currentIcon = isEnabled() ? icon : disabledIcon; if(currentIcon == null) {
return;
}
int w = currentIcon.getIconWidth();
int h = currentIcon.getIconHeight();
int offsetX = 0;
int offsetY = 0;
switch (iconOrientation) {

case WEST:
offsetY = getHeight() / 2 - h / 2;
break;
offsetX = horizontalOffset;
break;

caseNORTH:
offsetX = getWidth() / 2 - w / 2;
offsetY = verticalOffset;
break;
case SOUTH:
offsetX = getWidth() / 2 - w / 2;
offsetY = getHeight() - verticalOffset - h; break;
case NORTH_WEST:
offsetX = horizontalOffset;

offsetY = verticalOffset;
break; case NORTH_EAST:
offsetX = getWidth() - horizontalOffset - w;




offsetY = verticalOffset;
break;
case SOUTH_WEST:
offsetX = horizontalOffset;
offsetY = getHeight() - verticalOffset - h; break;
case SOUTH_EAST:
offsetX = getWidth() - horizontalOffset - w; offsetY = getHeight() - verticalOffset - h; break;
case CENTER:
offsetX = getWidth() / 2 - w / 2;
offsetY = getHeight() / 2 - h / 2;
break;
}

currentIcon.paintIcon(this,g2d,offsetX,offsetY);
private void drawBackgroundImage(final Graphics2D g2d) {
if (!isEnabled()) { }
}

return;
}
switch (status) {
caseROLLOVER:
if (rolloverBackgroundImage != null) {
rolloverBackgroundImage.paintIcon(this, g2d, 0, 0);
} elseif (backgroundImage != null) {
backgroundImage.paintIcon(this, g2d, 0, 0); }
break;
case PRESSED: if (pressedBackgroundImage != null) {



pressedBackgroundImage.paintIcon(this, g2d, 0, 0);
} else if (backgroundImage != null) {
backgroundImage.paintIcon(this, g2d, 0, 0); }
break;
case PRESSED_EXIT:
default:
if (backgroundImage != null) {
backgroundImage.paintIcon(this, g2d, 0, 0); }
break;
}
}
private void drawText(final Graphics2D g2d) {

if(text == null || text.isEmpty()) {
}
Font font = getFont();
return;
AffineTransform affineTransform = AffineTransform

.getTranslateInstance(
(getWidth() - fm.stringWidth(text)) / 2,
getHeight() / 2 + fm.getHeight() / 4);
Shape textShape = textLayout.getOutline(affineTransform) ;
if(isEnabled()) {
g2d.setPaint(getForeground());
} else {
g2d.setPaint(disabledForeground != null ? disabledFor eground

: DEFAULT_DISABLED_FOREGROUND);

}
g2d.fill(textShape); g2d.draw(textShape);





}
/**
* 鼠标单击事件的处理
* @param e 鼠标事件
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
public void mouseClicked(MouseEvent e) {
}
/**
* 按钮按下时的处理
* @param e 鼠标事件
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
public void mousePressed(MouseEvent e) {
if (!isEnabled()) {

return;
}
return;
} else if(!SwingUtilities.isLeftMouseButton(e)) {
&& !pressedPreferredSize.equals(currentSize)) {

currentSize = pressedPreferredSize;
revalidate();
}
}
/**
* 鼠标抬起时的处理
* @param e 鼠标事件
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
public void mouseReleased(MouseEvent e) {

if (!isEnabled()) {
return; } else if(!SwingUtilities.isLeftMouseButton(e)) { return;




}
if (e.getX() > 0 && e.getY() > 0 && e.getX() <getPreferredS ize().width
&& e.getY() < getPreferredSize().height) { status = Status.ROLLOVER;
if (rolloverPreferredSize != null
&& !rolloverPreferredSize.equals(currentSiz e)) {
currentSize = rolloverPreferredSize;
}
try {
doAction(e);
} catch (Exception ex) {
ex.printStackTrace();
}

} else {
rrentSize)) {
if (preferredSize !preferredSize.equals(cu
status = Status.DEFAULT;
repaint();

revalidate();
}
/**
* 鼠标进入时的处理
* @param e 鼠标事件
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
public void mouseEntered(MouseEvent e) {
if (!isEnabled()) {
return;

}
status = (status == Status.PRESSED_EXIT) ? Status.PRESSED : Status.ROLLOVER;
repaint();




if (rolloverPreferredSize != null
&& !rolloverPreferredSize.equals(currentSize)) { currentSize = rolloverPreferredSize;
revalidate();
}
}
/**
* 鼠标离开时的处理
* @param e 鼠标事件
* @deprecated 此方法只在内部被调用,外部不要显式调用
*/
public void mouseExited(MouseEvent e) {
if (!isEnabled()) {
return;
}

status = (status == Status.PRESSED) ? Status.PRESSED_EXIT
repaint();
if (preferredSize != null && !preferredSize.equals(curren : Status.DEFAULT;

}

}
/**
* 鼠标拖拽时的处理
* @param e 鼠标事件
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
public void mouseDragged(MouseEvent e) {
}
/**
* 鼠标在按钮上方移动时的处理

* @param e 鼠标事件
* @deprecated 此方法只在内部被调用,外部不要显式调用 */
public void mouseMoved(MouseEvent e) {




}
/**
* 执行按钮的动作
* @param e 鼠标事件
* @throws java.lang.Exception 如果执行的业务代码抛出的异常 */
private void doAction(MouseEvent e) throws Exception{ if (!isEnabled()) {
return;
}
if (action != null) {
ActionEvent ae = new ActionEvent(e.getSource(), e.get ID(), "",e
.getWhen(), e.getModifiers());
action.actionPerformed(ae);

}
/**
* 返回当前鼠标状态的最佳尺寸。这个值是不固定的,随着鼠标针
}
*/

@Override
public Dimension getPreferredSize() {
return currentSize;
}
/**
* 按钮各个状态的枚举
*
* @author 刘一童
*
*/

private enum Status { /**
* 默认状态
*/





DEFAULT,
/**
* 鼠标移动到按钮之上
*/
ROLLOVER,
/**
* 在按钮上按下鼠标左键
*/
PRESSED,
/**
* 在按钮上按下鼠标左键后鼠标光标移开按钮区域 */
PRESSED_EXIT;
}
/**

* 图标在按钮上出现位置的枚举,此按钮只允许放置一个图标,这
* @author 刘一童
*/ 也符合大多数按钮的规范。
*/

WEST,
/**
* 图标位于按钮的正北
*/
NORTH,
/**
* 图标位于按钮的正右
*/
EAST,
/**

* 图标位于按钮的正南 */
SOUTH,
/**





* 图标位于按钮的左上方
*/
NORTH_WEST,
/**
* 图标位于按钮的左下方
*/
SOUTH_WEST,
/**
* 图标位于按钮的右上方
*/
NORTH_EAST,
/**
* 图标位于按钮的右下方
*/
SOUTH_EAST,

/**
CENTER;
*/
* 图标位于按钮的中心



Copyright © 2019- tjwe.cn 版权所有

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务