Hi, i know this sounds awkward but here's my situation.
I wrote a small app that automates input into external programs,and to log actions i'm using a JTextArea in some sort of console view of what's going on from inside the application.
now what's really happening is that while the automation is running, text in the text area does not get updated but once it finishes, it does with all what was missed.
code
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;
import javax.swing.text.Document;
import javax.swing.text.Element;
/**
* acts as a in-application logger for the automated action being run.
*
*/
public class AutomationRunWatcher {
private JPanel mainPanel,actionPanel ;
private JTextArea logArea;
private JScrollPane scrollPane = null;
private Dimension dimensionWhenClosed,dimensionWhenActive;
private JPopupMenu popMenu;
private ActionAdapter actionAdapter;
private static final int MAX_ROWS=5000,CLEAR_ROWS=1000;
public AutomationRunWatcher(){
mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
dimensionWhenClosed = new Dimension(600,150);
dimensionWhenActive = new Dimension(600,150);
actionAdapter = new ActionAdapter();
mainPanel.add(getJScrollPane(),BorderLayout.CENTER);
mainPanel.add(getActionPanel(),BorderLayout.NORTH);
mainPanel.setPreferredSize(dimensionWhenClosed);
mainPanel.setVisible(true);
//mainPanel.setSize(dimensionWhenClosed);
}
/**
* called each time an automation is run to initialize and display the log console
*
*/
void startLogging(){
// clear previous text
getLogArea().setText(null);
//restore log panel
mainPanel.setPreferredSize(dimensionWhenActive);
mainPanel.setSize(dimensionWhenActive);
mainPanel.add(getJScrollPane(),BorderLayout.CENTER);
mainPanel.add(getActionPanel(),BorderLayout.NORTH);
mainPanel.revalidate();
mainPanel.repaint();
}
JPanel getRunWatcherView(){
return mainPanel;
}
private JScrollPane getJScrollPane(){
if(scrollPane == null){
scrollPane = new JScrollPane();
scrollPane.setViewportView(getLogArea());
}
return scrollPane;
}
private JPanel getActionPanel(){
if(actionPanel == null){
actionPanel = new JPanel(null);
actionPanel.setPreferredSize(new Dimension(200,20));
actionPanel.setOpaque(true);
JLabel btnClose = new JLabel("<html><u>close</u></html>");
btnClose.addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e){
if(e.isPopupTrigger())
return;
close();
}
});
btnClose.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
btnClose.setBounds(1240, 0, 50, 25);
actionPanel.add(btnClose);
}
return actionPanel;
}
private JTextArea getLogArea(){
if(logArea == null){
logArea = new JTextArea(MAX_ROWS,150);
logArea.setEditable(true);
logArea.setOpaque(true);
logArea.setBackground(Color.WHITE);
logArea.setPreferredSize(getJScrollPane().getPreferredSize());
logArea.setAutoscrolls(true);
logArea.getDocument().addDocumentListener(new DocumentListener(){
public void insertUpdate(DocumentEvent e){
ensureSpace();
}
public void removeUpdate(DocumentEvent e){
}
public void changedUpdate(DocumentEvent e){
}
});
((DefaultCaret)logArea.getCaret()).setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
logArea.addMouseListener(new MouseAdapter(){
public void mouseReleased(MouseEvent e){
if(!e.isPopupTrigger())
return;
getJPopupMenu().show(logArea, e.getX(), e.getY());
}
});
}
return logArea;
}
private JPopupMenu getJPopupMenu(){
if(popMenu == null){
popMenu = new JPopupMenu();
JMenuItem menuClear = new JMenuItem("clear");
menuClear.addActionListener(actionAdapter);
popMenu.add(menuClear);
JMenuItem menuClose = new JMenuItem("close");
menuClose.addActionListener(actionAdapter);
popMenu.add(menuClose);
}
return popMenu;
}
public void logText(final String text) {
getLogArea().append(text);
getLogArea().append("\n");
// force autoscroll
getLogArea().setCaretPosition(getLogArea().getDocument().getLength());
getLogArea().repaint();
}
/**
*
* "recycles" the lines used for logging by automatically freeing them for input,CLEAR_ROWS lines at a time
*/
private void ensureSpace(){
Document doc = getLogArea().getDocument();
Element root = doc.getDefaultRootElement();
if (root.getElementCount()== MAX_ROWS-1)
{
Element firstLine = root.getElement(CLEAR_ROWS);
try
{
doc.remove(0, firstLine.getEndOffset());
}
catch(BadLocationException ble)
{
System.out.println(ble);
}
}
getLogArea().setCaretPosition(doc.getLength() );
}
public void clear(){
getLogArea().setText(null);
}
public void close(){
//mainPanel.setPreferredSize(dimensionWhenClosed);
mainPanel.setSize(dimensionWhenClosed);
mainPanel.remove(getJScrollPane());
mainPanel.remove(getActionPanel());
mainPanel.revalidate();
mainPanel.repaint();
}
private class ActionAdapter implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource() instanceof JButton || "close".equals(e.getActionCommand()))
// close button was pressed
close();
else
// clear text
logArea.setText(null);
}
}
}
the above ^ class is where the JTextArea is initialized, here's where it is used
// in this class the AutomationRunWatcher is initialized
class Application{
.....
private void executeAction()
{
getAutomationRunWatcher().startLogging();
selectedAction.run(getAutomationRunWatcher());
......
}
}
and in class AutomatedAction below, i callback into the AutomationRunWatcher to append text into the console while the run method is being executed
public class AutomatedAction{
...
public void run(AutomationRunWatcher runWatcher){
...
//series of actions
runWatcher.logText("some text");
}
..
}
once the automation finishes the text that was enetered into the textarea with append is shown.
as you can see i tried repainting the text area each time text is appended but with no use. I also trying running asynchronously on the event dispatch thread
but no luck as well.I'm confused.