java swing项目桌面软件还是蛮香的,至少有了我自己的桌面软件|Java 开发实战

2023-11-28 16:03:09 浏览数 (1)

最近利用空闲时间自己琢磨了一下java swing 编程,其实在从事javaweb之前我一直向往的就是java swing 开发,不知道为什么可能当时觉得Windows上的exe程序很是神奇,关于windows上制作exe我之前也有介绍

java swing开发都是自己琢磨的,有的地方写的不规范,不过大多都是网上借鉴的,应该不算离谱的。

今天看了看自己的java swing的程序,感觉写的还不错,但是发现现在遇到一个瓶颈问题,就是jtable的使用,由于一开始概念不理解现在jtable得重新写,之前我吧数据放在jtable上了,但是真正开发的java swing数据都是放在TableModel上的。下面就Jtable的使用,好好整理了一番,途中参考的文章我都会放在下面列出,读者可以自己参考**

JTable结构梳理


  • JTable=TableHeader TableColumn
  • 顾名思义我们知道表格是由表头和表列组成的,这两个都是单独的控件。但是JTable中如果想让表头显示仅仅将JTable加入Jpanel或者Jframe中是不行的,我这里提供两种方式实现
  • 1、分别将TableHeader和TableColumn加入控件中单独的显示,这种情况不常见
  • 2、先将JTable加入jscrollpane(滚动条)中,然后在将滚动条加入到对应的控件中(Jpanel或者是Jframe).java swing 开发中加入滚动条是很常见的操作,所以这种方式的加入表格还是很推荐的。
代码语言:text复制
table = new JTable(data, columnNames);
table.setBackground(Color.gray);
table.setPreferredScrollableViewportSize(new Dimension(800, 100));
table.setFillsViewportHeight(false);
pane = new JScrollPane(table);
this.add(pane);
  • 上面的代码就是简单的实现将表格以显示表头的方式加入到jframe中显示。其中我们能够看到多了几个设置,setPreferredScrollableViewportSize可有可无的,无所谓,但是setFillsViewportHeight是设置表格在纵向上的铺展情况,什么意思呢,如果这里设置为true则表格就会在纵向上铺满jframe,如果是false,表格则会按照自己的实际占地面积显示,不会多占的。

JTable数据显示


  • java swing中jtable是mvc形式的,所以jtable仅仅是数据的显示,而真正和数据绑定的却是TableModel这个接口,我们先看看这个接口的内部有哪些方法,这样我们心里才有个底。
  • 众多周知jtable中常用的两种构造函数一个是数组另一个是vector,这两种构造函数中都是采用了匿名内部类实现tablemodel,前者用的是AbstractTableModel,后者是DefaultTableModel。而DefaultTableModel有事继承了AbstractTableModel,所以我们平时如果自定义model的话,都会去继承AbstractTableModel的。我们在去源码里可以看见,我们会发现AbstractTableModel有事继承TableModel这个接口的。所以我们的所有方法都是源于他。
  • 我们观察AbstractTableModel源码中注释发现,我们只需要继承AbstractTableModel类后只需要实现三个必须的方法,其他的方法根据需要实现
代码语言:c#复制
public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);
  • 这三个方法的作用就是通过model高数jtable我需要一个几行几列的表格,至于每个单元格显示的内容就是通过getValueAt这个方法实现的,到这里我们就实现了,jtable的model自定义显示。
代码语言:c#复制
//表格的列,需要用户自己设定好
	private int column;
	//待加载的数据  数据每行的列数和上面要统一好
	private List<Object> list;
	
	public MyTableModel(List<Object> list,int column){
		this.column=column;
		this.list=list;
	}
	@Override
	public int getRowCount() {
		// TODO Auto-generated method stub
		return list.size();
	}

	@Override
	public int getColumnCount() {
		// TODO Auto-generated method stub
		return this.column;
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) {
		// TODO Auto-generated method stub
		return list.get(rowIndex).toString() "_" rowIndex "_" columnIndex;
	}
  • 上面的代码就是我的model类,里面有个穿list的构造函数,然后我们看看我们的三个方法就起到了作用了。然后在getValueAt获取指定行数的list的指定内容就可以填充到表格上了。

jtable数据的CURD


  • 在上面我们继承了AbstractTableModel,这里面有对数据的CURD操作
代码语言:scss复制
if("增加".equals(command)){
			List<Object> data = getData();
			data.add("test5");
			data.add("test6");
			datamModel.setList(data);
//			datamModel.fireTableStructureChanged();
			datamModel.fireTableRowsInserted(5,6);
		}else if("删除".equals(command)){
			List<Object> data = getData();
			data.remove(2);
			datamModel.setList(data);
			datamModel.fireTableRowsDeleted(1, 1);
		}else if("更新".equals(command)){
			List<Object> data = getData();
			data.set(0, "test0_1");
			datamModel.setList(data);
			datamModel.fireTableRowsUpdated(0, 5);
		}
  • 里面都会带有参数比如datamModel.fireTableRowsUpdated(0, 5);的意思是通州JTable显示模块去刷新从1-6行的所有数据,所以说比如你更新了第一行的数据,而你用的两个参数是1,4.那么恭喜你,你的更新JTable无法实现,因为他只更新从第二行开始到第五行的数据。其他的方法参数和他一样。通过上面就可以轻松实现JTable的CURD操作。

JTable控件显示法


  • 相信有的朋友遇到过,表格中需要显示CheckBox、button等控件的,但是我们发现我们定义的控件在表格上显示成了控件对应的类的字符串了,这又是为什么呢。下面请随我一起看看源码吧:
代码语言:text复制
/**
     *  Returns <code>Object.class</code> regardless of <code>columnIndex</code>.
     *
     *  @param columnIndex  the column being queried
     *  @return the Object.class
     */
    public Class<?> getColumnClass(int columnIndex) {
        return Object.class;
    }
  • 源码中AbstractTableModel的getColumnClass的方法是JTable决定显示类型的主要依据,源码中返回的默认是object.class,这就意味着我们在jtable是true或false或其他类,在这里都会返回object.class,那么jtable就会采用默认的渲染方式去渲染表格,默认的就是所有都是字符串形式展示,这个设置在JTable中的源码中
代码语言:text复制
protected void createDefaultRenderers() {
        defaultRenderersByColumnClass = new UIDefaults(8, 0.75f);

        // Objects
        setLazyRenderer(Object.class, "javax.swing.table.DefaultTableCellRenderer$UIResource");

        // Numbers
        setLazyRenderer(Number.class, "javax.swing.JTable$NumberRenderer");

        // Doubles and Floats
        setLazyRenderer(Float.class, "javax.swing.JTable$DoubleRenderer");
        setLazyRenderer(Double.class, "javax.swing.JTable$DoubleRenderer");

        // Dates
        setLazyRenderer(Date.class, "javax.swing.JTable$DateRenderer");

        // Icons and ImageIcons
        setLazyRenderer(Icon.class, "javax.swing.JTable$IconRenderer");
        setLazyRenderer(ImageIcon.class, "javax.swing.JTable$IconRenderer");

        // Booleans
        setLazyRenderer(Boolean.class, "javax.swing.JTable$BooleanRenderer");
    }
  • 源码中就有渲染器专门处理bool类型的,那么我们只需要在getColumnClass进行处理就行了,在我们的bool的单元格返回bool类JTable就会采用bool类型的渲染器了。
代码语言:scss复制
return getValueAt(0, c).getClass();
  • 这样我们就可以显示一些其他的控件了,还有一些比如每行都需要一行按钮来实现修改改行的功能,这些按钮正常我们不需要再数据中添加(避免数据过于庞大),如果不在数据中添加那么我们的getClass方法就起不到作用,这个用到了下面的知识来解决

JTable渲染和编辑


  • 这种呢其实就是上面的getClass底层的实现方式,JTable中源码我们上面可以看出JTable通过返回的不同的类来调用不同的渲染器,现在我们不通过返回类的方式来渲染,而是自己定义一个渲染器,然后通过JTable提供的方法设定用该渲染器渲染该单元格!
代码语言:txt复制
setCellEditor和setCellRenderer
  • 大家可以观察源码,在JTable的编辑器中AbstractCellEditor是基础的抽象类,他继承了CellEditor,怎么样熟悉吗,这个不就是和AbstractTableModel 是一样的吗。但是这个类不能反回控件需要和TableCellEditor结合使用,或者我们只是用另外一个基础类DefaultCellEditor,
  • DefaultCellEditor和AbstractTableModel 有设么区别呢,他们都是一样实现了CellEditor接口,但是前者构造中只能传入控件,也就是说每日次实力只能通过不同构造函数构建不同的控件,但是后者是抽象类,继承的类可以自定义构造函数,这就方便我们够赞多个不同的控件了,所以这两个大家看情况使用。最后都是通过getTableCellEditorComponent这个函数将控件返回出去。
  • 设置完了编辑器,我们最终要是只渲染器,就是JTable最终如何显示的问题。和上面的那个一样。继承TableCellRenderer类,通过getTableCellRendererComponent方法返回渲染成设么控件,渲染的控件我们可以进行二次封装。
  • 调用如下 两个参数就是通过上面两个类构造的类
代码语言:text复制
column.setCellEditor(editor);

      
column.setCellRenderer(renderer);

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞