SWT对于图形按钮没有很好的支持,反正我折腾了半天,发现用org.eclipse.swt.widgets.Button是没办法做出好看的图形按钮的.
于是就参考org.eclipse.ui.forms.widgets.ImageHyperlink
自己撸了一个:
效果嘛,参见下图, 请忽略左边的美女:
鼠标不在按钮区域时的未激活状态
鼠标进入按钮区域时的激活状态
下面是完整代码,很简单。
ImageButton.java
package net.gdface.ui;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.wb.swt.SWTResourceManager;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
/** * 透明背景图像按钮 * @author guyadong * */
public class ImageButton extends Composite{
/** * 按钮背景图 */
private Image image;
/** * dispose时是否释放image资源( {@link #dispose()}不释放 没有指定透明色的 {@link #image} 对象) */
private boolean disposeImage=false;
/** * 按键状态枚举类型,不同的状态有不同的透明度值
* {@link #ACTIVE} 激活
* {@link #UNACTIVE} 未激活
* {@link #DOWN}按下
* @author guyadong */
private enum State{
ACTIVE(150),DOWN(255),UNACTIVE(50);
private State(int alpha) {
this.alpha = alpha;
}
int alpha;
}
/** * 按钮激活标志 */
private State active = State.UNACTIVE;
/** * 最小按钮尺寸 */
private Point minSize=null;
/** * 最大按钮尺寸 */
private Point maxSize=null;
/** * @param parent * @param transparent 指定透明色,为null时没有透明色 * @param style * @wbp.parser.constructor */
public ImageButton(Composite parent, Image image, RGB transparent) {
super(parent, SWT.TRANSPARENT);// 透明背景样式
image = image == null ? SWTResourceManager.getMissingImage() : image;
if(null!=transparent){
ImageData imageData = image.getImageDataAtCurrentZoom();
imageData.transparentPixel = imageData.palette.getPixel(transparent);
image = new Image(parent.getDisplay(), imageData);
disposeImage=true;
}
this.image=image;
this.maxSize=new Point(this.image.getBounds().width,this.image.getBounds().height);
// 鼠标进入离开时修改激活标志并重绘窗口
addMouseTrackListener(new MouseTrackAdapter() {
final Cursor defCursor = getCursor();
@Override
public void mouseEnter(MouseEvent e) {
active = State.ACTIVE;
setCursor(SWTResourceManager.getCursor(SWT.CURSOR_HAND));
redraw();
}
@Override
public void mouseExit(MouseEvent e) {
active = State.UNACTIVE;
setCursor(defCursor);
redraw();
}
});
addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
boolean isAdvanced = e.gc.getAdvanced();
try {
if(!isAdvanced)
e.gc.setAdvanced(true);
e.gc.setAntialias(SWT.ON);
// 激活时设置alpha参数以区分按钮状态
e.gc.setAlpha(active.alpha);
e.gc.drawImage(ImageButton.this.image, 0, 0, ImageButton.this.image.getBounds().width,
ImageButton.this.image.getBounds().height, 0, 0, getBounds().width, getBounds().height);
} finally {
if(!isAdvanced)
e.gc.setAdvanced(isAdvanced);
}
}
});
addMouseListener(new MouseAdapter() {
@Override
public void mouseDown(MouseEvent e) {
if(1==e.button){
active=State.DOWN;
redraw();
}
}
@Override
public void mouseUp(MouseEvent e) {
if(1==e.button){
active=State.ACTIVE;
redraw();
}
}
});
}
/** * 指定透明色为白色 * @param parent * @param image * @see #ImageButton(Composite, Image, RGB) */
public ImageButton(Composite parent, Image image) {
this(parent,image,new RGB(255, 255, 255));
}
@Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
@Override
public void dispose() {
if(disposeImage)
image.dispose();
super.dispose();
}
@Override
public Point computeSize(int wHint, int hHint, boolean changed) {
// 重写此方法,保证layout时按钮尺寸不超过设置的最大最小值
if(wHint!=SWT.DEFAULT){
if(null!=minSize)wHint=Math.max(minSize.x, wHint);
wHint=Math.min(maxSize.x, wHint);
}
if(hHint!=SWT.DEFAULT){
if(null!=minSize)hHint=Math.max(minSize.y, hHint);
hHint=Math.min(maxSize.y, hHint);
}
return super.computeSize(wHint, hHint, changed);
}
/** * @return * @see #minSize */
public Point getMinSize() {
return minSize;
}
/** * @param minSize * @return * @see #minSize */
public ImageButton setMinSize(Point minSize) {
this.minSize = minSize;
return this;
}
/** * @return * @see #maxSize */
public Point getMaxSize() {
return maxSize;
}
/** * @param maxSize * @return * @see #maxSize */
public ImageButton setMaxSize(Point maxSize) {
if(null!=maxSize&&maxSize.x>minSize.x&&maxSize.y>minSize.y)
this.maxSize = maxSize;
return this;
}
}
注意:
上面的代码在类构造函数中使用了SWT.TRANSPARENT样式进行初始化,SWT.TRANSPARENT指定透明背景
如果不指定SWT.TRANSPARENT样式,当按钮在有图像的组件之上时这样的效果
用WindowBuilder生成的测试代码也一并附上:
TestApp.java
package testwb;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import java.net.MalformedURLException;
import java.net.URL;
import org.eclipse.swt.SWT;
import org.eclipse.wb.swt.SWTResourceManager;
import net.gdface.ui.ActiveConstant;
import net.gdface.ui.ImageButton;
import net.gdface.ui.ImageCanvas;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
public class TestApp {
protected Shell shell;
/** * Launch the application. * * @param args */
public static void main(String[] args) {
try {
TestApp window = new TestApp();
window.open();
} catch (Exception e) {
e.printStackTrace();
}
}
/** * Open the window. */
public void open() {
Display display = Display.getDefault();
createContents();
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
/** * Create contents of the window. */
protected void createContents() {
shell = new Shell();
// 鼠标左键点击改变背景色测试明秀色效果
shell.addMouseListener(new MouseAdapter() {
Color defColor=SWTResourceManager.getColor(SWT.COLOR_RED);
boolean c=false;
@Override
public void mouseDown(MouseEvent e) {
c=!c;
shell.setBackground(c?SWTResourceManager.getColor(SWT.COLOR_BLACK):defColor);
}
});
shell.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK));
shell.setSize(526, 467);
shell.setText("SWT Application");
// 强制所有组件使用父窗口的背景色
shell.setBackgroundMode(SWT.INHERIT_FORCE);
try {
Image image = SWTResourceManager.getImage(new URL(
"http://d.hiphotos.baidu.com/image/pic/item/562c11dfa9ec8a13f075f10cf303918fa1ecc0eb.jpg"));
ImageCanvas canvas = new ImageCanvas(shell, SWT.NONE, image);
canvas.setBounds(10, 10, 124, 252);
ImageButton canvas_1 = new ImageButton(shell, SWTResourceManager.getImage(TestApp.class, "/image/arrow_left.png"), null);
canvas_1.setBounds(156, 47, 118, 184);
} catch (MalformedURLException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
}
}
注意:
上面的测试代码有这一行shell.setBackgroundMode(SWT.INHERIT_FORCE);
是强制所有组件使用父窗口的背景色。
这一行也很重要,如果没有这样,当按钮所在组件改变背景色的时候(setBackground),透明色就失效了。
SWT对图像背景透明的设置有几种方式,本文中我选择了最简单的一种,就是指定图像中某种颜色(本例为白色)为透明色。
当然使用这种方式也有缺点就是除了透明色之外,相近的颜色(比如 255,255,254)就没办法透明,所以修图时要把图清干净保持背景色是纯色。
因为jpeg是有损压缩格式,会破坏纯色的背景色,所以这种透明方式对于jpeg格式的图像效果不好。
所以建议使用png,bmp等无损压缩格式来存储图像文件。
2016/12/07 补充:按钮状态增加到3种,分为ACTIVE,UNACTIVE,DOWN,增加layout支持
2016/12/08 补充:修改为控件样式(style)改为SWT.TRANSPARENT,修正按钮在图像上浮云时效果不正确的问题
关于图像透明色的设置参考:
《Java Source Code: com.asprise.books.javaui.ch15.Transparency》
《Taking a look at SWT Images》