ocr_recognition/src/main/java/com/ytlk/ocr/OCRSwingArea.java

536 lines
25 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.ytlk.ocr;
import com.ytlk.huidan.table.ButtonRenderer;
import com.ytlk.huidan.table.LabelRenderer;
import com.ytlk.ocr.table.*;
import com.ytlk.ocr.util.FileUtils;
import com.ytlk.ocr.vo.UserErrorVo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
public class OCRSwingArea extends JFrame {
private static OCRSwingArea instance = null;
public static JTable table;
public static JTable table2;
public static final int MAX_FILE_NUM = 5;
private OCRSwingArea() {
setOpacity(0.0f);
this.setTitle("工资发放OCR识别与核对工具");
this.setResizable(false);
// this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setBounds(0, 0, 1000, 565);
setLocationRelativeTo(null);
getContentPane().setLayout(null);
getContentPane().setBackground(new Color(236, 236, 248));
/**********************工资册源版文件导入Excel表格*******************/
JLabel label1 = new JLabel("工资册源版文件导入:");
label1.setHorizontalAlignment(JLabel.LEFT);
label1.setFont(new Font("微软雅黑", Font.BOLD, 14));
label1.setBounds(15, 10, 160, 30);
label1.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
getContentPane().add(label1);
JLabel label2 = new JLabel("(Excel表格)");
label2.setHorizontalAlignment(JLabel.LEFT);
label2.setFont(new Font("微软雅黑", Font.BOLD, 14));
label2.setBounds(45, 30, 100, 30);
label2.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
getContentPane().add(label2);
// 添加文件按钮
JButton selectFile = new JButton("添加");
selectFile.setFont(new Font("微软雅黑", Font.PLAIN, 15));
selectFile.setBounds(200, 20, 80, 30);
getContentPane().add(selectFile);
// 重置文件按钮
JButton resetFile = new JButton("重置");
resetFile.setFont(new Font("微软雅黑", Font.PLAIN, 15));
resetFile.setBounds(300, 20, 80, 30);
getContentPane().add(resetFile);
// 文件表格
FileTableModel fileTableModel = new FileTableModel();
table = new JTable(fileTableModel);
table.setRowSelectionAllowed(false);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn labelColumn = table.getColumn("文件");
labelColumn.setCellRenderer(new LabelRenderer());
labelColumn.setPreferredWidth(390);
TableColumn buttonColumn = table.getColumn("操作");
buttonColumn.setPreferredWidth(80);
buttonColumn.setCellRenderer(new ButtonRenderer());
buttonColumn.setCellEditor(new OCRTableCellEditorButton());
JScrollPane statusScrollPane1 = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
statusScrollPane1.setBounds(15, 60, 480, 350);
getContentPane().add(statusScrollPane1);
/**********************工资册源版文件导入:添加按钮监听事件*******************/
selectFile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setMultiSelectionEnabled(true);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setFileFilter(new FileNameExtensionFilter("Excel Files (*.xls, *.xlsx)", "xls", "xlsx"));
fc.setAcceptAllFileFilterUsed(false);
int val = fc.showOpenDialog(null); // 文件打开对话框
if (val == fc.APPROVE_OPTION) {
// 正常选择文件
File[] fs = fc.getSelectedFiles();
boolean flag = FileUtils.getTableFileName(fileTableModel, fs);
if (flag) {
JOptionPane.showMessageDialog(null, "请勿选择相同工资册源版文件");
return;
}
int isExceedFileNum = FileUtils.isExceedFileNum(fileTableModel, fs);
if (isExceedFileNum > MAX_FILE_NUM) {
JOptionPane.showMessageDialog(null, "工资册源版文件超出" + MAX_FILE_NUM + "个文件限制");
return;
}
for (File f : fs) {
fileTableModel.addRow(new Object[]{f, ""});
OCRSwingArea.table.setValueAt(0, table.getRowCount() - 1, 1);
}
}
}
});
/**********************工资册源版文件导入:重置按钮监听事件*******************/
resetFile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int rows = fileTableModel.getRowCount();
if (rows > 0) {
for (int i = rows - 1; i >= 0; i--) {
fileTableModel.removeRow(i);
}
}
}
});
/**********************工资册签字版导入PDF*******************/
JLabel label3 = new JLabel("工资册签字版导入:");
label3.setHorizontalAlignment(JLabel.LEFT);
label3.setFont(new Font("微软雅黑", Font.BOLD, 14));
label3.setBounds(500, 10, 160, 30);
label3.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
getContentPane().add(label3);
JLabel label4 = new JLabel("PDF");
label4.setHorizontalAlignment(JLabel.LEFT);
label4.setFont(new Font("微软雅黑", Font.BOLD, 14));
label4.setBounds(530, 30, 100, 30);
label4.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
getContentPane().add(label4);
// 添加文件按钮2
JButton selectFile2 = new JButton("添加");
selectFile2.setFont(new Font("微软雅黑", Font.PLAIN, 15));
selectFile2.setBounds(650, 20, 80, 30);
getContentPane().add(selectFile2);
// 重置文件按钮2
JButton resetFile2 = new JButton("重置");
resetFile2.setFont(new Font("微软雅黑", Font.PLAIN, 15));
resetFile2.setBounds(750, 20, 80, 30);
getContentPane().add(resetFile2);
// 文件表格2
FileTableModel fileTableModel2 = new FileTableModel();
table2 = new JTable(fileTableModel2);
table2.setRowSelectionAllowed(false);
table2.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
TableColumn buttonColumn2 = table2.getColumn("操作");
buttonColumn2.setPreferredWidth(80);
buttonColumn2.setCellRenderer(new ButtonRenderer());
buttonColumn2.setCellEditor(new OCRTableCellEditorButton2());
TableColumn labelColumn2 = table2.getColumn("文件");
labelColumn2.setCellRenderer(new LabelRenderer());
labelColumn2.setPreferredWidth(390);
JScrollPane statusScrollPane2 = new JScrollPane(table2, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
statusScrollPane2.setBounds(500, 60, 480, 350);
getContentPane().add(statusScrollPane2);
/**********************工资册签字版导入:添加按钮监听事件*******************/
selectFile2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
fc.setMultiSelectionEnabled(true);
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setFileFilter(new FileNameExtensionFilter("PDF Documents", "pdf"));
// fc.setFileFilter(new FileNameExtensionFilter("Excel Files (*.xls, *.xlsx)", "xls", "xlsx"));
fc.setAcceptAllFileFilterUsed(false);
int val = fc.showOpenDialog(null); // 文件打开对话框
if (val == fc.APPROVE_OPTION) {
// 正常选择文件
File[] fs = fc.getSelectedFiles();
boolean flag = FileUtils.getTableFileName(fileTableModel2, fs);
if (flag) {
JOptionPane.showMessageDialog(null, "请勿选择相同工资册签字版文件");
return;
}
int isExceedFileNum = FileUtils.isExceedFileNum(fileTableModel2, fs);
if (isExceedFileNum > MAX_FILE_NUM) {
JOptionPane.showMessageDialog(null, "工资册签字版文件超出" + MAX_FILE_NUM + "个文件限制");
return;
}
for (File f : fs) {
fileTableModel2.addRow(new Object[]{f, ""});
OCRSwingArea.table2.setValueAt(0, table2.getRowCount() - 1, 1);
}
}
}
});
/**********************工资册签字版导入:重置按钮监听事件*******************/
resetFile2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int rows = fileTableModel2.getRowCount();
if (rows > 0) {
for (int i = rows - 1; i >= 0; i--) {
fileTableModel2.removeRow(i);
}
}
}
});
/**********************提示*******************/
JLabel label5 = new JLabel("1.支持批量导入进行核定");
label5.setHorizontalAlignment(JLabel.LEFT);
label5.setFont(new Font("微软雅黑", Font.PLAIN, 14));
label5.setBounds(15, 430, 350, 30);
label5.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
label5.setForeground(Color.RED);
getContentPane().add(label5);
JLabel label6 = new JLabel("2.请保证需核对的Excel与PDF文件名称一致");
label6.setHorizontalAlignment(JLabel.LEFT);
label6.setFont(new Font("微软雅黑", Font.PLAIN, 14));
label6.setBounds(43, 450, 350, 30);
label6.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
label6.setForeground(Color.RED);
getContentPane().add(label6);
JLabel label7 = new JLabel("3.请保证文件中包含有【姓名】【实发工资】字段");
label7.setHorizontalAlignment(JLabel.LEFT);
label7.setFont(new Font("微软雅黑", Font.PLAIN, 14));
label7.setBounds(43, 470, 350, 30);
label7.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
label7.setForeground(Color.RED);
getContentPane().add(label7);
JLabel label8 = new JLabel("4.Excel文件、PDF文件最多只能各上传五个文件");
label8.setHorizontalAlignment(JLabel.LEFT);
label8.setFont(new Font("微软雅黑", Font.PLAIN, 14));
label8.setBounds(43, 490, 350, 30);
label8.setVerticalAlignment(SwingConstants.CENTER); // 设置垂直对齐方式
label8.setForeground(Color.RED);
getContentPane().add(label8);
/**********************开始核对*******************/
JButton startCheckBtn = new JButton("开 始 核 对");
startCheckBtn.setFont(new Font("微软雅黑", Font.BOLD, 18));
startCheckBtn.setBounds(500, 450, 400, 40);
getContentPane().add(startCheckBtn);
startCheckBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int rowCount = fileTableModel.getRowCount();
int rowCount2 = fileTableModel2.getRowCount();
setButtonDisable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
if (rowCount == 0) {
JOptionPane.showMessageDialog(null, "请先上传工资册源版文件");
setButtonEnable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
return;
}
if (rowCount2 == 0) {
JOptionPane.showMessageDialog(null, "请先上传工资册签字版文件");
setButtonEnable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
return;
}
boolean flag = FileUtils.fileIsEquality(fileTableModel, fileTableModel2);
if (flag) {
JOptionPane.showMessageDialog(null, "请确保工资册源版文件与工资册签字版文件数量相等");
setButtonEnable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
return;
}
boolean flag2 = FileUtils.fileNameIsEquality(fileTableModel, fileTableModel2);
if (flag2) {
JOptionPane.showMessageDialog(null, "请确保工资册源版文件与工资册签字版文件文件名称一致");
setButtonEnable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
return;
}
showLoadingDialog(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
}
});
// 添加 WindowAdapter 关闭的监听事件
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.out.println("窗口正在关闭");
// 在这里执行关闭前的操作
int rows = fileTableModel.getRowCount();
if (rows > 0) {
for (int i = rows - 1; i >= 0; i--) {
fileTableModel.removeRow(i);
}
}
int rows2 = fileTableModel2.getRowCount();
if (rows2 > 0) {
for (int i = rows2 - 1; i >= 0; i--) {
fileTableModel2.removeRow(i);
}
}
}
});
}
public void setButtonEnable(JButton selectFile, JButton selectFile2, JButton resetFile, JButton resetFile2, JButton startCheckBtn) {
selectFile.setEnabled(true);
selectFile2.setEnabled(true);
resetFile.setEnabled(true);
resetFile2.setEnabled(true);
startCheckBtn.setEnabled(true);
}
public void setButtonDisable(JButton selectFile, JButton selectFile2, JButton resetFile, JButton resetFile2, JButton startCheckBtn) {
selectFile.setEnabled(false);
selectFile2.setEnabled(false);
resetFile.setEnabled(false);
resetFile2.setEnabled(false);
startCheckBtn.setEnabled(false);
}
/**
* 执行比较结果
*
* @param selectFile
* @param selectFile2
* @param resetFile
* @param resetFile2
* @param startCheckBtn
* @return void
* @author cwchen
* @date 2025/3/11 17:19
*/
public void showLoadingDialog(JButton selectFile, JButton selectFile2, JButton resetFile, JButton resetFile2, JButton startCheckBtn) {
JFrame parent = this;
// 创建加载框
JDialog loadingDialog = new JDialog(parent, "核对中", true);
loadingDialog.setSize(400, 150);
loadingDialog.setLocationRelativeTo(parent);
// 禁用关闭按钮
loadingDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
// 添加加载提示
JLabel label = new JLabel("正在处理中,请稍后...", SwingConstants.CENTER);
label.setFont(new Font("微软雅黑", Font.PLAIN, 16));
label.setBounds(15, 10, 400, 30);
JLabel label2 = new JLabel("等待时间可能较长正在OCR识别、表格提取、数据比对中...", SwingConstants.CENTER);
label2.setFont(new Font("微软雅黑", Font.PLAIN, 12));
label2.setBounds(15, 30, 400, 30);
loadingDialog.add(label);
loadingDialog.add(label2);
new Thread(() -> {
try {
Object obj = HandleDataUtil.handleData();
if (obj instanceof String) {
String checkExcelData = (String) obj;
if (StringUtils.isNotBlank(checkExcelData)) {
// 任务完成后关闭加载框
loadingDialog.dispose();
setButtonEnable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
JOptionPane.showMessageDialog(null, checkExcelData);
}
} else if (obj instanceof List) {
loadingDialog.dispose();
setButtonEnable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
List<Map<String, Object>> errorDataList = (List<Map<String, Object>>) obj;
showModalDialog(errorDataList);
}
} catch (Exception e) {
e.printStackTrace();
// 任务完成后关闭加载框
loadingDialog.dispose();
setButtonEnable(selectFile, selectFile2, resetFile, resetFile2, startCheckBtn);
}
}).start();
// 显示加载框
loadingDialog.setVisible(true);
}
public void showModalDialog(List<Map<String, Object>> errorDataList) {
JFrame parent = this;
// 创建模态对话框
JDialog dialog = new JDialog(parent, "比对结果", true); // true表示模态
dialog.setSize(690, 450);
dialog.setLocationRelativeTo(parent); // 相对于父窗口居中显示
dialog.setLayout(new FlowLayout());
JPanel parentContentPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0; // 列索引
gbc.fill = GridBagConstraints.HORIZONTAL; // 水平填充
gbc.weightx = 1; // 水平权重
parentContentPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); // 设置内边距
String[] columnNames = {"姓名", "Excel表格实发工资", "PDF实发工资","异常项"};
for (int i = 0; i < errorDataList.size(); i++) {
Map<String, Object> map = errorDataList.get(i);
JPanel childContentPanel = new JPanel();
childContentPanel.setLayout(new BoxLayout(childContentPanel, BoxLayout.Y_AXIS)); // 垂直布局
String fileName = (String) map.get("fileName");
List<UserErrorVo> errorList = (List<UserErrorVo>) map.get("errorList");
JLabel label = new JLabel(fileName);
JLabel label2 = new JLabel(" 异常数据" + errorList.size() + "");
JButton toggleButton = new JButton("收起/展开");
toggleButton.setPreferredSize(new Dimension(80, 30));
label2.setForeground(Color.RED);
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); // 左对齐
panel.add(label);
panel.add(label2);
panel.add(toggleButton);
childContentPanel.add(panel);
if (CollectionUtils.isNotEmpty(errorList)) {
ErrorTableModel errorTableModel = new ErrorTableModel(errorList, columnNames);
JTable errorTable = new JTable(errorTableModel);
errorTable.setRowSelectionAllowed(false);
errorTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
errorTable.setRowHeight(25); // 设置行高
TableColumn cellColumn = errorTable.getColumn("姓名");
cellColumn.setPreferredWidth(100);
TableColumn cellColumn2 = errorTable.getColumn("Excel表格实发工资");
cellColumn2.setPreferredWidth(150);
TableColumn cellColumn3 = errorTable.getColumn("PDF实发工资");
cellColumn3.setPreferredWidth(150);
TableColumn cellColumn4 = errorTable.getColumn("异常项");
cellColumn4.setPreferredWidth(200);
JScrollPane jScrollPane = new JScrollPane(errorTable, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
JPanel panel2 = new JPanel();
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS)); // 垂直排列
panel2.add(jScrollPane);
// 计算表格总高度
int rowHeight = errorTable.getRowHeight();
int rowCount = errorTable.getRowCount();
int tableHeight = rowHeight * rowCount + 50;
panel2.setPreferredSize(new Dimension(600, tableHeight));
toggleButton.addActionListener(new ToggleListener(panel2)); // 为每个按钮添加监听器
childContentPanel.add(panel2);
}
gbc.gridy = i; // 行索引
parentContentPanel.add(childContentPanel,gbc);
}
gbc.gridy = errorDataList.size() + 1;
gbc.weighty = 1; // 垂直权重,使组件占满剩余空间
gbc.fill = GridBagConstraints.BOTH; // 组件水平和垂直填充
parentContentPanel.add(new JLabel(""), gbc); // 添加一个空标签占位
// 创建JScrollPane并设置其滚动条策略可选
JScrollPane scrollPane = new JScrollPane(parentContentPanel);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); // 水平滚动条按需显示
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); // 垂直滚动条按需显示
scrollPane.setPreferredSize(new Dimension(660, 400)); // 设置滚动面板的尺寸,以适应内容或手动设置大小
dialog.add(scrollPane);
dialog.setVisible(true);
}
public String getTime(String time) {
if (time.startsWith("0")) {
return time.substring(1);
} else {
return time;
}
}
public File getCurrenPath() {
try {
String path = this.getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
path = java.net.URLDecoder.decode(path, "UTF-8");
File file = new File(path);
if (file.isFile()) {
return new File(file.getParent());
} else {
return file;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public void deleteTemp() {
File path = getCurrenPath();
File dir = path.getParentFile();
for (File f : dir.listFiles()) {
if (!f.getAbsoluteFile().equals(path.getAbsolutePath())) {
File zb = new File(f.getAbsoluteFile() + File.separator + "hdpdf.jar");
if (zb.exists()) {
for (File t : f.listFiles()) {
t.delete();
}
f.delete();
}
}
}
}
public File getCurrentJarDir() {
try {
File f = new File(".");
if (f.exists()) {
return f;
}
return getCurrenPath();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private JPanel createLabel(String v, List<String> kws, JPanel sp) {
// Icon icon = new ImageIcon(getClass().getResource("/close.jpg"));
JPanel p = new JPanel();
p.setLayout(new BorderLayout());
JLabel lbl = new JLabel(v);
lbl.setFont(new Font("微软雅黑", Font.PLAIN, 16));
// p.setBorder(BorderFactory.createLineBorder(Color.gray));
p.add(lbl, BorderLayout.CENTER);
JButton bt = new JButton("X");
// bt.setIcon(icon);
bt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
remove(v, kws, sp);
}
});
p.add(bt, BorderLayout.EAST);
return p;
}
private void remove(String v, List<String> keywords, JPanel sp) {
for (int i = keywords.size() - 1; i >= 0; i--) {
if (keywords.get(i).equals(v)) {
keywords.remove(i);
break;
}
}
sp.removeAll();
for (String k : keywords) {
JPanel p = createLabel(k, keywords, sp);
sp.add(p);
}
sp.revalidate();
sp.repaint();
}
public static OCRSwingArea getInstance() {
if (null == instance) {
synchronized (OCRSwingArea.class) {
if (null == instance) {
instance = new OCRSwingArea();
}
}
}
return instance;
}
public void initUI() {
this.setVisible(true);
deleteTemp();
}
}