想给程序增加一个可视化界面。从学习java开始,就一直没有怎么接触过gui编程,gui也确实被妖魔化、边缘化的比较严重。
简单查看了一些资料,发现对图像化的软件十分感兴趣,有些无法自拔的趋势。
一篇关于GUI文章的大神如是写到:“会不能代表什么,但是不会就能代表什么了”。
但迫于时间,只好忍痛,草草收场,导致很多设想没有实现,很多细节也没有完善。
先谈一下对v0.0.3代码的改造。
为了实现进度条功能,在excelUtil中增加了一个excels属性,用来判断excel中需要操作的数据条数。
excelUtil.java 代码如下
package com.crick.excel2word.util;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import com.crick.excel2word.core.enumeration.OfficeFileType;
public class ExcelUtil extends OfficeFileUtil {
public ExcelUtil(String fullPath) {
super(fullPath);
}
private int excels = 0;
public int getExcels() {
return excels;
}
public List<File> scanDirExcel(String dirPath) {
return super.scanDir(dirPath, OfficeFileType.EXCEL_03_TYPE, OfficeFileType.EXCEL_07UP_TYPE);
}
public List<Map<String, Object>> extract() {
List<Map<String, Object>> results = new ArrayList<Map<String,Object>>();
Workbook book;
try {
book = new HSSFWorkbook(new BufferedInputStream(new FileInputStream(getFile())));
Sheet sheet = book.getSheetAt(0);
if (sheet.getLastRowNum() == 0) {
return null;
}
this.excels = sheet.getLastRowNum();
List<String> keys = getKeyList(sheet.getRow(0));
for (int i=sheet.getFirstRowNum()+1; i <= sheet.getLastRowNum(); i++) {
Map<String, Object> param = extractRow(sheet.getRow(i), keys);
results.add(param);
}
} catch (Exception e) {
e.printStackTrace();
}
return results;
}
private Map<String, Object> extractRow(Row row, List<String> keys){
Map<String, Object> params = new HashMap<String, Object>();
for (int i=0; i<row.getLastCellNum(); i++) {
if (keys.get(i) == null || keys.get(i) == "") {
continue;
}
row.getCell(i).setCellType(Cell.CELL_TYPE_STRING);
params.put("#{"+keys.get(i)+"}", row.getCell(i));
}
return params;
}
/**
* 第一行作为key,即mark标签名
*
* @param row
* @return
*/
private List<String> getKeyList(Row row) {
List<String> keys = new ArrayList<String>();
for (int i=0; i<=row.getLastCellNum();i++) {
if (row.getCell(i) != null) {
row.getCell(i).setCellType(Cell.CELL_TYPE_STRING);
}
keys.add(row.getCell(i)==null?"":row.getCell(i).toString().toLowerCase());
}
//如果未指定name标签,则默认第一列为生成的word文件名
if (!keys.contains("name")) {
keys.set(0, "name");
}
return keys;
}
}
因为WordUtil是对单个word文件的操作,无法判断word文件的数量,所以将words属性放在Excel2Words类中,并提供getProgress方法获取进度百分比。
修改后的Excel2Words.java代码如下:
package com.crick.excel2word;
import java.io.File;
import java.util.List;
import java.util.Map;
import com.crick.excel2word.util.ExcelUtil;
import com.crick.excel2word.util.WordUtil;
public class Excel2Words {
private static WordUtil wordUtil;
private static ExcelUtil excelUtil;
private static int words = 0;
private static void init(String wordPath, String excelPath) {
wordUtil = new WordUtil(wordPath);
excelUtil = new ExcelUtil(excelPath);
}
public static void autoExport(String wordPath, String excelPath, String exportDir) {
init(wordPath, excelPath);
if (!exportDir.endsWith(File.separator)) {
exportDir = exportDir.concat(File.separator);
}
List<Map<String, Object>> rowList = excelUtil.extract();
for (Map<String, Object> rowParam : rowList) {
wordUtil.export(rowParam, exportDir, rowParam.get("#{name}").toString());
words++;
}
}
public static int getProgress() {
return words*100/excelUtil.getExcels();
}
}
图形化界面是通过eclipse,基于SWF和JFace制作而成。附Eclipse相关插件地址:http://download.eclipse.org/windowbuilder/WB/release/R201309271200/4.3/
能力有限,只是实现了基本功能,而代码层面,应该也没有达到比较好的实现,所以只是贴出代码,不做讲解。
MainWin.java依赖于v0.0.3打包生成的excel2word-0.0.3-SNAPSHOT-jar-with-dependencies.jar,代码如下:
package gui;
import org.eclipse.jface.action.CoolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.StatusLineManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.crick.excel2word.Excel2Words;
public class MainWin extends ApplicationWindow {
private String wordPath;
private String excelPath;
private String exportDir;
private ProgressBar progressBar;
private Text wordPathText;
private Text excelPathText;
private Text exportDirText;
private void clear() {
wordPath = "";
excelPath = "";
exportDir = "";
wordPathText.setText("");
excelPathText.setText("");
exportDirText.setText("");
progressBar.setSelection(0);
progressBar.dispose();
}
private void showProgress(Composite parent) {
progressBar = new ProgressBar(parent, SWT.NONE);
progressBar.setBounds(20, 200, 550, 25);
progressBar.setMinimum(0);
progressBar.setMaximum(100);
new Thread() {
public void run() {
getShell().getDisplay().asyncExec(new Runnable() {
public void run() {
while (progressBar.getSelection() < progressBar.getMaximum()) {
try {
progressBar.setSelection(Excel2Words.getProgress());
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
MessageDialog.openInformation(getShell(), "完成", "word文件已经生成成功,请在" + exportDirText.getText() + "目录下查看。");
clear();
}
});
}
}.start();
}
/**
* Create the application window,
*/
public MainWin() {
super(null);
addCoolBar(SWT.FLAT);
addMenuBar();
addStatusLine();
}
/**
* Create contents of the application window.
* @param parent
*/
@Override
protected Control createContents(Composite parent) {
final Composite container = new Composite(parent, SWT.NONE);
wordPathText = new Text(container, SWT.H_SCROLL | SWT.CANCEL | SWT.CENTER);
wordPathText.setEditable(false);
wordPathText.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
wordPathText.setFont(new Font(Display.getCurrent(), "微软雅黑", 11, SWT.NORMAL));
wordPathText.setText("word文件");
wordPathText.setBounds(20, 30, 505, 25);
Label label1 = new Label(container, SWT.SEPARATOR | SWT.VERTICAL);
label1.setBounds(527, 30, 2, 25);
final FileDialog wordDialog = new FileDialog(getShell());
Button selectWordBtn = new Button(container, SWT.NONE);
selectWordBtn.setBounds(530, 30, 40, 25);
selectWordBtn.setText("选择");
selectWordBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
wordPath = wordDialog.open();
wordPathText.setText(wordPath);
}
});
excelPathText = new Text(container, SWT.H_SCROLL | SWT.CANCEL | SWT.CENTER);
excelPathText.setEditable(false);
excelPathText.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
excelPathText.setFont(new Font(Display.getCurrent(), "微软雅黑", 11, SWT.NORMAL));
excelPathText.setText("excel文件");
excelPathText.setBounds(20, 70, 505, 25);
Label label2 = new Label(container, SWT.SEPARATOR | SWT.VERTICAL);
label2.setBounds(527, 70, 2, 25);
final FileDialog excelDialog = new FileDialog(getShell());
Button selectExcelBtn = new Button(container, SWT.NONE);
selectExcelBtn.setBounds(530, 70, 40, 25);
selectExcelBtn.setText("选择");
selectExcelBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
excelPath = excelDialog.open();
excelPathText.setText(excelPath);
}
});
exportDirText = new Text(container, SWT.H_SCROLL | SWT.CANCEL | SWT.CENTER);
exportDirText.setEditable(false);
exportDirText.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
exportDirText.setFont(new Font(Display.getCurrent(), "微软雅黑", 11, SWT.NORMAL));
exportDirText.setText("保存路径");
exportDirText.setBounds(20, 110, 505, 25);
Label label3 = new Label(container, SWT.SEPARATOR | SWT.VERTICAL);
label3.setBounds(527, 110, 2, 25);
final DirectoryDialog exportDialog = new DirectoryDialog(getShell());
Button selectExportBtn = new Button(container, SWT.NONE);
selectExportBtn.setBounds(530, 110, 40, 25);
selectExportBtn.setText("选择");
selectExportBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
exportDir = exportDialog.open();
exportDirText.setText(excelPath);
}
});
Button button = new Button(container, SWT.CHECK);
button.setBounds(370, 140, 70, 15);
button.setText("打包压缩");
Button startBtn = new Button(container, SWT.NONE);
startBtn.setBounds(150, 160, 300, 25);
startBtn.setText("开 始");
startBtn.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
showProgress(container);
Excel2Words.autoExport(wordPath, excelPath, exportDir);
}
});
return container;
}
/**
* Create the menu manager.
* @return the menu manager
*/
@Override
protected MenuManager createMenuManager() {
MenuManager menuManager = new MenuManager("menu");
return menuManager;
}
/**
* Create the coolbar manager.
* @return the coolbar manager
*/
@Override
protected CoolBarManager createCoolBarManager(int style) {
CoolBarManager coolBarManager = new CoolBarManager(style);
return coolBarManager;
}
/**
* Create the status line manager.
* @return the status line manager
*/
@Override
protected StatusLineManager createStatusLineManager() {
StatusLineManager statusLineManager = new StatusLineManager();
return statusLineManager;
}
/**
* Launch the application.
* @param args
*/
public static void main(String args[]) {
try {
MainWin window = new MainWin();
//使 open() 阻塞,直到窗口关闭为止
window.setBlockOnOpen(true);
window.open();
Display.getCurrent().dispose();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Configure the shell.
* @param newShell
*/
@Override
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
newShell.setText("Excel parse to Words");
}
/**
* Return the initial size of the window.
*/
@Override
protected Point getInitialSize() {
return new Point(600, 360);
}
}
这时有一个问题:由于是通过eclipse直接创建的SWT/JFace项目,所以依赖了众多的eclipse插件的jar包文件。
怎么能判断出项目依赖了哪些jar包,筛选出必需的依赖包呢?
第一步:利用eclipse将项目打包成jar文件。
第二步:通过-verbose:class判断使用了哪些.class文件
java -jar -verbose:class excel2word-0.0.4.jar >>dependents.txt
因为v0.0.4只有一个java文件,否则,则需要把各功能都使用一遍,以此找到所有的依赖文件。
dependents.txt中生成的文件内容如下:
第四步:将依赖的jar文件复制到新目录内。
将这两步放在一起的原因是因为我们要通过程序实现,我直接遍历的eclipse的plugins目录,具体代码如下:
package util;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
public class CopyDependentJar {
public static void main(String[] args) throws IOException {
String classTxt = readClassTxt();
File file = new File("D:\\eclipse_kepler\\plugins");
for (File f : file.listFiles()) {
if (classTxt.contains(f.getName())) {
copy(f, "D:\\cut\\dependents");
}
}
}
private static String readClassTxt() throws IOException {
File file = new File("D:\\cut\\dependents.txt");
BufferedReader re = new BufferedReader(new FileReader(file));
StringBuffer sb = new StringBuffer();
String line = re.readLine();
while (line != null) {
sb.append(line);
line = re.readLine();
}
re.close();
return sb.toString();
}
private static void copy(File srcFile, String outDirPath) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
File outDir = new File(outDirPath);
if (!outDir.exists()) {
outDir.mkdir();
}
File outFile = new File(outDirPath + File.separator + srcFile.getName());
if (!outFile.exists()) {
outFile.createNewFile();
}
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile));
byte[] chs = new byte[1024];
int len = bis.read(chs, 0, chs.length);
while(len != -1){
bos.write(chs, 0, len);
len = bis.read(chs, 0, chs.length);
}
bos.close();
bis.close();
}
}
将dependents目录下的文件和excel2word-0.0.3-SNAPSHOT-jar-with-dependencies.jar一起放入项目的lib目录下,添加依赖,ok,搞定。