java SWT:基于Composite定制背景透明的浮动图像按钮(image button)

版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/53488923

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;
    /**
     * 按键状态枚举类型,不同的状态有不同的透明度值<br>
     * {@link #ACTIVE} 激活<br>
     * {@link #UNACTIVE} 未激活<br>
     * {@link #DOWN}按下<br>
     * @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样式,当按钮在有图像的组件之上时这样的效果

使用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》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券