I'd like to automate putting a jTextField next to an ImageIcon on the same row basically, for as many rows as I'd like.
I need to do this process depending on how many images I provided as input that's why a manual solution doesn't work for me.
This is an example of what I'd like it to look like. As you can see, an image with a text field next to it for as many rows as I need:
i am working with Java Swing
here is what i tried now in this exemple :
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));
*/
String path = "C:\\Users\\ibrahim\\Desktop\\MARKS";
File folder = new File(path);
File[] listOfFiles = folder.listFiles();
DefaultListModel listModel = new DefaultListModel();
int count = 0;
for (int i = 0; i < listOfFiles.length; i++) {
System.out.println("check path" + listOfFiles[i]);
String name = listOfFiles[i].toString();
// load only png
if (name.endsWith("png")) {
images.add(new ImageText(createBufferedImage(name), name));
}
} }
and this is the result it shows me path of image not the image
Here's the GUI I came up with.
To use this GUI, you would select the first row that you want to correct with the mouse, and type the corrected text into the row.
Press the Enter key to put your cursor on the next row. You can skip a row by pressing the Enter key without typing anything.
When you've made all the corrections, left-click on the Save Corrections button.
When I create a Swing GUI, I use the model / view / controller (MVC) pattern. This pattern allows me to separate my concerns and focus on one part of the GUI at a time.
Using Java Swing, the MVC pattern is implemented this way:
There's usually not one controller class to "rule them all". Each ActionListener
acts as an independent controller.
For this project, I created two model classes, a view class, a JTable
cell renderer class, and one controller class.
I created two model classes. The ImageText
class holds an OCR image, the OCR text, and the corrected text. This keeps the corrections separate and allows easier verification of the correctness of the code.
The ImageTextModel
class holds a java.util.List
of ImageText
instances. Since you didn't provide any OCR image examples, I created some from the text. This is where you would read the OCR images and the OCR text and put the values into the List
.
I started the Swing application with a call to the SwingUtilities
invokeLater
method. This method ensures that all Swing components are created and executed on the Event Dispatch Thread.
I created one JFrame
and two JPanels
. The JFrame
methods must be executed in a specific order. This is the order I use for all my Swing applications.
The upper JPanel
holds the JTable
. The lower JPanel
holds the JButton
. The ImageCellRenderer
class allows me to display the BufferedImage
in the JTable
.
I use Swing layout managers to create the JPanels
and pack the JFrame
. This allows the layout managers to place the Swing components and make the JFrame
as small as possible.
The ButtonListener
class prints the corrected text. Here's where you would write the corrected OCR text to your file system.
Here's the complete runnable code. I made all the classes inner classes so I could post the code as one block.
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;
}
}
}