前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java SWT:基于Composite定制背景透明的浮动图像按钮(image button)

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

作者头像
10km
发布2019-05-25 21:53:50
1.8K0
发布2019-05-25 21:53:50
举报
文章被收录于专栏:10km的专栏10km的专栏

版权声明:本文为博主原创文章,转载请注明源地址。 https://cloud.tencent.com/developer/article/1433563

SWT对于图形按钮没有很好的支持,反正我折腾了半天,发现用org.eclipse.swt.widgets.Button是没办法做出好看的图形按钮的.

于是就参考org.eclipse.ui.forms.widgets.ImageHyperlink自己撸了一个:

效果嘛,参见下图, 请忽略左边的美女:

鼠标不在按钮区域时的未激活状态

鼠标进入按钮区域时的激活状态

下面是完整代码,很简单。

ImageButton.java

代码语言:javascript
复制
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

代码语言:javascript
复制
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》

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016年12月06日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档