java SWT:自定义布局(Layout)实现组件自动缩放显示

2024-03-23 07:20

本文主要是介绍java SWT:自定义布局(Layout)实现组件自动缩放显示,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

什么是布局(Layout)

窗口布局(Layout)其实是指Composite中组件的一种定位原则的实现,当Composite改变大小时,会自动调用Composite初始化时设置的Layout对象来重新调整所有组件的位置。
一般的UI框架都提供了一些默认布局,比如SWT中的FillLayout,GridLayout…如果使用WindowBuilder开发UI,可以在Design界面下看到所有SWT提供的布局对象,见下图
这里写图片描述

自定义布局

有的时候,使用SWT提供的布局是无法满足需要的,这种情况下,就需要自实现所需的特殊布局。
实现自定义的Layout并不复杂,
以下是org.eclipse.swt.widgets.Layout的简要注释说明:

package org.eclipse.swt.widgets;
import org.eclipse.swt.graphics.*;/*** 布局抽象类,* 用于控制组件内所有子对象的位置和尺寸*/
public abstract class Layout {/*** 必须实现的抽象方法* 返回容器组件(父窗口)的Client区域尺寸*/
protected abstract Point computeSize (Composite composite, int wHint, int hHint, boolean flushCache);protected boolean flushCache (Control control) {return false;
}/*** 必须实现的抽象方法* 设置所有容器组件(父窗口)内所有子组件的位置和大小* @param composite 将被重新设置布局的容器组件(父窗口)* @param flushCache <code>true</code> means flush cached layout values*/
protected abstract void layout (Composite composite, boolean flushCache);
}

从上面的代码可以知道,只要实现抽象类org.eclipse.swt.widgets.Layout的两个抽象方法就可以实现一个特殊布局了,SWT提供的那些默认布局类都是通过继承Layout实现的

关于Layout的详细原文说明参见SWT的javadoc
http://help.eclipse.org/neon/nftopic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/widgets/Layout.html

组件自动缩放显示

上一节讲完Layout的实现思路,下面就以以一个实例来说明如何实现自定义布局。
比如下面的图中矩形框,并不是画在背景图上的,而是背景透明的Composite,可以移动和改变尺寸(如何实现,参见我的上一篇博客《 java SWT入门:自定义背景透明且可鼠标拖动改变尺寸和位置的Composite》)
这些矩形用于对图像中的人脸位置进行标注,我们希望当图像大小和位置改变的时候,这些矩形在图像上的相对位置保持不变。
这里写图片描述
这里写图片描述

这种需求,SWT中现成的布局都不能满足要求,所以就要自己实现一个,以下是实现代码,
ActiveRectContainer.java

package net.gdface.ui;import java.net.URL;
import java.util.ArrayList;
import java.util.List;import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Decorations;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.wb.swt.SWTResourceManager;/*** 活动矩形显示容器* 窗口尺寸改变时所有{@link ActiveRectangle}对象自动等比例改变* * @author guyadong**/
public class ActiveRectContainer extends Decorations {/*** 创建自定义的布局对象实现窗口内的ActiveRectangle对象能根据父窗口的尺寸改变而同步等比例改变,* 以保持每一个矩形在父窗口上的相对位置不变 * @author guyadong**/class ZoomLayout extends Layout {@Overrideprotected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {// 返回可以画图的区域Rectangle bounds = composite.getClientArea();return new Point(bounds.width, bounds.height);}@Overrideprotected void layout(Composite composite, boolean flushCache) {Control[] childrens = composite.getChildren();Rectangle originalbounds = getBackgroundImage().getBounds();Rectangle bounds = composite.getBounds();// 计算x/y轴缩放比例float zoomX = (float) bounds.width / originalbounds.width;float zoomY = (float) bounds.height / originalbounds.height;for (Control children : childrens) {if (children instanceof ActiveRectangle) {// 对于ActiveRectangle对象调用zoom方法改变bounds((ActiveRectangle) children).zoom(zoomX, zoomY);}else if(children.getLayoutData() instanceof Rectangle){// 对于其他Control对象调用如果通过setLayoutData()设置了原始的对象尺寸,则可以根据父窗口尺寸同步改变boundsRectangle originalBounds=(Rectangle) children.getLayoutData();// 获取Control原始位置尺寸children.setBounds(new Rectangle((int)(originalBounds.x*zoomX),(int)(originalBounds.y*zoomY),(int)(originalBounds.width*zoomX),(int)(originalBounds.height*zoomY)));}}}}protected List<ActiveRectangle> annRects=EMPTY_RECTS;private static final List<ActiveRectangle> EMPTY_RECTS=new ArrayList<ActiveRectangle>();/*** @param parent* @param image 显示的背景图像,为null时不显示* @param rects 显示的矩形对象数组* @param focusIndex 焦点矩形索引,超出 rects索引范围时无效*/public ActiveRectContainer(Composite parent, Image image, Rectangle[] rects, int focusIndex) {super(parent, SWT.BORDER|SWT.RESIZE);if(null!=rects&&rects.length>0){this.annRects=new ArrayList<ActiveRectangle>();for(Rectangle rect:rects){// 创建矩形对象(ActiveRectangle)annRects.add(new ActiveRectangle(this, false,rect));}try{// 设置焦点对象this.annRects.get(focusIndex).focus=true;}catch(IndexOutOfBoundsException  e){}}this.setBackgroundImage(null==image?SWTResourceManager.getMissingImage():image);// 设置自定义布局对象        this.setLayout(new ZoomLayout());addPaintListener(new PaintListener() {@Overridepublic void paintControl(PaintEvent e) {// 调用重绘方法paintImage(e.gc);}});}/*** @param parent* @param url 背景图像的URL* @param rects* @param focusIndex * @see #AutoZoomRecContainer(Composite, Image, Rectangle[], int)*/public ActiveRectContainer(Composite parent, URL url, Rectangle[] rects, int focusIndex) {this(parent, SWTResourceManager.getImage(url),rects, focusIndex);}/*** 将 {@link #image} 重绘图像到窗口(缩放到整个窗口)* * @param gc*/protected final void paintImage(GC gc) {boolean isAdvanced = gc.getAdvanced();try {gc.setAdvanced(true);gc.setAntialias(SWT.ON);Point destSize = getSize();Image image = getBackgroundImage();Rectangle imgSize = image.getBounds();gc.drawImage(image, 0, 0, imgSize.width, imgSize.height, 0, 0, destSize.x, destSize.y);} finally {gc.setAdvanced(isAdvanced);}}/*** 以窗口中心为原点对窗口进行缩放* @param zoomX x轴缩放比例* @param zoomY x轴缩放比例*/public void zoomCenter(float zoomX, float zoomY) {// 以背景图像的尺寸为当前对象的原始尺寸Rectangle originalSize = getBackgroundImage().getBounds();Rectangle bounds=getBounds();// 缩放后的尺寸int width=(int) (originalSize.width*zoomX);int height=(int) (originalSize.height*zoomX);// 中心点位置int x=bounds.x+(bounds.width-width)/2;int y=bounds.y+(bounds.height- height)/2;       super.setBounds(x, y, width, height);}/*** x/y轴等比例缩放* @param zoom 缩放比例* @see #zoomCenter(float, float)*/public void zoomCenter(float zoom) {zoomCenter(zoom,zoom);}@Overrideprotected void checkSubclass() {}}

注意:自定义布局实现在ActiveRectContainer.java的代码中是以一个内部类ZoomLayout 来实现的

以下是用WindowBuilder生成的测试代码
TestRectContainer.java

package testwb;import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.wb.swt.SWTResourceManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import net.gdface.ui.ActiveRectContainer;import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;public class TestRectContainer {static final Logger logger = LoggerFactory.getLogger(TestRectContainer.class);protected Shell shell;/*** Launch the application.* @param args*/public static void main(String[] args) {try {TestRectContainer window = new TestRectContainer();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();}}}/*** 返回适合当前窗口尺寸完整显示图像的缩放比例,图像长宽都小于显示窗口时,则返回1* * @return*/private static float fitZoom(Point parentSize,Point childrenSize) {if (childrenSize.x < parentSize.x && childrenSize.y < parentSize.y)return 1f;if (childrenSize.x * parentSize.y < childrenSize.y * parentSize.x) {return ((float) parentSize.y) / (float)childrenSize.y;}return ((float) parentSize.x) / (float)childrenSize.x;}private static Rectangle fitBounds(Point parentSize,Point childrenSize) {float zoom = fitZoom(parentSize, childrenSize);childrenSize.x*=zoom;childrenSize.y*=zoom;return new Rectangle((parentSize.x-childrenSize.x)/2,(parentSize.y-childrenSize.y)/2,childrenSize.x,childrenSize.y);}/*** Create contents of the window.*/protected void createContents() {shell = new Shell();shell.setText("SWT Application");shell.setSize(569, 459);Rectangle[] rects = new Rectangle[]{new Rectangle(50,50,200,200),new Rectangle(350,100,150,250),new Rectangle(125,300,200,321)};ActiveRectContainer canvas;//Image image = SWTResourceManager.getImage("http://pic8.nipic.com/20100704/3525627_110847063052_2.jpg");Image image = SWTResourceManager.getImage("J:/workspace.neon/iadbui/src/image/3525627_110847063052_2.jpg");//Image image = SWTResourceManager.getImage(this.getClass(),"/image/3525627_110847063052_2.jpg");Point imgSize=new Point(image.getBounds().width,image.getBounds().height);canvas = new ActiveRectContainer(shell, image,rects,0);canvas.setBounds(fitBounds(shell.getSize(),imgSize));Button btnNewButton = new Button(canvas, SWT.NONE);btnNewButton.setBounds(189, 95, 80, 27);// 如果这里通过setLayoutData设置了btnNewButton的原始尺寸,btnNewButton也会随着窗口尺寸改变而自动缩放btnNewButton.setLayoutData(new Rectangle(189, 95, 80, 27));btnNewButton.setText("New Button");}
}

请注意:
对于一般的Control对象,如果没有通过setLayoutData方法设置原始的尺寸位置,则Layout对其无效,所以上面的测试代码中对btnNewButton调用了setLayoutData,指定了初始的位置和尺寸。这样它才能与父窗口同步缩放。如下图
这里写图片描述
如果注释掉 btnNewButton.setLayoutData(new Rectangle(189, 95, 80, 27));这一行,效果是这样的
这里写图片描述

参考

《org.eclipse.swt.widgets.Layout》
《 java SWT入门:自定义背景透明且可鼠标拖动改变尺寸和位置的Composite》

这篇关于java SWT:自定义布局(Layout)实现组件自动缩放显示的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/837556

相关文章

springMVC返回Http响应的实现

《springMVC返回Http响应的实现》本文主要介绍了在SpringBoot中使用@Controller、@ResponseBody和@RestController注解进行HTTP响应返回的方法,... 目录一、返回页面二、@Controller和@ResponseBody与RestController

JAVA集成本地部署的DeepSeek的图文教程

《JAVA集成本地部署的DeepSeek的图文教程》本文主要介绍了JAVA集成本地部署的DeepSeek的图文教程,包含配置环境变量及下载DeepSeek-R1模型并启动,具有一定的参考价值,感兴趣的... 目录一、下载部署DeepSeek1.下载ollama2.下载DeepSeek-R1模型并启动 二、J

nginx中重定向的实现

《nginx中重定向的实现》本文主要介绍了Nginx中location匹配和rewrite重定向的规则与应用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下... 目录一、location1、 location匹配2、 location匹配的分类2.1 精确匹配2

Nginx之upstream被动式重试机制的实现

《Nginx之upstream被动式重试机制的实现》本文主要介绍了Nginx之upstream被动式重试机制的实现,可以通过proxy_next_upstream来自定义配置,具有一定的参考价值,感兴... 目录默认错误选择定义错误指令配置proxy_next_upstreamproxy_next_upst

nginx生成自签名SSL证书配置HTTPS的实现

《nginx生成自签名SSL证书配置HTTPS的实现》本文主要介绍在Nginx中生成自签名SSL证书并配置HTTPS,包括安装Nginx、创建证书、配置证书以及测试访问,具有一定的参考价值,感兴趣的可... 目录一、安装nginx二、创建证书三、配置证书并验证四、测试一、安装nginxnginx必须有"-

springboot rocketmq配置生产者和消息者的步骤

《springbootrocketmq配置生产者和消息者的步骤》本文介绍了如何在SpringBoot中集成RocketMQ,包括添加依赖、配置application.yml、创建生产者和消费者,并展... 目录1. 添加依赖2. 配置application.yml3. 创建生产者4. 创建消费者5. 使用在

Spring Retry 实现乐观锁重试实践记录

《SpringRetry实现乐观锁重试实践记录》本文介绍了在秒杀商品SKU表中使用乐观锁和MybatisPlus配置乐观锁的方法,并分析了测试环境和生产环境的隔离级别对乐观锁的影响,通过简单验证,... 目录一、场景分析 二、简单验证 2.1、可重复读 2.2、读已提交 三、最佳实践 3.1、配置重试模板

Spring中@Lazy注解的使用技巧与实例解析

《Spring中@Lazy注解的使用技巧与实例解析》@Lazy注解在Spring框架中用于延迟Bean的初始化,优化应用启动性能,它不仅适用于@Bean和@Component,还可以用于注入点,通过将... 目录一、@Lazy注解的作用(一)延迟Bean的初始化(二)与@Autowired结合使用二、实例解

SpringBoot使用Jasypt对YML文件配置内容加密的方法(数据库密码加密)

《SpringBoot使用Jasypt对YML文件配置内容加密的方法(数据库密码加密)》本文介绍了如何在SpringBoot项目中使用Jasypt对application.yml文件中的敏感信息(如数... 目录SpringBoot使用Jasypt对YML文件配置内容进行加密(例:数据库密码加密)前言一、J

Java中有什么工具可以进行代码反编译详解

《Java中有什么工具可以进行代码反编译详解》:本文主要介绍Java中有什么工具可以进行代码反编译的相关资,料,包括JD-GUI、CFR、Procyon、Fernflower、Javap、Byte... 目录1.JD-GUI2.CFR3.Procyon Decompiler4.Fernflower5.Jav