您当前的位置: 首页 > 学无止境 > 心得笔记 网站首页心得笔记
javase-swing模拟css的固定定位(冻结头部布局)的实现
发布时间:2017-08-19 19:42:01编辑:雪饮阅读()
在网页布局中css有position: fixed便可轻松实现类似excel的首行冻结效果,右边还有滚动条可以滚动。那么学习javase的同学在swing中又该如何实现呢?
肯定会有人说,直接一个普通容器然后嵌入一个up区域和down区域其中down中放一个JScrollPane容器,JScrollPane在嵌入一个普通容器做为滚动区域,up放一个普通容器做为头部即可。
但仔细观察你会发现网页中,滚动条仅贴整个页面的最右边以右上角为起始位置。
而JScrollPane则是以其子容器的右上角为起始位置的。
其实这里实现起来要大费周章。为了 高度 自由 ,我们需要通过JScrollBar来设计,而不是用现成的JScrollPane。
宏观 思路 是:
整个 界面分出一个left,一天right区域
left:
left区域再分成up区域和down0区域,down0区域再嵌入down区域,down区域中通过for循环嵌入大量按竖排列的普通容器。
right:
right区域放入滚动条并添加上滚动监听事件
最后通过对滚动事件的监听获取滚动刻度对down0->down区域进行布局位置的重新构建。
具体实现详细请看代码(代码中附详细注释,java代码不像php那样简洁,代码比较繁杂网页上查看不方便,也可在文末下载源码,jdk环境为1.6):
import javax.swing.SwingUtilities;
import javax.swing.JPanel;
import javax.swing.JFrame;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.BorderFactory;
import java.awt.Rectangle;
import javax.swing.JButton;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JScrollBar;
public class test extends JFrame implements AdjustmentListener {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
private JPanel left = null;
private JPanel right = null;
private JPanel up = null;
private JButton jButton = null;
private JButton jButton1 = null;
private JButton jButton2 = null;
private JPanel down = null;
private JPanel down0 = null;
private JButton jButton3 = null;
private JScrollBar jScrollBar = null;
private int current=0;
private int screenWidth;
private int screenHeight;
private double leftProportion=0.98;
/**
* This method initializes left
*
* @return javax.swing.JPanel
*/
private JPanel getLeft() {
left = new JPanel();
left.setLayout(null);
int w=(int)(screenWidth*leftProportion);
left.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
left.setBounds(new Rectangle(0, 0,w,screenHeight));
left.add(getUp(), null);
left.add(getDown0(), null);
return left;
}
/**
* This method initializes right
*
* @return javax.swing.JPanel
*/
private JPanel getRight() {
right = new JPanel();
right.setLayout(null);
int leftw=(int)(screenWidth*leftProportion);
int w=screenWidth-leftw;
right.setBounds(new Rectangle(leftw,0,w,screenHeight));
right.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
right.add(getJScrollBar());
return right;
}
/**
* This method initializes up
*
* @return javax.swing.JPanel
*/
private JPanel getUp() {
up = new JPanel();
up.setLayout(null);
up.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
int leftw=(int)(screenWidth*leftProportion);
up.setBounds(new Rectangle(0,0,leftw, 50));
up.add(getJButton1(), null);
up.add(getJButton(), null);
up.add(getJButton2(), null);
return up;
}
/**
* This method initializes jButton
*
* @return javax.swing.JButton
*/
private JButton getJButton() {
jButton = new JButton();
int leftw=(int)(screenWidth*leftProportion);
int leftupbtw=(int)(leftw/3);
int leftupbtSpacing=(int)((leftw-leftupbtw*3)/2);
int leftupbt2x=leftupbtw+leftupbtSpacing;
jButton.setText("当前刻度:"+current);
jButton.setBounds(new Rectangle(leftupbt2x, 0,leftupbtw,50));
return jButton;
}
/**
* This method initializes jButton1
*
* @return javax.swing.JButton
*/
private JButton getJButton1() {
jButton1 = new JButton();
jButton1.setText("按钮1");
int leftw=(int)(screenWidth*leftProportion);
int leftupbt1w=(int)(leftw/3);
jButton1.setBounds(new Rectangle(0, 0,leftupbt1w, 50));
return jButton1;
}
/**
* This method initializes jButton2
*
* @return javax.swing.JButton
*/
private JButton getJButton2() {
jButton2 = new JButton();
jButton2.setText("按钮2");
int leftw=(int)(screenWidth*leftProportion);
int leftupbtw=(int)(leftw/3);
int leftupbtSpacing=(int)((leftw-leftupbtw*3)/2);
int leftupbt3x=leftupbtw*2+leftupbtSpacing;
jButton2.setBounds(new Rectangle(leftupbt3x,0,leftupbtw,50));
return jButton2;
}
/**
* This method initializes down
*
* @return javax.swing.JPanel
*/
private JPanel getDown() {
down = new JPanel();
down.setLayout(null);
down.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
int leftw=(int)(screenWidth*leftProportion);
int h=0;
for(int i=0;i<100;i++){
h+=50;
down.setBounds(new Rectangle(0, 0,leftw,h));
down0.setBounds(new Rectangle(0,50,leftw,h));
down.add(getJButton3(i), null);
}
return down;
}
/**
* This method initializes down
*
* @return javax.swing.JPanel
*/
private JPanel getDown0() {
/*
左边本来直接分为上下两部分即可,但我这样做,当滚动条滚动后若鼠标悬停或点击到up区域,若up区域的子容器没有占满up区域时就会出现怪异的现象
比如某些子容器浮动在上层某些子容器浮动到底层,还有就是down区域的子容器可能浮动在up区域上面。
此等种种我分析如下:
当滚动条滚动时,down区域会向上塞入到up区域的下面,产生一种up区域貌似浮动在down上面的效果,可能由于浮动的层级关系(down在上层浮动或者up在上层浮动)混乱的原因
以及鼠标悬停、点击等问题导致的。
既然是这样,那么我想出的办法就是down区域下再次添加一个区域,原down就更名为down0,此时down0-〉down区域循环添加一些按行排放的容器(为了实现滚动效果做一些测试用的容器,以形成一个竖直排列的list)
此时若滚动条滚动,则down0-〉down向down0的上边界滚动 了。这样就与up区域无关了。这样就处理了头部区域浮动效果的稳定性的bug。
*/
down0 = new JPanel();
down0.setLayout(null);
int leftw=(int)(screenWidth*leftProportion);
down0.setBounds(new Rectangle(0, 50,leftw,0));
down0.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
down0.add(getDown());
return down0;
}
/**
* This method initializes jButton3
*
* @return javax.swing.JButton
*/
private JButton getJButton3(int a) {
jButton3 = new JButton();
jButton3.setText("a"+a);
int y=a*50;
int leftw=(int)(screenWidth*leftProportion);
jButton3.setBounds(new Rectangle(0, y,leftw,50));
return jButton3;
}
/**
* This method initializes jScrollBar
*
* @return javax.swing.JScrollBar
*/
private JScrollBar getJScrollBar() {
jScrollBar = new JScrollBar();
/*
setValues第一个参数为当前值,第二个参数为滑块尺寸,第三个为最小值,第四个为最大值
barMax:本人定义该变量用于计算滚动条最大值
barMax=100*左边中间区域按行独占的每行的高度+顶部区域高度-屏幕高度+滑块自身设置的高度
*/
int h=jContentPane.getHeight();
int sliderSize=(int)(screenHeight*0.2);
int barMax=100*50+50-screenHeight+sliderSize;
int leftw=(int)(screenWidth*leftProportion);
int w=screenWidth-leftw;
jScrollBar.setValues(0, sliderSize, 0, barMax);
jScrollBar.setBounds(new Rectangle(0, 0, w,h));
//添加滚动条滚动的监听事件
jScrollBar.addAdjustmentListener(this);
return jScrollBar;
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
SwingUtilities.invokeLater(new Runnable() {
public void run() {
test thisClass = new test();
thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisClass.setVisible(true);
}
});
}
/**
* This is the default constructor
*/
public test() {
super();
Toolkit kit = Toolkit.getDefaultToolkit(); //定义工具包
Dimension screenSize = kit.getScreenSize(); //获取屏幕的尺寸
screenWidth = screenSize.width; //获取屏幕的宽
screenHeight=screenSize.height;//获取屏幕的高
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
//窗体最大化
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setLayout(null);
this.setContentPane(getJContentPane());
//重新获取精准高度
/*
pack()是自动适应大小。在写程序的时候,如果定义了preferred size,则会按照首选大小画框架大小;或者按照容器内组件的大小来自适应大小。
这里使用pack才可以使得frame即这里的this返回整个窗体真正的可视高度(包含getRootPane().getY()的值),所以真正的可视高度是要减去“this.getRootPane().getY()*2"的
获得真正的高度后,使用该高度重新构建jframe。构建后需要使用 pack()才能真正生效,否则窗体会没有下边框的bug。
为什么重建jframe,因为我们要做到自适应,不同分辨率下我们的各个容器的高度都是不能写死的。所以需要获取真正的可视高度。
pack必须在setVisible执行前,否则无效。
*/
this.pack();
int ySum=this.getRootPane().getY()*2;
int h=this.getRootPane().getHeight();
screenHeight=h-ySum;
//重新创建jframe
this.setContentPane(getJContentPane());
this.pack();
this.setVisible(true);
this.setTitle("JFrame");
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
jContentPane = new JPanel();
jContentPane.setLayout(null);
jContentPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
jContentPane.setPreferredSize(new Dimension(screenWidth, screenHeight));
jContentPane.setBounds(new Rectangle(0, 0, screenWidth,screenHeight));
jContentPane.add(getLeft(), null);
jContentPane.add(getRight(), null);
return jContentPane;
}
//获取监听
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
current=e.getValue();
jButton.setText("当前刻度:"+current);
//待滚动区域的默认纵坐标相对于其父容器是0,每滚动一次y轴就减少
int newy=(int)(0-current);
down.setBounds(down.getBounds().x,newy, down.getBounds().width, down.getBounds().height);
}
}
实现效果如下:
源代码下载:
test.java
关键字词:javase,swing,css,固定定位,冻结