Hallo, ich möchte an dieser Stelle nochmal eine Ergänzung zu meiner alten Diskussion starten, da diese aufgrund der Länge eingeschlafen ist.
Es geht dabei darum, dass die Fortschrittsanzeige nicht durchgehen und kontinuierlich aktualisiert wird, sobald parallel sehr viele Elemente in eine JList geschrieben werden. Mich interessieren an dieser Stelle die Hintergründe dafür und ob es evtl. Techniken gibt, welche meiner Herangehensweise überlegen sind.
Ein weiteres Problem ist, dass das ganze Haupt-Fenster während des Ladevorgangs nicht aktualsiert wird, wenn ich zuvor einen Dialog öffne. Sicherlich ist mir hier ein Konzept-Fehler unterlaufen - ich würde gerne erfahren, wie man das richtig löst.
Ich habe meine Anwendung mal zu einer Demo abgespeckt, welche diese beiden Probleme aufzeigt:
Um die Probleme zu sehen, solltet ihr eine möglichst große (~10...50MB) Textdatei in das Hauptfenster ziehen. Dann erscheint eine Abfrage, ob ein Fenster angezeigt werden soll. Bitte Nein ankicken, um das erste Problem darzustellen. Wenn Ja angeklickt wird, wird ein weiterer Dialog angezeigt. Dieser kann dann nur ausgeblendet (setVisible), oder aber ganz geschlossen (dispose) werden - egal was man wählt, die Aktualisierung des UI erfolgt erst mit Abschluss des Ladevorgangs.
Ich füge diesem Dialog einen Component/WindowListener hinzu, in welchem der Ladevorgang gestartet wird, sobald der Nutzer eine Auswahl getroffen und somit den Dialog geschlossen hat. - Kann es sein, dass damit der Ladevorgang selber im EDT läuft? Wie kann man so etwas besser machen?
Vielen Dank für eure Unterstützung!
Es geht dabei darum, dass die Fortschrittsanzeige nicht durchgehen und kontinuierlich aktualisiert wird, sobald parallel sehr viele Elemente in eine JList geschrieben werden. Mich interessieren an dieser Stelle die Hintergründe dafür und ob es evtl. Techniken gibt, welche meiner Herangehensweise überlegen sind.
Ein weiteres Problem ist, dass das ganze Haupt-Fenster während des Ladevorgangs nicht aktualsiert wird, wenn ich zuvor einen Dialog öffne. Sicherlich ist mir hier ein Konzept-Fehler unterlaufen - ich würde gerne erfahren, wie man das richtig löst.
Ich habe meine Anwendung mal zu einer Demo abgespeckt, welche diese beiden Probleme aufzeigt:
Java:
package progress_bar;
import javax.swing.*;
import common.ui.files.FileDrop;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.*;
@SuppressWarnings("serial")
public class Demo extends JFrame {
// singleton variable
private static Demo m_instance;
private JTabbedPane m_TabsPane = null;
private JProgressBar m_progress = null;
private KeyListener m_keyListener = null;
private static final String APP_TITLE = "Demo";
private final int DEF_WIDTH = 800;
private final int DEF_HEIGHT = 600;
// constructor
public Demo() {
//-----------------------------------------------------------------------------
// Creating the tabbed pane
m_TabsPane = new JTabbedPane();
// Creating the progress bar
m_progress = new JProgressBar();
m_progress.setVisible(false);
// Adding the TabRowJacket
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(m_TabsPane, BorderLayout.CENTER);
this.getContentPane().add(m_progress, BorderLayout.SOUTH);
//-----------------------------------------------------------------------------
// define hot keys
m_TabsPane.addKeyListener( getArrowKeyListener() );
// for drag'n'drop feature
new FileDrop(this, new FileDrop.Listener() {
public void filesDropped(final File[] files) {
if(files.length > 1) {
String msg = "Hey du Workaholic!\n=> Immer schön eins nach dem anderen... ;)";
JOptionPane.showMessageDialog(Demo.this, msg);
} else {
Thread openFileThread = new Thread(new Runnable() {
@Override
public void run() {
checkFile(files[0]);
}
});
openFileThread.start();
}
}
});
// window should be centered on the primary monitor
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
int posX = (int)(dim.getWidth()-DEF_WIDTH) / 2;
int posY = (int)(dim.getHeight()-DEF_HEIGHT) / 2;
this.setSize(DEF_WIDTH, DEF_HEIGHT);
this.setLocation(posX, posY);
// defining close operation
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public KeyListener getArrowKeyListener() {
if(m_keyListener == null) {
m_keyListener = new KeyListener() {
@Override public void keyTyped(KeyEvent ev) {}
@Override public void keyReleased(KeyEvent ev) {}
@Override
public void keyPressed(KeyEvent ev) {
switch(ev.getKeyCode()) {
case KeyEvent.VK_LEFT: Demo.this.prevTab();
case KeyEvent.VK_RIGHT: Demo.this.nextTab();
}
}
};
}
return m_keyListener;
}
//========================================================================================
// previous tab
public void prevTab() {
int index = m_TabsPane.getSelectedIndex();
if(index > 0) {
m_TabsPane.setSelectedIndex(index-1);
}
}
// next tab
public void nextTab() {
int index = m_TabsPane.getSelectedIndex();
if(index < m_TabsPane.getTabCount()-1) {
m_TabsPane.setSelectedIndex(index);
}
}
// loading file
private void loadFile(File logFile) {
if(logFile != null) {
this.setTitle( APP_TITLE + ": beim Laden..." );
final MyList newList = new MyList();
m_TabsPane.add(logFile.getName(), newList);
m_TabsPane.setSelectedComponent(newList);
final double factor = (double)logFile.length() / 100;
try {
m_progress.setValue(0);
m_progress.setVisible(true);
BufferedReader in = new BufferedReader(new FileReader(logFile));
String line = null;
double percent = 0;
while((line = in.readLine()) != null) {
percent += ((line.length() + 2) / factor);
newList.addItem(line);
m_progress.setValue( (int)percent );
}
m_progress.setVisible(false);
} catch(Exception ex) {
String msg = "Beim Lesen der Datei ist folgender Fehler aufgetreten:\n" + ex.toString();
JOptionPane.showMessageDialog(this, msg);
return;
}
this.setTitle(APP_TITLE);
}
}
private void checkFile(final File logFile) {
if(logFile != null) {
int ret = JOptionPane.showOptionDialog(this, "Soll das Fenster angezeigt werden.", "Test", 0, 0, null, null, null);
if(ret == 0) {
MyWindow win = MyWindow.getInstance();
win.addComponentListener(new ComponentListener() {
@Override public void componentMoved(ComponentEvent arg0) {}
@Override public void componentResized(ComponentEvent arg0) {}
@Override public void componentShown(ComponentEvent arg0) {}
@Override
public void componentHidden(ComponentEvent arg0) {
loadFile(logFile);
}
});
win.addWindowListener(new WindowListener() {
@Override public void windowActivated(WindowEvent arg0) {}
@Override public void windowClosing(WindowEvent arg0) {}
@Override public void windowDeactivated(WindowEvent arg0) {}
@Override public void windowDeiconified(WindowEvent arg0) {}
@Override public void windowIconified(WindowEvent arg0) {}
@Override public void windowOpened(WindowEvent arg0) {}
@Override public void windowClosed(WindowEvent arg0) {
loadFile(logFile);
}
});
win.setVisible(true);
} else {
loadFile(logFile);
}
}
}
//========================================================================================
// singleton
public static Demo getInstance() {
if(m_instance == null) {
m_instance = new Demo();
}
return m_instance;
}
// main routine
public static void main(final String[] arg) throws IOException {
System.out.println("Java-Version: " + System.getProperty("java.version"));
try {
UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
}
catch (ClassNotFoundException e) { e.printStackTrace(); }
catch (InstantiationException e) { e.printStackTrace(); }
catch (IllegalAccessException e) { e.printStackTrace(); }
catch (UnsupportedLookAndFeelException e) { e.printStackTrace(); }
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Demo win = Demo.getInstance();
win.setVisible(true);
if(arg.length > 0) {
win.loadFile(new File(arg[0]));
} else {
win.setTitle(APP_TITLE + ": Datei einfach hereinziehen");
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
});
}
}
@SuppressWarnings("serial")
class MyList extends JScrollPane {
private JList m_listComponent = null;
private DefaultListModel m_listModel = null;
public MyList() {
// Add listbox with the ability to handle tabulator characters
m_listComponent = new JList();
super.add(m_listComponent);
// Define list model
m_listModel = new DefaultListModel();
m_listComponent.setModel(m_listModel);
// Define viewport for the JScrollPane (this class is extending JScrollPane)
this.setViewportView(m_listComponent);
}
public void addItem(Object obj) {
final Object finalObj = obj;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
m_listModel.addElement(finalObj);
}
});
}
}
@SuppressWarnings("serial")
class MyWindow extends JDialog {
private static MyWindow m_instance = null;
private MyWindow() {
super(Demo.getInstance(), false);
JButton but1 = new JButton("Ausblenden");
but1.setPreferredSize(new Dimension(100, 20));
but1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
MyWindow.this.setVisible(false);
}
});
JButton but2 = new JButton("Schließen");
but2.setPreferredSize(new Dimension(100, 20));
but2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
MyWindow.this.dispose();
}
});
this.setLayout( new FlowLayout() );
this.add(but1);
this.add(but2);
this.pack();
this.setVisible(true);
centerTo(Demo.getInstance());
}
public static MyWindow getInstance() {
if(m_instance == null) {
m_instance = new MyWindow();
}
return m_instance;
}
private void centerTo(JFrame owner) {
int x = owner.getLocation().x + (owner.getWidth() - this.getWidth()) / 2;
int y = owner.getLocation().y + (owner.getHeight() - this.getHeight()) / 2;
this.setLocation(x, y);
}
}
Ich füge diesem Dialog einen Component/WindowListener hinzu, in welchem der Ladevorgang gestartet wird, sobald der Nutzer eine Auswahl getroffen und somit den Dialog geschlossen hat. - Kann es sein, dass damit der Ladevorgang selber im EDT läuft? Wie kann man so etwas besser machen?
Vielen Dank für eure Unterstützung!