The current project in wherein I’m working creates a log file using the log4j library and also must have the functionality “showLog” which create a frame where the log can be viewed. Moreover, this frame has to refresh when the log file is modified (appending a new log message).
Well, I have done all except the refresh action, and this is the question, how can I do the dynamically refresh?
Here fragments of my code, I put only the relevant lines:
-
Interface Action: runs the event actions
public interface Action { public void executer(); } -
Class CadreTexte: Creates and manages the frame wherein the log file is showed
public class CadreTexte extends JFrame { private JTextPane log; public CadreTexte(String titre, File texte) { super(titre); if (texte.exists() && texte.canRead()) { this.texte = texte; } else { throw new ExceptionGenerateurs("NE_FILE"); //Own exception } initializeFrame();
log= new JTextPane(); log.setEditable(false); java.net.URL urlFichier = null; try { urlFichier = texte.toURI().toURL(); } catch (MalformedURLException e1) { throw new ExceptionGenerateurs("Fichier de texte non montrable"); } try { log.setPage(urlFichier); } catch (IOException e) { System.out.println(e.getLocalizedMessage()); //CATCH } finally { urlFichier = null; } JScrollPane docSP = setScrollPane(); // bars as needed, contains JTextPane getContentPane().setLayout(new BorderLayout()); getContentPane().add(docSP,BorderLayout.CENTER); } } -
Class Vue: main frame. It has a list of Action objects which are stored into a HashMap. The actions are accessible throught a menu. Due to this class is very large, I put only the most important lines:
-
ActionPerformed Function:
public void actionPerformed(ActionEvent e) { JComponent composant; Action handler; composant = (JComponent) e.getSource(); String idEvenement = composant.getName(); modele.log(Modele.LOG_DEBUG, String.format("Événement. ID: %s",idEvenement)); handler = ACTIONS_MAP.get(idEvenement); if (handler == null) { modele.log(Modele.LOG_ERROR, "Action non identifiée"); } else { handler.executer(); modele.log(Modele.LOG_DEBUG, "Fin action"); } } -
Action visualiserLog:
Action visualiserLog = new Action() { public void executer() { if (cadreLog == null) { cadreLog = new CadreTexte("Fichier du log", model.getLogFile()); visuLog = true; } else { visuLog = !visuLog; } cadreLog.visualiser(visuLog); } };
-
Finally, the MenuItem which activates the visualiserLog Action it’s a JCheckBoxMenuItem
I hope you can help me after understand this large question. If someone needs more information, ask for it!
Regards!
NOTE: I’d be very grateful if someone can edit and give correct format to the question, I have been fighting with the editor and it wins me =(
I’m not sure that automatic refreshes are a good idea: log files are normally very frequently modified, and can quickly become quite long, so you have a risk of constantly rereading a long file to update the area, and this area, being constantly updated, could become hard to read.
If you really want to do that, I think the only solution is to read the file first and store its length or modification date, and then start a thread which, every N seconds, compares the length or modification date with the one stored in memory.If it has changed, re-read the file and update the text area and the length or modification date.
Be careful not to update the text area from the polling thread, but from the event dispatch thread. Use
SwingUtilities.invokeLaterto do it.