Swing Progressbar aktualisiert sich nicht

jf

Bekanntes Mitglied
Hallo Java-Forum,

ich habe nun mal eine "kleine" Demo meiner Anwendung gebastelt.


Die Probleme dabei wären folgende:

1.) Die Progressbar soll den Lade-Prozess visualisieren, doch leider erscheint sie erst nachdem der Vorgang schon beended wurde. => Ich arbeite aber bereits mit InvokeLater() und mache sogar eine kurze Pause, damit das System Zeit für die Aktualisierung der Progressbar hat - leider bringt dies scheinbar nichts... ;(

2.) Damit die Ladeanzeige korrekte Werte anzeigt, muss ich immer noch die 2 Byte für den Zeilenumbruch hinzufügen:
Code:
count += ((double)line.length() + 2) / 1024 / 1024;
Bei Dateien mit Unix-Format wäre dies aber nur 1 Zeichen. Kann mir der BufferedReader evtl. sagen, um was für eine Datei es sich handelt?

3.) Mit jeder Datei, welche ich hereinziehe, wird ein neues Tab erstellt. Nun möchte ich mit den Pfeiltasten Nach-Links und Nach-Rechts zwischen den Tabs wechseln, auch wenn der Fokus auf der JList liegt. - Wie muss man hierfür vorgehen?
Ich würde auch gern das KeyBinding der JTabbedPane überschreiben, da hier original beim letzten Tab stets wieder auf den ersten gesprungen wird (und umgekehrt). Dieses Verhalten finde ich störend.

Es wäre sehr nett von euch, wenn sich jemand dieser Demo mal annehmen und mir weiterhelfen würde. ;)


Hier ist meine Demo:
Java:
import javax.swing.*;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
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(File[] files) {
				if(files.length > 1) {
					String msg = "Bitte nur eine Datei.";
					JOptionPane.showMessageDialog(Demo.this, msg);
				} else {
					loadFile(files[0]);
				}
			}
        });
        
        // 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) {
			double size = ((double)logFile.length()) / 1024 / 1024;
			m_progress.setMaximum( (int)size );

			this.setTitle( APP_TITLE + ": beim Laden..." );
			JList newList = new JList();
			newList.setModel( new DefaultListModel() );
			newList.addKeyListener( getArrowKeyListener() );
			
			m_TabsPane.add(logFile.getName(), newList);
			
			try {
				m_progress.setValue(0);
				m_progress.setVisible(true);
				
				BufferedReader in = new BufferedReader(new FileReader(logFile));
	    		String line = null;
	    		double count = 0;
	    		int oldCount = 0;
	
	    		while((line = in.readLine()) != null) {
    				((DefaultListModel) newList.getModel()).addElement(line);
    				
    				count += ((double)line.length() + 2) / 1024 / 1024;
    				if(oldCount != (int)count) {
    					final int newValue = (int)count; 
	    				//System.out.println(count + " (Max=" + m_progress.getMaximum() + ")");
	    				SwingUtilities.invokeLater(new Runnable() {
	    					public void run() {
	    						m_progress.setValue(newValue);
	    					}
	    				});
	    				Thread.sleep(100);
    				}
    				oldCount = (int)count;
	 			}
	    		
	    		//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);
		}
    }
    

    //========================================================================================

    
    // 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();
                }
            }
        });
    }
}

[WR]Der Code benötigt die Klasse FileDrop[/WR]


Vielen Dank!!!
 

Sonecc

Gesperrter Benutzer
zu1: So wie ich das sehe rufst du loadFile innerhalb des UI-Threads aus, weswegen dieser blockiert wird. Die Progressbar kann also nicht aktualisiert werden.
 

jf

Bekanntes Mitglied
zu1: So wie ich das sehe rufst du loadFile innerhalb des UI-Threads aus, weswegen dieser blockiert wird. Die Progressbar kann also nicht aktualisiert werden.
Vielen Dank für den Tipp! :toll:

Ich habe es nun wie folgt geändert:

Java:
		// 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(LogMaster.this, msg);
				} else {
					Thread openFileThread = new Thread(new Runnable() {
						@Override
						public void run() {
							checkFile(files[0]);
						}
					});
					openFileThread.start();
				}
			}
        });

Die Progressbar funktioniert jetzt - allerdings werden nun beim Laden der Datei einge Exceptions geworfen:

Code:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 457
	at javax.swing.plaf.basic.BasicListUI.updateLayoutState(BasicListUI.java:1351)
	at javax.swing.plaf.basic.BasicListUI.maybeUpdateLayoutState(BasicListUI.java:1294)
	at javax.swing.plaf.basic.BasicListUI.getPreferredSize(BasicListUI.java:561)
	at javax.swing.JComponent.getPreferredSize(JComponent.java:1634)
	at javax.swing.ScrollPaneLayout.layoutContainer(ScrollPaneLayout.java:769)
	at java.awt.Container.layout(Container.java:1421)
	at java.awt.Container.doLayout(Container.java:1410)
	at java.awt.Container.validateTree(Container.java:1507)
	at java.awt.Container.validateTree(Container.java:1513)
	at java.awt.Container.validateTree(Container.java:1513)
	at java.awt.Container.validateTree(Container.java:1513)
	at java.awt.Container.validateTree(Container.java:1513)
	at java.awt.Container.validateTree(Container.java:1513)
	at java.awt.Container.validate(Container.java:1480)
	at javax.swing.RepaintManager.validateInvalidComponents(RepaintManager.java:669)
	at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueUtilities.java:124)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

Womit könnte das denn nun wieder zusammenhängen...? ???:L
 
S

SlaterB

Gast
funktioniert es wenn du die ständigen GUI-Änderungen,
> ((DefaultListModel) newList.getModel()).addElement(line);
in das invokeLater() setzt, wie allgemein vorgesehen?
du brauchst dann eine finale Kopie des Strings in der Schleife,
fürs Model lieber einmalig eine Variable (final) anlegen, noch vor Übergabe an die JList

Bug ID: 6253801 JList cause an exception when exclusively add data to the list

(Suche war 'updateLayoutState ArrayIndexOutOfBoundsException ')
 

jf

Bekanntes Mitglied
funktioniert es wenn du die ständigen GUI-Änderungen,
> ((DefaultListModel) newList.getModel()).addElement(line);
in das invokeLater() setzt, wie allgemein vorgesehen?
du brauchst dann eine finale Kopie des Strings in der Schleife,
Ja, das hat geholfen. Vielen Dank! :toll:
(Das Problem trat übrigens nur ein meiner Anwendung auf - nicht aber in der Demo.)

Nun habe ich aber ein weiteres (nicht ganz so tragisches, aber immer noch sehr lästiges) Problem:
In meiner Anwendung läuft die Progressbar bei mittelgroßen Dateien (~15 MB) nur so bis etwa 10%, dann dauert es ein bisschen und schließlich ist die Datei komplett geladen. Wenn ich eine große Datei verwende, dann sieht man überhaupt nichts (keine neues Tab, keine JList und keine Progressbar) - erst wenn die Datei komplett eingelesen wurde, erscheint das neue Tab... und nach einer weiteren Verzögerung sind dann in der Liste auch die Zeilen der Datei zu sehen. Von der Progressbar sieht man gar nichts, da diese nach dem Ladevorgang wieder ausgeblendet wird.
Wenn ich das Hinzufügen der Zeilen zur JList auskommentiere, dann funktioniert die Progressbar einwandfrei.

In meiner Demo hat es bereits geholfen, wenn ich nach dem InvokeLater() den Thread kurz schlafen lege (10ms aller 1000 Zeilen) - in meiner Anwendung hat dies aber leider nicht geholfen. Der Einzige Unterschied, welchen ich hier sehe ist, dass die Liste in meiner Anwendung noch ein JScrollPane besitzt.

Wie kann man hier noch optimieren? - Ich verstehe von Swing leider zu wenig und weiß gerade nicht, wo ich hier überhaupt ansetzen kann... ;(

fürs Model lieber einmalig eine Variable (final) anlegen, noch vor Übergabe an die JList
Meinst du so:
Java:
    				SwingUtilities.invokeLater(new Runnable() {
    					public void run() {
    						final DefaultListModel model = (DefaultListModel)newList.getModel();
    						model.addElement(item);
    	    				m_progress.setValue(newValue);
    					}
    				});

Ok, du hast Recht - da hätte ich selber suchen müssen.
Dies tut mir leid... ich bin wohl ein wenig überfordert mit den Ansprüchen, welche Swing an die Programmierung stellt.
Aus dem Bereich wo ich her komme, da geht so etwas wesentlich simpler vonstatten. :oops:
 
Zuletzt bearbeitet:
S

SlaterB

Gast
> Meinst du so:
> final DefaultListModel model = (DefaultListModel)newList.getModel();

passt das denn zu meiner Meinung 'noch vor Übergabe an die JList'?

vor der Schleife vor allem, damit nicht tausende Male getModel() ausgeführt wird,
auch wenn man eigentlich nicht danach optimieren soll,
wer weiß wie kompliziert der Zugriff aus dem Listener auf die finale Variable ist

-----

zu deinem Problem sehe ich nichts deutliches, schon gar nicht wenn er in einer Demo funktioniert,

ein theoretischer Tipp: falls es tausend Zeilen und mehr sind, verringere die Updates,
suche dir eine Update-Zahl u = Anzahl-Zeilen/100,
und dann sammle jeweils u Zeilen, füge die alle in einem invokeLater() ein + ein progress.setValue(),

also weniger Updates, nur ca. 100 statt z.B. 1000,
danach umso eher ein kleines sleep(),
aber eigentlich sollte es ohne Tricks arbeiten..
 

jf

Bekanntes Mitglied
> Meinst du so:
> final DefaultListModel model = (DefaultListModel)newList.getModel();

passt das denn zu meiner Meinung 'noch vor Übergabe an die JList'?
Achso, du meinst, ich sollte mir das ListModel in einer Variable merken, bevor ich des der JList hinzufüge und dann im Nachhinein stets mit der Variable arbeiten? - Ich dachte erst, du meinst
Code:
.addElement(item)
mit "Übergabe an die JList"...

vor der Schleife vor allem, damit nicht tausende Male getModel() ausgeführt wird,
auch wenn man eigentlich nicht danach optimieren soll,
wer weiß wie kompliziert der Zugriff aus dem Listener auf die finale Variable ist
Ok, das werde ich machen.

zu deinem Problem sehe ich nichts deutliches, schon gar nicht wenn er in einer Demo funktioniert,
:autsch:

ein theoretischer Tipp: falls es tausend Zeilen und mehr sind, verringere die Updates,
suche dir eine Update-Zahl u = Anzahl-Zeilen/100,
und dann sammle jeweils u Zeilen, füge die alle in einem invokeLater() ein + ein progress.setValue(),

also weniger Updates, nur ca. 100 statt z.B. 1000,
danach umso eher ein kleines sleep(),
aber eigentlich sollte es ohne Tricks arbeiten..
Ok, das werde ich versuchen.
Ich kenne die Zeilen-Zahl zwar erst nach dem Laden, aber evtl. hilft es, wenn ich immer gleich 1000 Zeilen zusammen hinzufüge - oder aber mit der Dateilänge/100 arbeite...

Wenn auch das nichts bringt, verzweifle ich - für so etwas sind Progressbars ja doch eigentlich gedacht...! :(
 

jf

Bekanntes Mitglied
@SlaterB:

Durch deinen Rat bin ich nun wieder ein Stück weiter - aber dafür gibt es neue Probleme... es ist einfach zum Heulen! ;(

Ich habe in meiner List-Klasse spezielle SilentAdd-Methoden eingefügt, welche das Update nach jeweils 1000 Einträgen vornehmen:
Java:
	List<Object> m_silentItems = new ArrayList<Object>();
	long m_silentAdds = 1000;
	long m_addCount = 0;
	
	public void setSilentAddNumber(long number) {
		m_silentAdds = number;
	}
	public boolean addItemSilent(Object obj) {
		m_silentItems.add(obj);
		
		if(m_addCount++ == m_silentAdds) {
			m_addCount = 0;
			final Object[] currentItems = m_silentItems.toArray();
			m_silentItems.clear();
			
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					for(Object item : currentItems) {
						m_listModel.addElement(item);						
					}
 				}
			});

			return true;
		}
		return false;
	}
	public void finishSilentAdd() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				for(Object item : m_silentItems) {
					m_listModel.addElement(item);						
				}
			}
		});
	}

Aufgrufen werden die Methoden wie folgt:
Java:
			final JListEx newList = new JListEx();
			m_TabsPane.add("Neu", 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;
	    			
	    			final int newValue = (int)percent;
	    			final String item = line;
	    		
	    			//TODO
    				SwingUtilities.invokeLater(new Runnable() {
    					public void run() {
    	    				m_progress.setValue(newValue);
    					}
    				});

    				if(filter.doFilter(item)) {
    					if(newList.addItemSilent(item)) {
    						Thread.sleep(10);
    					}
    				}
	 			}
	    		newList.finishSilentAdd();
	    		
	    		m_progress.setVisible(false);
Dabei steckt das Aktualisieren der Progressbar immer noch in einem einzelnen InvokeLater().

[TIPP]Nun ist die Fortschrittsanzeige bei mittelgroßen Dateien zwar schön animiert - aber bei sehr großen Dateien besteht nach wie vor das Problem, dass das erzeugte neue Tab erst mit dem Ende das Ladevorgangs sichtbar wird. - Was könnte solch ein Phänomen nur hervorrufen?[/TIPP]

[WR]Außerdem tritt jetzt ab und an folgende Ausnahme auf:[/WR]
Code:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
	at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
	at java.util.AbstractList$Itr.next(AbstractList.java:343)
	at common.ui.list.JListEx$2.run(JListEx.java:130)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

[EDIT]
Das mit der Ausnahme könnte sich erledigt haben: ich hatte noch einen Fehler in der addItemSilent()-Methode, welchen oben bereits korrigiert habe. Bisher trat das Problem nicht mehr auf.

Ich habe nun auch herausbekommen, warum es bei großen Dateien Probleme gibt:
Wenn eine Datei größer als 50MB ist, wird nachgefragt, ob spzielle Logeinträge herausgefiltert werden sollen, damit der Java Heap nicht gesprengt wird. Kommentiere ich diese Abfrage aus, dann funktioniert die Fortschrittsanzeige auch bei den großen Dateien.
-> Dieses Abfrage-Fenster wird nur versteckt und nicht geschlossen. Auch rufe ich es nicht mit InvokeLater() auf. Sollte ich dies besser tun? Welchen Grund gibt es für dieses Verhalten?
[/EDIT]
 
Zuletzt bearbeitet:
S

SlaterB

Gast
> Dieses Abfrage-Fenster wird nur versteckt und nicht geschlossen. [..] Welchen Grund gibt es für dieses Verhalten?

die Frage kannst du dir erstmal selber stellen, bzw. wenn du allgemeine Vorgänge meinst, dann wären Informationen hilfreich,
JDialog, JOptionPane? geschlossen durch normale Button-Klicks oder hast du irgendwo dispose() im Code?
was läßt dich vermuten dass es nur versteckt wird?

-----

nach wie vor ohne dass es entscheidend sein sollte:
meiner Idee nach sollte auch der progress.setValue()-Aufruf nur seltener passieren, nur alle 1000 Zeilen, eben in den anderen (beiden) invokeLater-Blöcken rein, die man mit entsprechender Variablität auch zusammenfassen könnte

aber so wie bisher ist, ist es durchaus auch denkbar, die ProgressBar läuft kontinuierlich(er),
ohne dass auch gleich neue Daten sichtbar sind



ich bin jetzt wahrscheinlich bis Samstag abend oder später nicht mehr da
 

jf

Bekanntes Mitglied
> Dieses Abfrage-Fenster wird nur versteckt und nicht geschlossen. [..] Welchen Grund gibt es für dieses Verhalten?

die Frage kannst du dir erstmal selber stellen, bzw. wenn du allgemeine Vorgänge meinst, dann wären Informationen hilfreich, JDialog, JOptionPane? geschlossen durch normale Button-Klicks oder hast du irgendwo dispose() im Code?
was läßt dich vermuten dass es nur versteckt wird?
Weil ich es so programmiert habe:
Java:
			m_enterButton.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent ev) {
					m_canceled = false;
					InputWindow.this.setVisible(false);
				}
			});
Das Fenster (modeless mit owner) ist eine Instanz (Singleton) einer Klasse, welche von JDialog erbt.
Ich verwende kein dispose(), da ich es recht praktisch fand, das Fenster nur zu verstecken:
in diesem Fall sind beim nächsten Aufruf alle Nutzereingaben von zuvor automatisch vorhanden.

nach wie vor ohne dass es entscheidend sein sollte:
meiner Idee nach sollte auch der progress.setValue()-Aufruf nur seltener passieren, nur alle 1000 Zeilen, eben in den anderen (beiden) invokeLater-Blöcken rein, die man mit entsprechender Variablität auch zusammenfassen könnte
Ja, dies habe ich zwischenzeitlich bereits realisiert:
Java:
				m_progress.setValue(0);
				m_progress.setVisible(true);
				
				BufferedReader in = new BufferedReader(new FileReader(logFile));
	    		String line       = null;
	    		double percent    = 0;
	    		double oldPercent = 0;
	
	    		while((line = in.readLine()) != null) {
	    			oldPercent = percent;
	    			percent += ((line.length() + 2) / factor);
	    			
	    			//TODO
    				if(filter.doFilter(line)) {
    					newList.addItemSilent(line);
    					
    					if((int)oldPercent != (int)percent) {
    			    		final int newValue = (int)percent;
    			    		
    		    			SwingUtilities.invokeLater(new Runnable() {
    	    					public void run() {
    	    	    				m_progress.setValue(newValue);
    	    					}
    	    				});

    			    		newList.finishSilentAdd();
    	    				Thread.sleep(10);
    					}
    				}
	 			}
	    		newList.finishSilentAdd();
				Thread.sleep(100);
	    		m_progress.setVisible(false);
Nun passiert ein Update bei jeder Prozent-Änderung (also genau 100 Mal, was eigentlich gut zur Progressbar passen müsste...)

aber so wie bisher ist, ist es durchaus auch denkbar, die ProgressBar läuft kontinuierlich(er), ohne dass auch gleich neue Daten sichtbar sind
Auch damit hast du wieder Recht! :)
Vorher war die Progressbar-Darstellung sehr kontinuierlich. Die Aktualisierung der Liste ist dagegen recht egal, da man schnell den Viewport gefüllt hat und die Größen-Änderung des ScrollbarThumbs eher zu vernachlässigen ist - gerade bei so großen Dateien)
Nun ist die leider nicht mehr so - auch unter Verwendung des obigen Codes!
Wahrscheinlich ist die Pause zu gering, als das sie für die Aktualisierung von beidem (JProgressBar und JList) ausreicht... Am Ende des Ladevorgangs von großen Dateien wird nun erneut die Fortschrittsanzeige nicht aktualisiert (ca. 10%-Sprünge bis etwa 60...80%).
=> ich versuche noch etwas zu optimieren, aber wahrscheinlich werde ich zurückbauen müssen... :(

ich bin jetzt wahrscheinlich bis Samstag abend oder später nicht mehr da
Das hast du dir auch rätlich verdient - gerade bei dem Wetter! :toll:
Wenn du nächste Woche noch mal ein wenig Hintergrundwissen zu dem Problem mit dem Fenster vermitteln könntest, wäre ich sehr dankbar. :)

Schönes Wochenende!!!
 

bERt0r

Top Contributor
Ich hab mir nicht alles durchgelesen aber du hast offenbar die Ansicht, der Computer braucht eine "Pause" um irgendwas anzuzeigen. Dem ist nicht so. Wenn du in einem Thread sagen willst "und jetzt lieber Prozessor verarbeite was anderes" rufst du yield() auf. Sleep ist nur dafür da, wenn du irgendwas um eine bestimmte Zeitspanne verzögern willst. In einem Thread der einen Progressbar aktualisiert hat das nichts verloren - du willst doch den aktuellen Fortschritt anzeigen, da musst du doch nichts verzögern.
Ein setValue brauchst du auch nicht zwingend auf dem EDT ausführen, viel wichtiger ist, dass dein ArbeitsThread nicht auf dem EDT läuft. Ich hab jetzt nicht herausgefunden wo das bei dir läuft, wurde aber bestimmt schon behandelt.
 

jf

Bekanntes Mitglied
Ich hab mir nicht alles durchgelesen aber du hast offenbar die Ansicht, der Computer braucht eine "Pause" um irgendwas anzuzeigen. Dem ist nicht so. Wenn du in einem Thread sagen willst "und jetzt lieber Prozessor verarbeite was anderes" rufst du yield() auf. Sleep ist nur dafür da, wenn du irgendwas um eine bestimmte Zeitspanne verzögern willst. In einem Thread der einen Progressbar aktualisiert hat das nichts verloren - du willst doch den aktuellen Fortschritt anzeigen, da musst du doch nichts verzögern.
Klar, ich hatte diese Methode leider übersehen. Danke für die Info.
Allerdings läuft auch damit die Progressbar nicht sauber durch...

Ein setValue brauchst du auch nicht zwingend auf dem EDT ausführen, viel wichtiger ist, dass dein ArbeitsThread nicht auf dem EDT läuft. Ich hab jetzt nicht herausgefunden wo das bei dir läuft, wurde aber bestimmt schon behandelt.
Das Hauptfenster wird mit
Code:
EventQueue.invokeLater()
gestartet.
Im Konstruktor dieser Klasse wird ein FileDrop-Objekt erzeugt, welches beim Hereinziehen einer Datei das Laden derselben anstößt:
Java:
					Thread openFileThread = new Thread(new Runnable() {
						@Override
						public void run() {
							loadFile(files[0]);
						}
					});
					openFileThread.start();

Scheinbar muss beim Hinzufügen von neuen Elementen zur JList stets
Code:
SwingUtilities.invokeLater()
verwendet werden, sonst gibt es Exceptions (es werden irgendwelche Array-Grenzen überschritten - wahrscheinlich bei der JScrollPane).

Das ist schon echt müsig mit Swing! :noe:
Ich füge nun 100 Einträge der JList hinzu, anschließend werden die Zeilen der Datei nur in einer temporären Liste gespeichert - hierbei läuft die Fortschrittsanzeige sauber durch. Nach Abschluss des Ladevorgangs werden dann die restlichen Zeilen der JList hinzugefügt. Dies führt dann leider zu einer zusätzlichen Verzögerung, welche in der Fortschrittsanzeige nicht dargestellt wird. Zudem springt dadurch die vertikale Rollleiste der JList. Also alles andere als perfekt.
Gibt es Techniken, um solche Effekte zu vermeiden?

Außerdem habe ich immer noch das Problem mit dem Fenster, welches die Aktualisierung der Liste beim Laden stört. - Hat hier noch jemand einen Tipp für mich?
 

bERt0r

Top Contributor
Ja, eine JList solltest du nur im EDT manipulieren. Man kann das aber umgehen: Ich nehme mal an du weißt was MVC ist. Das model hat eine Liste von JLists, welche es benachrichtigt wenn sich die Daten ändern. Das blöde ist, das macht das model nach jedem Eintrag. In meinem Beispiel Code unterbinde ich diese Benachrichtigungen, füge meine Einträge ein und aktiviere die Benachrichtigungen wieder. Das ganze könnte man mit einem selbstimplementierten Model, welches eine addAll Funktionalität bietet, auch eleganter lösen.

Java:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;

public class JListTest extends JFrame
{
	
	private JPanel contentPane;
	private JList<Integer> list;
	private DefaultListModel<Integer> model;
	private JProgressBar progressBar;
	private JPanel panel;
	private JLabel entryLabel;
	private JDialog progressDialog;
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args)
	{
		EventQueue.invokeLater(new Runnable()
			{
				public void run()
				{
					try
					{
						JListTest frame = new JListTest();
						frame.setVisible(true);
					} catch (Exception e)
					{
						e.printStackTrace();
					}
				}
			});
	}
	
	/**
	 * Create the frame.
	 */
	public JListTest()
	{
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JScrollPane scrollPane = new JScrollPane();
		contentPane.add(scrollPane, BorderLayout.CENTER);
		
		model = new DefaultListModel<Integer>();
		list = new JList<Integer>(model);
		scrollPane.setViewportView(list);
		
		JButton btnAddRandomEntries = new JButton("Add Random Entries");
		btnAddRandomEntries.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent arg0)
				{
					new CreateEntryWorker().start();
					progressDialog.setVisible(true);
				}
			});
		contentPane.add(btnAddRandomEntries, BorderLayout.SOUTH);
		
		
		progressDialog=new JDialog(this,true);
		
		panel = new JPanel();
		progressDialog.setContentPane(panel);
		
		entryLabel = new JLabel("Füge Einträge ein:");
		panel.add(entryLabel);
		
		progressBar = new JProgressBar();
		panel.add(progressBar);
		progressBar.setStringPainted(true);
	}
	
	class CreateEntryWorker extends Thread
	{
		public void run()
		{
			Random r = new Random();
			int n = r.nextInt(1000);
			
			entryLabel.setText("Füge "+n+" Einträge ein:");
			progressDialog.pack();
			progressDialog.setLocationRelativeTo(progressDialog.getParent());
			
			ListDataListener[] listeners=model.getListDataListeners();
			for(ListDataListener l:listeners)
			{
				model.removeListDataListener(l);
			}
			
			
			System.out.println("Creating "+n+" entries");
			for(int i=0;i<n;i++)
			{
				try
				{
				Thread.sleep(5); //Mal angenommen hier steht eine aufwendige Berechnung/Zugriff
				}catch(InterruptedException e)
				{
					e.printStackTrace();
				}
				model.addElement(i);
				progressBar.setValue(100*i/n);
			}
			for(ListDataListener l:listeners)
			{
				model.addListDataListener(l);
				l.contentsChanged(new ListDataEvent(model,ListDataEvent.CONTENTS_CHANGED,0,model.size()));
			}
			progressBar.setValue(100);
		}
	}
}
 

jf

Bekanntes Mitglied
Ja, eine JList solltest du nur im EDT manipulieren. Man kann das aber umgehen:
Dein Bespiel ist super! - Es ist merklich schneller als wenn es über den EDT läuft.

Ich nehme mal an du weißt was MVC ist.
Jetzt weiß ich es. :D

Das model hat eine Liste von JLists, welche es benachrichtigt wenn sich die Daten ändern. Das blöde ist, das macht das model nach jedem Eintrag. In meinem Beispiel Code unterbinde ich diese Benachrichtigungen, füge meine Einträge ein und aktiviere die Benachrichtigungen wieder.
Bei mir zeigte Java Fehler an folgenden Zeilen:
Java:
        model = new DefaultListModel<Integer>();
        list = new JList<Integer>(model);
Ich musste die Templates entfernen. Woran kann das liegen? - Verwendest du evtl. eine neuere Java-Version (bei mir ist es Java 6 SE)?

Außerdem verendest du
Code:
EventQueue.invokeLater
in der main Routine, Ebenius macht es aber hingegen mit
Code:
SwingUtilities.invokeLater
.
- Kommt das am Schluss auf das Gleiche heraus, oder gibt es hier Unterschiede?

Das ganze könnte man mit einem selbstimplementierten Model, welches eine addAll Funktionalität bietet, auch eleganter lösen.
Die Frage der Eleganz ist hier wohl eine Standpunktfrage: ich habe die JList sowieso gewrappt, damit ich nicht jedesmal das DefaultListModel und die JScrollPane hinzufügen muss, was sehr lästig ist und den Code viel unlesbarer macht. Dabei bietet mein Wrapper natürlich ein add(List<Object>) und ein add(Object[]), was mit deinem Trick nun auch prima funktioniert. :)

Außerdem ist ein addAll in der Verwendung oftmals nicht so komfortabel: wenn ich z. B. eine Datei zeilenweise auslese, dann kann ich die Zeile mit add gleich der Liste hinzufügen (+ ein doUpdate ganz am Schluss) - bei einem addAll müsste man das über eine temporäre Liste lösen.

Vielen Dank für deinen Ratschlag! :toll:
 

bERt0r

Top Contributor
Ja die Generics sind nur Java 7 kompatibel. SwingUtilities is afaik nur eine Convenienceklasse, die EventQueue aufruft. Es kommt also aufs gleiche raus.
 

jf

Bekanntes Mitglied
Ja die Generics sind nur Java 7 kompatibel.
Ok, dachte mir schon, dass es an Java 7 liegt. ;)
Aber das Generics nur mit Java 7 kompatibel sind, verstehe ich jetzt nicht:
List<Object> ist doch auch in Java 6 SE möglich - nur bei den Swing-Klassen ist mir es da bisher so noch nicht unter gekommen...

SwingUtilities is afaik nur eine Convenienceklasse, die EventQueue aufruft. Es kommt also aufs gleiche raus.
Ah, ok. Dann ist ja alles gut. :)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
G Progressbar aktualisiert sich nicht (vernünftig). WIESO? AWT, Swing, JavaFX & SWT 2
F Progressbar Farbe AWT, Swing, JavaFX & SWT 6
T Swing Reload JPanel + darin liegende ProgressBar AWT, Swing, JavaFX & SWT 9
A Swing ProgressBar über 2 parallel laufende Threads AWT, Swing, JavaFX & SWT 2
P JavaFx - Progressbar - Füllen mittels mehreren Tasks AWT, Swing, JavaFX & SWT 0
Bluedaishi JavaFX ProgressBar AWT, Swing, JavaFX & SWT 10
T Starten des Programms mit dem Progressbar AWT, Swing, JavaFX & SWT 2
L Progressbar Laufzeitveränderung AWT, Swing, JavaFX & SWT 4
1 Swing Progressbar benutzen um Fortschritt einer Methode anzuzeigen AWT, Swing, JavaFX & SWT 4
B JavaFX Textfields: Fortschritt als ProgressBar und Progressindicator AWT, Swing, JavaFX & SWT 5
MR._FIRE_Flower progressBar in ein bestehendes Programm einbauen AWT, Swing, JavaFX & SWT 3
M Wie binde ich eine JavaFX ProgressBar an eine Datei Übertragung? AWT, Swing, JavaFX & SWT 2
Z Swing Swing und die Progressbar AWT, Swing, JavaFX & SWT 1
I JavaFX Im Controller die ProgressBar mit Task updaten AWT, Swing, JavaFX & SWT 6
R LookAndFeel Wie kann man die Textfarbe der Nimbus ProgressBar nach Füllstand ändern? AWT, Swing, JavaFX & SWT 2
M JavaFX Progressbar bar und track Komponente zur Laufzeit ändern AWT, Swing, JavaFX & SWT 2
Z ProgressBar in Eclipse mit Wizard page? AWT, Swing, JavaFX & SWT 1
W Swing ProgressBar update AWT, Swing, JavaFX & SWT 4
A JavaFX Eine Task mit einer ProgressBar verbinden AWT, Swing, JavaFX & SWT 0
H Nimbus ProgressBar Colors AWT, Swing, JavaFX & SWT 9
P Swing Die ProgressBar wird nicht angezeigt AWT, Swing, JavaFX & SWT 5
B SWT Progressbar mit Textoverlay? AWT, Swing, JavaFX & SWT 3
M ProgressBar in ActionListener AWT, Swing, JavaFX & SWT 4
T Prozessstatus in Progressbar anzeigen AWT, Swing, JavaFX & SWT 5
V Persistentes Objekt laden Progressbar AWT, Swing, JavaFX & SWT 7
V Swing Progressbar Problem AWT, Swing, JavaFX & SWT 14
B ProgressBar während Berechnung AWT, Swing, JavaFX & SWT 4
Tobse LookAndFeel [Windows7] Nativ aussehnde ProgressBar AWT, Swing, JavaFX & SWT 13
J Progressbar mit einfacher Funktion AWT, Swing, JavaFX & SWT 6
D Progressbar AWT, Swing, JavaFX & SWT 5
H Zeile in DefaultTableModel hinzufügen, ProgressBar AWT, Swing, JavaFX & SWT 4
S Upload Progressbar AWT, Swing, JavaFX & SWT 3
S Dateien kopieren mit ProgressBar AWT, Swing, JavaFX & SWT 6
S Swing ProgressBar AWT, Swing, JavaFX & SWT 3
S SWT ProgressBar: Value/Selection anzeigen AWT, Swing, JavaFX & SWT 4
D SWT JFace Wizard Progressbar AWT, Swing, JavaFX & SWT 4
S ProgressBar newRunnable (schon wieder!) AWT, Swing, JavaFX & SWT 9
ModellbahnerTT Progressbar anzeigen AWT, Swing, JavaFX & SWT 5
J Progressbar aktualisierung nach file übergabe AWT, Swing, JavaFX & SWT 7
P Progressbar in java AWT, Swing, JavaFX & SWT 3
K Frage zu ProgressBar, SwingWorker etc. AWT, Swing, JavaFX & SWT 4
V ProgressBar AWT, Swing, JavaFX & SWT 5
D Suche verticale Progressbar AWT, Swing, JavaFX & SWT 2
M Bug; Swing-Worker, Progressbar und Mouse AWT, Swing, JavaFX & SWT 22
P [SWT] - ProgressBar, Prozentzahlen live anzeigen geht nicht AWT, Swing, JavaFX & SWT 13
P JTable sortiert ProgressBar nicht AWT, Swing, JavaFX & SWT 8
L Button ändert eigenes Bild und Progressbar-Value nicht AWT, Swing, JavaFX & SWT 6
B Eine Alternative zur Steuerung einer ProgressBar? AWT, Swing, JavaFX & SWT 5
N ProgressBar --> brauche Hilfe AWT, Swing, JavaFX & SWT 4
S Anzeige einer Progressbar. AWT, Swing, JavaFX & SWT 3
M Bild laden + ProgressBar AWT, Swing, JavaFX & SWT 2
C Problem mit ProgressBar AWT, Swing, JavaFX & SWT 4
thE_29 Problem mit ProgressBar AWT, Swing, JavaFX & SWT 2
M ProgressBar in einem Thread? AWT, Swing, JavaFX & SWT 4
C ProgressBar AWT, Swing, JavaFX & SWT 4
S Ausgabe aktualisiert sich nur nach 2. Klick AWT, Swing, JavaFX & SWT 17
F JList aktualisiert nicht AWT, Swing, JavaFX & SWT 24
K Swing GUI aktualisiert nicht richtig AWT, Swing, JavaFX & SWT 5
J Meine ProgBar und ProgIndi werden nicht aktualisiert AWT, Swing, JavaFX & SWT 28
M JTextArea wird nicht aktualisiert (ActionListener-Problem) AWT, Swing, JavaFX & SWT 1
F AWT Grafik wird nicht richtig aktualisiert AWT, Swing, JavaFX & SWT 2
J AWT choice mit viel Auswahl aktualisiert sich nicht korrekt beim scrollen?! AWT, Swing, JavaFX & SWT 3
A Vier gewinnt: GUI aktualisiert sich nicht AWT, Swing, JavaFX & SWT 12
T Java Swing Oberfläche aktualisiert sich nicht AWT, Swing, JavaFX & SWT 2
C JLabel wird nicht aktualisiert AWT, Swing, JavaFX & SWT 3
D JTabke aktualisiert sich nicht AWT, Swing, JavaFX & SWT 4
El_Lobo Swing Swing TextArea und JTextField werden nicht aktualisiert AWT, Swing, JavaFX & SWT 2
N Tabellenzelle wird bei JCombBox mit eigenem Datentyp nicht aktualisiert AWT, Swing, JavaFX & SWT 7
F Timer welches JPanel aktualisiert AWT, Swing, JavaFX & SWT 6
N JLabel Text aktualisiert sich nicht AWT, Swing, JavaFX & SWT 2
K JTable wird nicht aktualisiert, wenn Filter gesetzt ist AWT, Swing, JavaFX & SWT 9
R AWT JList wird nur zufällig auf der GUI aktualisiert AWT, Swing, JavaFX & SWT 5
P Swing GUI aktualisiert sich nicht AWT, Swing, JavaFX & SWT 7
S Jtable wird nicht aktualisiert AWT, Swing, JavaFX & SWT 8
M Graphics-Objekt aktualisiert sich nicht AWT, Swing, JavaFX & SWT 2
C Swing JProgressBar Aktualisiert sich nicht. AWT, Swing, JavaFX & SWT 9
I Swing Warten, bis eine GUI-Komponente aktualisiert ist? AWT, Swing, JavaFX & SWT 4
C (Swing)GUI-Elemente werden nicht aktualisiert. AWT, Swing, JavaFX & SWT 2
S Swing JList in JScrollPane aktualisiert sich nicht AWT, Swing, JavaFX & SWT 6
PAX JList aktualisiert zu langsam beim Hinzufügen von Einträgen AWT, Swing, JavaFX & SWT 6
C JTree wird nicht aktualisiert AWT, Swing, JavaFX & SWT 3
A Gui Komponenten werden nicht von selbst aktualisiert! AWT, Swing, JavaFX & SWT 2
K Textfeld wird nur jedes zweite Mal aktualisiert AWT, Swing, JavaFX & SWT 3
T JPanel aktualisiert nicht AWT, Swing, JavaFX & SWT 3
C JTable aktualisiert die Anzeige nicht AWT, Swing, JavaFX & SWT 2
R GUI wird nicht richtig aktualisiert AWT, Swing, JavaFX & SWT 5
G JList wird in einem Applet nur teilweise aktualisiert AWT, Swing, JavaFX & SWT 12
G JTable (AbstractTableModel) wird nicht aktualisiert AWT, Swing, JavaFX & SWT 2
J JTextArea wird nicht aktualisiert bei Zugriff von außerhalb AWT, Swing, JavaFX & SWT 2
A JTree wird erst nach Klick aktualisiert AWT, Swing, JavaFX & SWT 2
S JLabel aktualisiert sich nicht AWT, Swing, JavaFX & SWT 4
G Tabelle aktualisiert sich erst, nachdem man auf sie klickt! AWT, Swing, JavaFX & SWT 4
B TreeViewer für das Dateisystem, der sich selbst aktualisiert AWT, Swing, JavaFX & SWT 8
J Dialogfenster wird nicht aktualisiert/CardLayout AWT, Swing, JavaFX & SWT 6
raptorrs JTextfelder werden in while-Schleife nicht aktualisiert AWT, Swing, JavaFX & SWT 5
L JProgressBar wird nicht mehr aktualisiert AWT, Swing, JavaFX & SWT 2
O Choice/Combobox wird nur 1x aktualisiert AWT, Swing, JavaFX & SWT 3
G Mein JFrame aktualisiert sich nicht richtig AWT, Swing, JavaFX & SWT 3
Juelin Javafx hängt sich auf AWT, Swing, JavaFX & SWT 31
I JavaFX Programmcode pausieren gestaltet sich als schwierig AWT, Swing, JavaFX & SWT 7

Ähnliche Java Themen


Oben