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

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06