简介
这是我想出的 GUI。
要使用此 GUI,您可以用鼠标选择要更正的第一行,然后在该行中键入更正后的文本。
按 Enter 键将光标放在下一行。您可以通过按 Enter 键跳过一行,而无需输入任何内容。
完成所有更正后,左键单击“保存更正”按钮。
说明
当我创建 Swing GUI 时,我使用 model / view / controller (MVC) 模式。这种模式让我可以将关注点分开,一次只关注 GUI 的一个部分。
使用 Java Swing,MVC 模式是这样实现的:
- 视图从模型中读取信息。
- 视图不更新模型。
- 控制器更新模型并重新绘制/重新验证视图。
通常没有一个控制器类可以“统辖”它们。每个ActionListener 充当一个独立的控制器。
对于这个项目,我创建了两个模型类,一个视图类、一个JTable 单元渲染器类和一个控制器类。
型号
我创建了两个模型类。 ImageText 类包含 OCR 图像、OCR 文本和更正后的文本。这样可以将更正分开,并允许更轻松地验证代码的正确性。
ImageTextModel 类拥有java.util.List 的ImageText 实例。由于您没有提供任何 OCR 图像示例,因此我从文本中创建了一些示例。您可以在此处读取 OCR 图像和 OCR 文本并将值放入 List。
查看
我通过调用 SwingUtilities invokeLater 方法启动了 Swing 应用程序。此方法确保所有 Swing 组件都在 Event Dispatch Thread 上创建和执行。
我创建了一个JFrame 和两个JPanels。 JFrame 方法必须按特定顺序执行。这是我用于所有 Swing 应用程序的顺序。
上面的JPanel 包含JTable。较低的JPanel 包含JButton。 ImageCellRenderer 类允许我在 JTable 中显示 BufferedImage。
我使用Swing layout managers 创建JPanels 并打包JFrame。这允许布局管理器放置 Swing 组件并使JFrame 尽可能小。
控制器
ButtonListener 类打印更正后的文本。您可以在此处将更正后的 OCR 文本写入文件系统。
代码
这是完整的可运行代码。我把所有的类都做成了内部类,这样我就可以将代码作为一个块发布。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class ImageTextGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new ImageTextGUI());
}
private final OCRTableModel tableModel;
private final ImageTextModel model;
public ImageTextGUI() {
this.tableModel = new OCRTableModel();
this.model = new ImageTextModel();
}
@Override
public void run() {
JFrame frame = new JFrame("Image Text GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createJTablePanel(), BorderLayout.CENTER);
frame.add(createButtonPanel(), BorderLayout.AFTER_LAST_LINE);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createJTablePanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
tableModel.addColumn("OCR Image");
tableModel.addColumn("OCR Text");
tableModel.addColumn("Corrected Text");
for (ImageText imageText : model.getImages()) {
Object[] object = new Object[3];
object[0] = imageText.getImage();
object[1] = imageText.getOcrText();
object[2] = imageText.getCorrectedText();
tableModel.addRow(object);
}
JTable table = new JTable(tableModel);
table.getColumnModel().getColumn(0).setPreferredWidth(220);
table.getColumnModel().getColumn(1).setPreferredWidth(200);
table.getColumnModel().getColumn(2).setPreferredWidth(200);
table.setDefaultRenderer(BufferedImage.class, new ImageRenderer());
table.setRowHeight(40);
JScrollPane scrollPane = new JScrollPane(table);
panel.add(scrollPane, BorderLayout.CENTER);
panel.setPreferredSize(new Dimension(670, panel.getPreferredSize().height));
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new FlowLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
JButton button = new JButton("Save Corrections");
button.addActionListener(new ButtonListener());
panel.add(button);
return panel;
}
public class OCRTableModel extends DefaultTableModel {
private static final long serialVersionUID = 1L;
@Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex < 3) {
return getValueAt(0, columnIndex).getClass();
} else {
return JButton.class;
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return (columnIndex == 2);
}
}
public class ImageRenderer implements TableCellRenderer {
JPanel panel = new JPanel(new FlowLayout());
JLabel label = new JLabel();
@Override
public Component getTableCellRendererComponent(JTable table,
Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
label.setIcon(new ImageIcon((BufferedImage) value));
panel.add(label);
return panel;
}
}
public class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
model.saveImages(tableModel);
}
}
public class ImageTextModel {
private final List<ImageText> images;
public ImageTextModel() {
this.images = new ArrayList<>();
// This is where you would read the OCR images and OCR text from your
// file system and add the information to the List. I generated OCR images to
// make the GUI look more realistic.
String name = "John Smith";
images.add(new ImageText(createBufferedImage(name), name));
name = "George Washington";
images.add(new ImageText(createBufferedImage(name), name));
name = "John Adams";
images.add(new ImageText(createBufferedImage(name), name));
name = "Thomas Jefferson";
images.add(new ImageText(createBufferedImage(name), name));
}
private BufferedImage createBufferedImage(String text) {
BufferedImage image = new BufferedImage(200, 30, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, image.getWidth(), image.getHeight());
g2d.setColor(Color.BLACK);
int pointSize = 20;
Font font = new Font("Arial", Font.BOLD, pointSize);
FontMetrics fm;
Rectangle2D r;
do {
g2d.setFont(font);
fm = g2d.getFontMetrics();
r = fm.getStringBounds(text, g2d);
pointSize -= 2;
font = font.deriveFont((float) pointSize);
} while (image.getWidth() < r.getWidth());
int x = (image.getWidth() - (int) r.getWidth()) / 2;
int y = (image.getHeight() - (int) r.getHeight()) / 2 + fm.getAscent();
g2d.drawString(text, x, y);
g2d.dispose();
return image;
}
public void saveImages(OCRTableModel tableModel) {
for (int row = 0; row < tableModel.getRowCount(); row++) {
String correctedText = (String) tableModel.getValueAt(row, 2);
System.out.println(correctedText);
// Here's where you would write the corrected text to a file
if (!correctedText.isBlank()) {
images.get(row).setCorrectedText(correctedText);
}
}
}
public List<ImageText> getImages() {
return images;
}
}
public class ImageText {
private final BufferedImage image;
private final String ocrText;
private String correctedText;
public ImageText(BufferedImage image, String ocrText) {
this.image = image;
this.ocrText = ocrText;
this.correctedText = "";
}
public String getCorrectedText() {
return correctedText;
}
public void setCorrectedText(String correctedText) {
this.correctedText = correctedText;
}
public String getOcrText() {
return ocrText;
}
public BufferedImage getImage() {
return image;
}
}
}