前言
之前有写过一个可以根据窗体大小自动改变组件位置的面板,在此开源给各位正在学习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();
}
/**
* @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();
}
}
效果如下
未拖动窗体前
窗体大小发生改变后,组件位置发生变化
总结
用计算机解决问题的过程:
弄清问题---->确定解法---->弄清解法原理---->将解法拆解成若干机械步骤---->整理步并考虑代码健壮性---->解决完成
以上就是今天给大家分享的内容,如果觉得本文对你有帮助的话,就点个赞吧🤣