一、序
最近公司做的项目里出现了一个新的需求,项目大部分是为金融业定制开发的数据集成平台,包括数据的采集,处理,使用。
数据的采集方式不固定,有机构化数据,有非结构话数据,还有附件等其它文件形式。
对于采集端,大部分要求具备硬件服务器架设能力,这时就出现了一个问题,有些采集端是不具备硬件服务器架设能力的,或者主观上不愿意架设,
要求公司拿出一套可以不假设服务器,而是和中心服务器交互。
功能精简为:只保留数据采集,数据结果由中心服务器来提供,客户端安装模式。
二、解决:
我们是JAVA,要开发客户端,那就是AWT、SWING,业内也一直都说是C#更适合开发。
老板一句话,两周之内要产品,没办法,还是用熟悉的SWING吧。遇到了很多问题,中间很坎坷,在这里记录一下:
(1)页面的设计嵌套时,要整个包裹好再放入另一个容器里,这样就可以保证样式
(2)SWING时间控件的选择很少,第三方的时间控件又很难满足具体项目的定制需求
(3)表格的分页,表格单元格显示复选框的感觉很别扭
三、重点:
(1)框架居中:
//第一种居中方式(为空时默认居中) this.setLocationRelativeTo(null); //第二种居中方式(获取屏幕来居中) int width = (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth(); int height = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight(); this.setBounds((int)(width/2-500/2), (int)(height/2-350/2), 500, 350); //this.setUndecorated(true); this.setResizable(false);(2)分割框的分割比重
//第一种设置方式,不具有强制性,有可能设置失败 panel_split.setResizeWeight(0.6); //第二种设置方式,可以指定分割框所占的比重 panel_split.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { panel_split.setDividerLocation(1.0 / 4.0); } }); panel_split.setOrientation(JSplitPane.VERTICAL_SPLIT);(3)表格插入图片的时候显示字符串
//其中6、7均为格式需要转换为图片的列位置 table = new JTable(model){ @SuppressWarnings({ "unchecked", "rawtypes" }) public Class getColumnClass(int column) { if (column==6 && model.getDataVector().size()>0) { return getValueAt(0, 6).getClass(); } else if(column==7 && model.getDataVector().size()>0) { return getValueAt(0, 7).getClass(); } else { return getValueAt(0, 0).getClass(); } } }; //图片数据列的插入 row.addElement(new ImageIcon(this.getClass().getClassLoader().getResource("reload.png"))); //普通字串数据列的插入 row.add(data.get("FILE_ID")==null?new String(""):data.get("FILE_ID"));(4)分页对象
//分页对象 package com.dis.view; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; @SuppressWarnings("serial") public abstract class SubPageBar extends JPanel implements ItemListener, ActionListener { private int allCount, fromRec, endRec, pageSize, pageIndex, pageCount; private JLabel allCountLab, curCountLab, pageIndexLab; @SuppressWarnings("rawtypes") private JComboBox eachCom; // 首页 private JButton firstPageButton; // 前一页 private JButton latePageButton; // 下一页 private JButton nextPageButton; // 末页 private JButton lastPageButton; public SubPageBar(int recNums) { this.allCount = recNums; initUI(); updateData(); } @SuppressWarnings({ "unchecked", "rawtypes" }) private void initUI() { // comboBox eachCom = new JComboBox(new String[] { "10", "20", "50" }); // label curCountLab = new JLabel(); allCountLab = new JLabel(); pageIndexLab = new JLabel(); // button firstPageButton = new JButton("首页"); latePageButton = new JButton("上一页"); nextPageButton = new JButton("下一页"); lastPageButton = new JButton("末页"); // listener eachCom.addItemListener(this); firstPageButton.addActionListener(this); nextPageButton.addActionListener(this); latePageButton.addActionListener(this); lastPageButton.addActionListener(this); this.setLayout(new FlowLayout(FlowLayout.RIGHT)); this.add(curCountLab); this.add(allCountLab); this.add(new JLabel("每页")); this.add(eachCom); this.add(new JLabel("条")); this.add(firstPageButton); this.add(latePageButton); this.add(pageIndexLab); this.add(nextPageButton); this.add(lastPageButton); } /** * @Description: (更新分页栏的值) */ private void updateData() { // 必须知道的参数值:allCount pageIndex pageSize pageSize = Integer.valueOf(eachCom.getSelectedItem().toString()); fromRec = pageIndex * pageSize + 1; if (0 == allCount) { fromRec = 0; } endRec = (pageIndex + 1) * pageSize; if (endRec > allCount) { endRec = allCount; } pageSize = (0 == pageSize) ? 1 : pageSize; pageCount = allCount / pageSize - ((0 == allCount % pageSize && 0 != allCount) ? 1 : 0); // curCountLab.setText("第 " + fromRec + "~" + endRec + " 条"); allCountLab.setText("【共有 " + allCount + " 条】 "); pageIndexLab.setText(" 【第 " + (pageIndex) + "/" + (pageCount + 1) + " 页】 "); firstPageButton.setEnabled(pageIndex > 0); latePageButton.setEnabled(pageCount > 0 && pageIndex > 0); nextPageButton.setEnabled(pageIndex < pageCount); lastPageButton.setEnabled(pageCount > 0 && pageIndex < pageCount); } /** * @Description: 有新数据载入时,需要重载 */ public void fresh(int recNums) { this.allCount = recNums; updateData(); } @Override public void itemStateChanged(ItemEvent e) { // 这边之所以要加上这个判断,是因为“选中”和“取消选中”都会触发ItemEvent. if (e.getStateChange() == ItemEvent.SELECTED) { pageIndex = 0; pageSize = Integer.valueOf(eachCom.getSelectedItem().toString()); updateData(); onPageSizeChange(pageSize); } } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == firstPageButton) { pageIndex = 1; onClickPreButton(pageIndex); } else if (e.getSource() == latePageButton) { pageIndex--; onClickPreButton(pageIndex); } else if (e.getSource() == nextPageButton) { pageIndex++; onClickNextButton(pageIndex); } else if (e.getSource() == lastPageButton) { pageIndex = pageCount; onClickNextButton(pageIndex); } updateData(); } public int getPageIndex() { return (pageIndex>0) ? pageIndex : 1; } public void updatePageIndex(int pageIndex) { this.pageIndex = pageIndex; updateData(); } public int getPageSize() { return pageSize; } public abstract void onPageSizeChange(int newPageSize); public abstract void onClickPreButton(int pageIndex); public abstract void onClickNextButton(int pageIndex); } //分页对象集成 table_col_name = new Vector<>(); table_col_name.add("编号"); table_col_name.add("文件名"); table_col_name.add("机构名"); table_col_name.add("流程名"); table_col_name.add("当前状态"); table_col_name.add("变更时间"); table_col_name.add("操作"); table_col_name.add("重置"); Vector<Vector<Object>> rowData = new Vector<Vector<Object>>(); DefaultTableModel model = new DefaultTableModel(rowData, table_col_name); table = new JTable(model){ @SuppressWarnings({ "unchecked", "rawtypes" }) public Class getColumnClass(int column) { if (column==6 && model.getDataVector().size()>0) { return getValueAt(0, 6).getClass(); } else if(column==7 && model.getDataVector().size()>0) { return getValueAt(0, 7).getClass(); } else { return getValueAt(0, 0).getClass(); } } }; table.getTableHeader().setReorderingAllowed(false);// 限制整列拖动 table.setEnabled(false); table.addMouseListener(tableListener); table_bar = new SubPageBar(0) { @Override public void onPageSizeChange(int newPageSize) { initTable(); } @Override public void onClickPreButton(int pageIndex) { this.updatePageIndex(pageIndex--); initTable(); } @Override public void onClickNextButton(int pageIndex) { this.updatePageIndex(pageIndex++); initTable(); } }; JPanel panel_table = new JPanel(new BorderLayout()); JScrollPane scrollPanel_table = new JScrollPane(); scrollPanel_table.setBorder(border); scrollPanel_table.setViewportView(table); panel_table.add(scrollPanel_table, BorderLayout.CENTER); panel_table.add(table_bar, BorderLayout.SOUTH); scrollPanel_bottom.setViewportView(panel_table); //表格数据加载 //初始化表格 @SuppressWarnings("unchecked") public void initTable() { HashMap<String,String> params = this.getParams(); params.put("page", table_bar.getPageIndex()+""); params.put("rows", table_bar.getPageSize()+""); if (params.get("cycleType")=="-1") { params.remove("cycleType"); } try { //请求数据 // String resultStr = HttpRequest.sendGetRequest(PropertyUtil.readKeyValue(PropertyUtil.CONFIG_FILE_PATH, PropertyUtil.API_GETALLFILE), params,"UTF-8"); String resultStr = HttpRequest.sendGetRequest(Sysconfig.getSysInstance().getProperty(PropertyUtil.API_GETALLFILE), params,"UTF-8"); Page resultPage = GsonUtil.GsonToBean(resultStr, Page.class); //解析数据 int totalCount = resultPage.getTotal(); List<Map<String,String>> fileList = (List<Map<String, String>>) resultPage.getRows(); //渲染表格 table_bar.fresh(totalCount); DefaultTableModel model = (DefaultTableModel) table.getModel(); model.getDataVector().clear(); Vector<Vector<Object>> vData = model.getDataVector(); if(null != fileList && fileList.size() > 0 && totalCount > 0) { Page page = null; page = new Page(totalCount); page.setPageSize(table_bar.getPageSize()); page.setPageNow(pageNow); for (Map<String, String> data : fileList) { Vector<Object> row = new Vector<Object>(); row.add(data.get("FILE_ID")==null?new String(""):data.get("FILE_ID")); row.add(data.get("FILE_NAME")==null?new String(""):data.get("FILE_NAME")); row.add(data.get("BANK_NAME")==null?new String(""):data.get("BANK_NAME")); row.add(data.get("PROCESS_NAME")==null?new String(""):data.get("PROCESS_NAME")); row.add(data.get("NODE_DESC")==null?new String(""):data.get("NODE_DESC")); row.add(data.get("UPDATE_TIME")==null?new String(""): this.parseDate(data.get("UPDATE_TIME"))); row.addElement(new ImageIcon(this.getClass().getClassLoader().getResource("look.png"))); row.addElement(new ImageIcon(this.getClass().getClassLoader().getResource("reload.png"))); row.add(data.get("F_PNODE_STATE")==null?new String(""):data.get("F_PNODE_STATE")); vData.add(row); } } table.getColumnModel().getColumn(7).setCellEditor(new DefaultCellEditor(new JCheckBox())); model.fireTableCellUpdated(0, 7); model.fireTableDataChanged(); } catch (Exception e) { JOptionPane.showMessageDialog(this, "服务地址解析错误!"); e.printStackTrace(); log.error("服务地址解析错误!"); } }
客户端软件gui开发技术漫谈:原生与跨平台解决方案分析_zhoulujun-编程思维
原生开发应用开发 Microsoft阵营的 Winform WinForm是·Net开发平台中对Windows Form的一种称谓。 如果你想深入的美化UI,需要耗费很大的力气,对于目前主流的CSS样式表来讲,美化Winform的界面以及自定义控件是需要耗费更多的时间的。 WPF 基于XML+C#+CSS的呈现方式让它