【Java】手把手教会你如何设计自适应面板,实现组件位置自动调整


前言

之前有写过一个可以根据窗体大小自动改变组件位置的面板,在此开源给各位正在学习Java的同学,具体思路和实现在下面阐述。


一、为什么要自适应?

自适应其实在很多大家熟悉的日常使用的软件中都有体现。在我们使用软件时,窗体的布局并不是固定的,我们在“拖拽”窗体后窗体大小和比例发生变化,此时,如果组件位置不进行调整,部分组件则不会正常显示。

二、如何实现自适应?

自适应原理

实现自适应的第一步是明确自适应的原理,直白一点,自适应就是窗体大小发生变化后,组件根据某种调整准则,重新调整自身位置的过程。调整准则其实是组件与父容器之间的一种关系的描述,如果将组件视为一点(点的位置可以取组件的中心位置或者是布局中位置),这种关系往往是坐标系中的位置比例,即组件始终处于父类容器中某个相对位置。调整准则的不同,直接会影响到调整后的显示效果。

思路整理:第一步获取父类容器上的所有组件,第二部计算位置关系,第三步窗体大小发生变化时重新设定组件位置。

实现思路

我们已经理解了自适应原理,明白我们所要做的事情,现在我们将想法变为代码吧!

想要计算组件和父容器的位置关系,首先我们得知道有哪些组件,以及定义保存位置关系的对象,我们在这里定义两个Container,分别达到上述两个目的。

ArrayList<Component> autojust = new ArrayList<Component>();		//放置在本类对象上的组件顺序表,每次添加的组件都会放入其中
ArrayList<Point2D.Double> times = new ArrayList<Point2D.Double>();//组件位置左上角与本类初始大小的倍数关系

对象定义好了,现在考虑如何往对象中填充组件,我们可以在使用add方法将组件添加到父容器时顺便添加到组件Container中并且计算位置关系。

@Override
public Component add(Component comp) throws ArithmeticException{	//若未设置大小,则抛出算术异常
	super.add(comp);
	autojust.add(comp);		//将组件放入child顺序表,用于实现自适应
	Point p = null;		//放入后计算当前child的坐标位置与本类大小的比例关系
	p = comp.getLocation(p);
	if(height == 0 && width == 0){		//大小没有被设置,宽高则都为0
		throw new ArithmeticException("先设置此面板大小!");
	}else{		//若已设置,则计算当前放入的组件的位置与面板大小的倍数关系,并存入倍数关系顺序表
		double xtimes = (double)p.getX()/(double)(width);
		double ytimes = (double)p.getY()/(double)(height);
		times.add(new Point2D.Double(xtimes,ytimes));	//比例关系计入位置关系顺序表
	}
	return comp;
}

在拥有组件Container和位置关系后,最后要考虑的就是如何在窗体发生变化时自动重新设定组件位置。如果你的Swing界面设计经验十分丰富,应该知道我们下一步要做什么。————————对的,通过重写paint这类自动调用的方法去帮助我们实现功能。

	@Override
	public void paint(Graphics g){		//面板实现自适应,根据组件的位置对于面板大小的位置比例系数,每次刷新页面时更新组件位置
		super.paint(g);
		int mywidth = this.getWidth(),myheight = this.getHeight();	//重新获得当前面板大小的位置
		for(int i = 0;i<autojust.size();i++){	//遍历重新设置各个组件的位置
			autojust.get(i).setLocation((int)(mywidth*times.get(i).getX()),(int)(myheight*times.get(i).getY()));
		}
	}

整体代码

所有功能都已经实现,整理一下代码可得如下。

import java.util.*;
import javax.swing.*;
import java.awt.geom.*;
import java.awt.*;

public class AutojustChildPanel extends JPanel{
	ArrayList<Component> autojust = new ArrayList<Component>();		//放置在本类对象上的组件顺序表,每次添加的组件都会放入其中
	ArrayList<Point2D.Double> times = new ArrayList<Point2D.Double>();//组件位置左上角与本类初始大小的倍数关系
	int width = 0,height = 0;	//记录初始化时的默认大小,用于计算倍数

	//无需自定义构造方法

	@Override
	public void setBounds(int x,int y,int width,int height){	//设置位置时,记录大小
		super.setBounds(x,y,width,height);
		this.width = width;
		this.height = height;
	}

	@Override
	public void setSize(int width,int height){	//直接设置大小时,记录大小
		super.setSize(width,height);
		this.width = width;
		this.height = height;
	}

	@Override
	public Component add(Component comp) throws ArithmeticException{	//若未设置大小,则抛出算术异常
		super.add(comp);
		autojust.add(comp);		//将组件放入child顺序表,用于实现自适应
		Point p = null;		//放入后计算当前child的坐标位置与本类大小的比例关系
		p = comp.getLocation(p);
		if(height == 0 && width == 0){		//大小没有被设置,宽高则都为0
			throw new ArithmeticException("先设置此面板大小!");
		}else{		//若已设置,则计算当前放入的组件的位置与面板大小的倍数关系,并存入倍数关系顺序表
			double xtimes = (double)p.getX()/(double)(width);
			double ytimes = (double)p.getY()/(double)(height);
			times.add(new Point2D.Double(xtimes,ytimes));	//比例关系计入位置关系顺序表
		}
		return comp;
	}

	@Override
	public void paint(Graphics g){		//面板实现自适应,根据组件的位置对于面板大小的位置比例系数,每次刷新页面时更新组件位置
		super.paint(g);
		int mywidth = this.getWidth(),myheight = this.getHeight();	//重新获得当前面板大小的位置
		for(int i = 0;i<autojust.size();i++){	//遍历重新设置各个组件的位置
			autojust.get(i).setLocation((int)(mywidth*times.get(i).getX()),(int)(myheight*times.get(i).getY()));
		}
	}
}

三、使用实例

代码如下(示例):

import javax.swing.*;
import java.awt.*;

public class TestAutojust extends JFrame {

    private AutojustChildPanel acp;

    public TestAutojust(){
        super("自适应布局测试");
        this.setSize(1280,720);
        Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
        this.setLocation((screensize.width-1280)/2,(screensize.height-720)/2);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setMinimumSize(new Dimension(800,600));
        this.setVisible(true);
        init();
        this.repaint();
    }


    public void init(){
        acp = new AutojustChildPanel();
        acp.setBackground(Color.yellow);
        acp.setLayout(null);
        acp.setSize(this.getWidth(),this.getHeight());
        this.add(acp);
        JButton jb1 = new JButton("测试按钮1");
        JButton jb2 = new JButton("测试按钮2");
        JButton jb3 = new JButton("测试按钮3");
        jb1.setBounds(400,100,100,30);
        jb2.setBounds(400,200,100,30);
        jb3.setBounds(150,300,100,30);
        acp.add(jb1);
        acp.add(jb2);
        acp.add(jb3);
        acp.repaint();
    }

    /**
     * &#064;function  外部窗口发生变化时,内部自适应面板的大小需要做出变化
     * 自适应面板变化后,其内部的组件会自动调整位置
     * @param g the specified Graphics window
     */
    @Override
    public void paint(Graphics g){
        super.paint(g);
        acp.setSize(this.getWidth(),this.getHeight());
    }

    public static void main(String[] args){
        new TestAutojust();
    }
}

效果如下
未拖动窗体前

默认
窗体大小发生改变后,组件位置发生变化

在这里插入图片描述


总结

用计算机解决问题的过程:
弄清问题---->确定解法---->弄清解法原理---->将解法拆解成若干机械步骤---->整理步并考虑代码健壮性---->解决完成
以上就是今天给大家分享的内容,如果觉得本文对你有帮助的话,就点个赞吧🤣

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值