Fenster mit ProgressMonitor immer leer

may24

Bekanntes Mitglied
Hi,
ich versuche gerade einen ProgressMonitor in mein app. einzubauen. Ihn aufzurufen gibt mir zwar ein kleines Fenster, das ist aber immer leer. Jemand 'ne Idee ?

Java:
package Converter;

import javax.swing.JFrame;
import javax.swing.ProgressMonitor;

public class MyProgressMonitor extends JFrame
{
	private ProgressMonitor pm;
	private int maxValue = 0;
	
	public MyProgressMonitor(int maxValue)
	{
		this.maxValue = maxValue;
		
		setSize(250, 100);														// this is related to JFrame
	    setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
	    setResizable(false);
		setLocation(600,200);
	    myProgressMonitorOpen();
	    setVisible(true);
		
	}
	
	private void myProgressMonitorOpen()
	{
		pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);

	Thread thread = new Thread (new Runnable() 
		{
	    public void run() 
	    	{
	    		pm.setProgress(maxValue);
	    	}
	        
	    });
	  thread.start ();
	}  
	  
	  public void makeProgress(int progress)
	  {
		  maxValue = progress;
	  }
}
 
> Ihn aufzurufen gibt mir zwar ein kleines Fenster, das ist aber immer leer.

das ist das JFrame

Java:
 private void myProgressMonitorOpen()  {
        pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
        pm.setMillisToPopup(0); // Anforderungen senken
        pm.setMillisToDecideToPopup(0); // Anforderungen senken
        pm.setProgress(1); // Dialog erscheint

        Thread thread = new Thread(new Runnable() {
                public void run()   {
                    try      {
                        Thread.sleep(2000); // warten
                    }  catch (InterruptedException e)   {    e.printStackTrace();    }
                    pm.setProgress(maxValue); // bei maxValue verschwindet der Dialog, falls zu sehen gewesen
 
Beim ProgressMonitor ist es wohl so, dass er sich automatisch schließt, wenn er das Maximum erreicht hat... und in deinem Thread setzt du ihn sofort auf Maximum.

Hier mein "Spiel"-Beispiel, ich finde das funktioniert gut 🙂
Java:
      public static void main(String[] args) {
          final ProgressMonitor pm = new ProgressMonitor(null, "Bitte warten...", "", 0, 100);
          new Thread(new Runnable() {
              @Override
              public void run() {
                  int progress = 0;
                  while (progress < 100 && ! pm.isCanceled()) {
                      try {
                          Thread.sleep(500L);
                      } 
                      catch (InterruptedException e) {}
                      progress += 2;
                      pm.setProgress(progress);
                  }
              }
          }).start();
      }
 
Ok, ich habe das Ganze nun abgeändert, aber so richtig funktionieren tut's trotzdem nicht.

Java:
package Converter;

import javax.swing.JFrame;
import javax.swing.ProgressMonitor;

public class MyProgressMonitor
{
	private int maxValue;
	private int progress = 0;
	
	public MyProgressMonitor(int maxValue)
	{
		this.maxValue = maxValue;
	    myProgressMonitorOpen();
		
	}
	
	private void myProgressMonitorOpen()
	{
		final ProgressMonitor pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
		
		pm.setMillisToPopup(0);
	    pm.setMillisToDecideToPopup(0);

	    Thread thread = new Thread (new Runnable() 
		{
	    public void run() 
	    	{
	    		while (progress < maxValue)
	    		{
	    			pm.setProgress(progress);
	    			System.out.println("progress: " + progress + " maxLalue: " + maxValue);
	    		}
	    	}
	        
	    });
	    
	    thread.start();
	}  
	  
	  public void makeProgress(int progress)
	  {
		  this.progress = progress + 1;
	  }
}

das println in der while Schleife sollte mir ja bei jeden Durchlauf progress + maxValue zeigen.
Zwar geht jetzt der ProgressMonitor auf, aber erstens läuft besagte Zeile nur einmal durch, und zweitens kommt der "porgrss" Balken nie bis 100%
Entweder der Aufbau des Threads ist so langsam das maxValue schon erreicht ist bevor er den ersten Wert verarbeiten kann (sehr unwarscheinlich) oder zweitens: hier läuft was total schief - aber was ?
Setzt man das println unten in die makeProgress Methode, so sieht man das dies jedes mal ordentlich um 1 erhöht - daran kann es also nicht liegen ... ???:L ;(
 
> while (progress < maxValue)
die while-Bedingung verhindert, dass der maximale Wert eingetragen werden kann,

der ganze Thread scheint ziemlich nutzlos, übertrage doch genau EINMAL den neuen Value in der makeProgress()-Methode,
dann brauchst du ihn nicht mal zwischenzuspeichern,
warum sollte ein Thread die CPU auf 100% schwitzen lassen und nur ohne Pause zig Millionen mal pro Sekunde den Wert übergeben?

für die Aktion, für den Aufruf von makeProgress() brauchst du bestimmt einen Thread,
aber der Thread in myProgressMonitorOpen() macht nichts sinnvolles
 
Ok, ich hab den sourcecode nochmal abgeändert:

Java:
package Converter;

import javax.swing.ProgressMonitor;

public class MyProgressMonitor
{
	private int maxValue;
	private int progress = 0;
	private ProgressMonitor pm;
	
	public MyProgressMonitor(int maxValue)
	{
		this.maxValue = maxValue;
		pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
		pm.setMillisToPopup(0);
	        pm.setMillisToDecideToPopup(0);
		pm.setProgress(0);
	        myProgressMonitorOpen();
	}
	
	private void myProgressMonitorOpen()
	{
	    Thread thread = new Thread (new Runnable() 
		{
	    public void run() 
	    	{
	    		while (progress <= maxValue)
	    		{
	    			pm.setProgress(progress);
	    		}
	    	}
	    });
	    thread.start();
	}  
	  
	  public void makeProgress(int progress)
	  {
		  this.progress = progress + 1;
	  }
}

wenn
Code:
progress <= maxValue
dann schließt sich auch der ProgressMonitor bei 100%
Aber es scheint trotzdem so zu sein, als daß der neue Thread zu langsam ist um die Daten schnell genug darzustellen ... Hab's getestet mit 200 Zeilen a 2 Einträge die geändert wurden. Aber das scheint zu schnell abzulaufen um angezeigt zu werden (und das ist her 'n Atlon ... nix mehrfach Core oder 64 Bit ...)
Vielleicht liegts auch daran das die Threads nicht ge-synced sind ... aber geht das überhaupt so einfach hier :bahnhof:
 
siehe auch mein Post zwischendurch,
und was drumherum in deinen Programm passiert kann wohl kaum beurteilt werden
 
@SlaterB: Ja, da warste zu fix für mich mit dem posten.

OK, "drumherum" werden zwei Zahlen aus einem Array neu berechnet und diese in ein neues Array gepackt. Den Code schenke ich mir jetzt.
Sache ist, das ich ca. 200 Durchläufe habe und nun das Voranschreiten graphisch darstellen will. Diese Klasse instanziert die MyProgressMonitor, und ruft nach jedem Durchlauf das makeProgress auf ... ca. 200 mal.

myProgressMonitorOpen sollte eigentlich nur dazu gut sein einen neuen Thread zu starten indem der ProgressMonitor läuft. Damit er den Haupt-Thread nicht blockert.
 
> myProgressMonitorOpen sollte eigentlich nur dazu gut sein einen neuen Thread zu starten indem der ProgressMonitor läuft. Damit er den Haupt-Thread nicht blockert.

geht auch ohne, zumal du ja jetzt schon den ProgressMonitor außerhalb des Threads anlegst,
nur in Thread setProgress() aufzurufen kann ja nicht die komplette ProgressMonitor-Durchführung sein
 
Ja, aber nehmen wir mal an, ich erzeuge den ProgressMonitor im neuen Thread. Wie könnte ich dann noch von außen mit setProgress zugreifen ?
 
was hat der erste mit dem zweiten Satz zu tun?

von außen musst du nicht unbedingt setProgress() aufrufen, der Befehl könnte wie gesagt in makeProgress() stehen,
wobei das dann nur eine Weiterleitung ist, du könntest auch einen getter für pm schreiben,
oder die ganze Klasse könnte wegfallen und die andere Klasse selber ProgressMonitor definieren usw.,

Java:
pm.setMillisToPopup(0);
pm.setMillisToDecideToPopup(0);
pm.setProgress(0);
kann übrigens wieder weg, wenn dir die üblichen Regeln reichen, etwa dass das Fenster frühestens nach 0.5 sec erscheint
 
Ok, hab das Ganze nochmal grundlegend umgebastelt.
So wird beim erzeugen der Klasse ein neuer Thread gestartet mit dem PM drinne. Doch wie schreibe ich jetzt den "Progress" direkt da rein ?
(Das Beispiel funktioniert natürlich nicht)

Java:
package Converter;

import javax.swing.ProgressMonitor;

public class MyProgressMonitor
{
	private int maxValue;
	
	public MyProgressMonitor(int maxValue)
	{
		this.maxValue = maxValue;
	    myProgressMonitorOpen();
		
	}

	
	private void myProgressMonitorOpen()
	{
		Thread thread = new Thread (new Runnable() 
		{
	    public void run() 
	    	{
	    	ProgressMonitor pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
			pm.setMillisToPopup(0);
		    pm.setMillisToDecideToPopup(0);
			pm.setMillisToPopup(0);
	    	}
	        
	    });
	    
	    thread.start();
	}  
	  
	  public void makeProgress(int progress, ProgressMonitor pm)
	  {
		  ???.pm.setProgress(progress);
	  }
}
 
Zuletzt bearbeitet:
Java:
package Converter;

import javax.swing.ProgressMonitor;

public class MyProgressMonitor
{
	private ProgressMonitor pm;
	
	public MyProgressMonitor(int maxValue)
	{
		pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
		pm.setMillisToPopup(0);
		pm.setMillisToDecideToPopup(0);
	}  
	  
	  public void makeProgress(int progress)
	  {
		  pm.setProgress(progress);
	  }
}
oder eben die ganze Klasse weg und der ProgressMonitor beim Aufrufer
 
Ja, darüber habe ich auch schon nachgedacht. Wie wahrscheinlich ist es das ein ProgressMonitor den ganzen (main) Thread schon lahm legt ... ???:L
Allerdings wäre es schön trotzdem so eine eigene Klasse zu haben. Die könnte man auch an anderer Stelle Benutzen.
OTOT: Sollte ich das nächste mal was mit Multi-Threading programmieren wäre ich schon mal ein Stück weiter :rtfm:
 
Hi,
und noch ein Versuch ...

Java:
package Converter;

import javax.swing.ProgressMonitor;

public class MyProgressMonitor
{
	private int maxValue;
	private ProgressMonitor pm;
	private int pg = 0;
	private Thread thread;
	
	public MyProgressMonitor(int maxValue)
	{
	    this.maxValue = maxValue;
	    myProgressMonitorOpen();
	    thread.start();
	}

	
	private void myProgressMonitorOpen()
	{
		thread = new Thread (new Runnable() 
		{
	    public void run() 
	    	{
	    	pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
			pm.setMillisToPopup(0);
		        pm.setMillisToDecideToPopup(0);
			pm.setMillisToPopup(0);
			pm.setProgress(pg);
			
				while (pg <= maxValue)
				{
					pm.setProgress(pg);
					System.out.println("pm: " + pg);
				}
	    	}
	        
	    });
	}  
	  
	public void makeProgress(int progress) throws InterruptedException
	  {
		Thread.sleep(1000);
		  pg = progress + 1;
	  }
}
Interessanterweise bekomme ich einen output über System.out.println(...) aber weder der Progrssmonitor balken ist sichtbar noch das "abbrechne" button ...
Nur um sicher zu gehen das der neue Thread auch genügend Zeit hat was zu holen, habe ich das Hauptprogramm ein wenig ausgebremst: Thread.sleep(1000);
 
Zuletzt bearbeitet:
kommt ganz auf das Restprogramm an, bei mir gehts,
Fenster erscheint sowie die unseligen ungezählten unnötigen Ausgaben,
der Thread läuft danach übrigens weiter, falls es nicht noch über maxValue hinaus geht


mit der von mir zuvor geposteten MyProgressMonitor (und angepasste makeProgress-Methode)
kein Deut Unterschied, nur die Unmengen an Ausgaben + CPU-Belastung weg

Java:
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        MyProgressMonitor mpm = new MyProgressMonitor(100);
        for (int i = 9; i < 100; i += 10) 
        {
            // 99 muss genau erwischt werden, damit makeProgress 100 draus macht für Abbruch..
            mpm.makeProgress(i); 
        }
    }
}


class MyProgressMonitor
{
    private int maxValue;
    private ProgressMonitor pm;
    private int pg = 0;
    private Thread thread;

    public MyProgressMonitor(int maxValue)
    {
        this.maxValue = maxValue;
        myProgressMonitorOpen();
        thread.start();
    }


    private void myProgressMonitorOpen()
    {
        thread = new Thread(new Runnable()
            {
                public void run()
                {
                    pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
                    pm.setMillisToPopup(0);
                    pm.setMillisToDecideToPopup(0);
                    pm.setMillisToPopup(0);
                    pm.setProgress(pg);

                    while (pg <= maxValue)
                    {
                        pm.setProgress(pg);
                        System.out.println("pm: " + pg);
                    }
                }

            });
    }

    public void makeProgress(int progress)
        throws InterruptedException
    {
        Thread.sleep(1000);
        pg = progress + 1;
    }
}
 
Hm, vielleicht liegt's am openJDK ... bin hier auf Fedora 16 32-Bit.
Werde aber Morgen noch mal was Anderes ausprobieren.
Die System.out.println sind ja auch nur dazu da um überhaupt zu festzustellen ob die Schleife läuft. Und sehr viel anders sieht mein Hauptprogramm auch nicht aus.
 
Ok, ich habe nun versucht den Thread solange "schlafen zu legen" bis meine Fuktion einen notify sended.
Nur warum carshed es an der Stelle mit dem notify ?

Java:
package Converter;

import javax.swing.ProgressMonitor;

public class MyProgressMonitor
{
	private int maxValue;
	private ProgressMonitor pm;
	private int pg = 0;
	private Thread thread;
	
	public MyProgressMonitor(int maxValue)
	{
	    this.maxValue = maxValue;
	    myProgressMonitorOpen();
	    thread.start();
	}

	
	private void myProgressMonitorOpen()
	{
		thread = new Thread (new Runnable() 
		{
	    public void run() 
	    	{
	    	pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
			pm.setMillisToPopup(0);
		        pm.setMillisToDecideToPopup(0);
			pm.setMillisToPopup(0);
			pm.setProgress(pg);
			try 
				{
					this.wait();
					while (pg <= maxValue)
					{
					pm.setProgress(pg);
					System.out.println("pm: " + pg);
					}
				} 
			catch (InterruptedException e) 
				{
				e.printStackTrace();
				}

	    	}
	        
	    });
	}  
	  
	public void makeProgress(int progress) throws InterruptedException
	  {
		System.out.println(pg);
		//Thread.sleep(1000);
		pg = progress + 1;
		thread.notify();

	  }
}
 
Das
Code:
notify()
muss in einem synchronized-Block sein:
Java:
synchronized (thread) {
    thread.notify();
}

Analog zum wait() ...
 
@Kroko ... leider nicht, das crashed sofort:

Java:
package Converter;

import javax.swing.ProgressMonitor;

public class MyProgressMonitor //implements Runnable
{
	private int maxValue;
	private ProgressMonitor pm;
	private int pg = 0;
	private Thread thread;
	
	public MyProgressMonitor(int maxValue)
	{
		this.maxValue = maxValue;
		//pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
		//Thread t1 =   new Thread( new
		myProgressMonitorOpen();
	    thread.start();
	}

private void myProgressMonitorOpen()
    {
        thread = new Thread (new Runnable() 
        {
        public void run() 
            {
            pm = new ProgressMonitor(null, "Refactoring", "", 0, maxValue);
            pm.setMillisToPopup(0);
            pm.setMillisToDecideToPopup(0);
            pm.setMillisToPopup(0);
            try 
                {
            		synchronized (thread)
            		{
            			this.wait();
            			while (pg <= maxValue)
            			{
            				pm.setProgress(pg);
            				System.out.println("pm: " + pg);
            			}
            		} 
                }
            catch (InterruptedException e) 
                {
                	e.printStackTrace();
                }
            }    
        });
    }  
	  
	public void makeProgress(int progress) throws InterruptedException
	  {
		//System.out.println(pg);
		//Thread.sleep(1000);
		  pg = progress + 1;
		  synchronized (thread)
		  {
			  thread.notify();
		  }
	  }
}

Code:
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at Converter.MyProgressMonitor$1.run(MyProgressMonitor.java:47)
	at java.lang.Thread.run(Thread.java:679)
 
Wenn du das
Code:
wait()
im Thread wie folgt einpackst, kommt die Ausnahme nicht mehr:

Java:
synchronized (this) {
    this.wait();
}

Aber "gehen" tut dein Programm dennoch nicht. Der ProgressMonitor gehört nicht in irgendeinen Thread sondern in die AWT-EventQueue. Der arbeitende Thread muss den ProgressMonitor nur benachrichtigen und das get über setProgress().

Von der Oracle-Seite gibts ein Beispiel mit SwingWorker. Hier hast du auch Parallelität, allerdings in sauberer Form. Das Zusammenspiel mit dem Worker, den Monitor und den Listenern mag zwar nicht sofort eingänglich sein, aber ist letztlich doch "besser" als ein eigener Lockingmechanismus.
 
und beide Befehle müssen an denselben Objekt gerufen werden,
das 'this' in der run-Methode dürfte sich im Moment auf das Runnable beziehen, das ist ungleich dem Thread-Objekt,
entweder das Runnable mehr und beide darauf synchronisieren oder beide Stellen auf das thread-Objekt
 
Ich kann ja gar nicht genug darauf hinweisen: Synchronisierung in Java hat das Problem, dass sie so einfach aussieht. Wirklich kompliziert ist's gar nicht, aber viele Leute benutzen Synchronisierung ohne sie verstanden zu haben. Das Tutorial (oder gern auch ein anderes) zu lesen und zu verstehen ist eine wirklich gute Investition.

Ahoi, Ebenius
 

Zurück
Oben