Swing SwingWorker abbrechen

Cromm Cruach

Mitglied
Hallo,

Folgender SwingWorker befüllt ein Formular mit daten und Bildern aus dem Internet:

Java:
public class ImportDataSwingWorker extends SwingWorker<String, String> {

	AddFilmDialogController addFilmDialogController;


	/**
	 * Übergibt den Formularcontroler
	 * 
	 * @param addFilmDialogController
	 *            Controller
	 */
	public ImportDataSwingWorker( AddFilmDialogController addFilmDialogController ) {

		this.addFilmDialogController = addFilmDialogController;
	}


	/**
	 * Ausführung der Aufgabe
	 */
	@Override
	protected String doInBackground() throws Exception {

		addFilmDialogController.disableDialog();

		if ( addFilmDialogController.isImportFieldEmpy() ) {
			addFilmDialogController.setImportError( "Bitte geben Sie eine TMDb-ID ein!" );
		} else {
			addFilmDialogController.setImportError( "" );
			try {
				addFilmDialogController.loadMovie();
				addFilmDialogController.importData();
			} catch ( IOException | ParserConfigurationException | SAXException e ) {
				e.printStackTrace();
			}
		}

		addFilmDialogController.enableDialog();

		return null;
	}


}

Während des Ladevorgangs wird ein Ladebildschrim angezeigt. Auf diesem Befindet sich ein Button der den Ladevorgang abbrechen soll! In diesem Fall soll der Swingworker gestopt und das Formular geleert werden. Der Button ruft folgende Methode auf:

Java:
	/**
	 * Bricht den Importvorgang ab
	 */
	public void cancelImport() {

		enableDialog();
		importDataSwingWorker.cancel( true );
		addFilmDialog.clearCover();
		addFilmDialog.clearFields();
		addFilmDialog.clearTables();
		splashScreen.closeWindow();
	}

Wenn ich den Abbruchvorgang ausführe kommt folgende Konsolenausgabe:

Code:
INTERRUPTED while loading Image

Alles was bis dahin geladen wurde, wird wie gewünscht geleert. Das ist das der SwingWorker nicht stoppt! Wenn z.B. Alle Textfelder befüllt und 10 von 15 geladen sind und ich den Abbruch betätige, werden die Textfelder geleert die 10 aus der Anzeige entfernt aber der SwingWorker arbietet weiter und läd noch die 5 verbleibenden Bilder. Egal wo ich den Abbruch betätige der SwingWorker führt den Rest seint Aufgabe aus.

Ich habe bisher nur mit SwingWorkern gearbeitet, die von Anfang bis Ende laufen sollte. Das ist das erste mal das ich in einen Thread eingreifen will. Wie beende ich diesen korrekt und gehe sicher, dass das Leeren des Dialogs erst dann ausgeführt wird wenn der Worker auch korrekt beendet ist sodass auch alles gelöscht ist.

Gruß
 
Ich schätze mal du fängst in deinen Methoden addFilmDialogController.loadMovie() bzw. addFilmDialogController.importData() eine InterruptException ab. Der SwingWorker der die Methoden aufruft kriegt davon aber nichts mehr mit und macht munter weiter-> Du solltest die Exception im SwingWorker abfangen.
 
Heist das bei alle Methoden vom SwingWorker aufgerufen werden
Code:
throws InterruptException
? Dann sollte es klappen?!

In den beiden Methoden werden keine Exception aufgerufen oder Weitergereicht und iwie erklärt mir das immer noch nicht wie ich den SwingWorker abbreche bzw warum meiner weiterläuft.
 
Zuletzt bearbeitet:
Das ist schon klar. Allerdings wird der Fehler ohne Zeilenangabe ausgegeben. Es wird nur diese Zeile ausgegeben. Und der Obenangegebene Try-Catch-Block ist der einzige im gesamten Orogamm bis jetzt und die fängt den fehler nicht ab das hab ich getestet.

EDIT: Ich habe nun noch ein wenig DEBUGT.

Die Bilder läd folgende Methode sie wird für jedes Bild das geladen werden soll aufgerufen:

Java:
	public ImageIcon loadPicture(String adress, int width, int height, int id, int option) throws MalformedURLException{
		
		ImageIcon icon = null;
		
		switch(option){
			case 0:
				icon = new ImageIcon(new URL(adress));
				break;
		}
		
		icon.setImage(icon.getImage().getScaledInstance(width, height, Image.SCALE_DEFAULT));
		
		return icon;
	}

Zum Zeitpunkt des Abbruchs befindet sich das Programm iwo in dieser Methode. Drückt ich dann "Abbrechen" "springt es zum oben genannten Methode
Code:
cancelImport()
. Danach wird wird die Methode
Code:
loadPicture()
zuende ausgefüht. Der Fehler
Code:
INTERRUPTED while loading Image
wird an dem Punkt
Code:
return icon
ausgegeben. Hier endet das Programm aber nun nicht, sondern die Methode wird für alle anderem Bilder aufgerufen und sie werden geladen.
 
Zuletzt bearbeitet:
Irgendwo in deinem Code muss doch ein System.out.println("INTERRUPTED while loading"); stehen. An der Stelle würde ich mal nachsehen.
Was anderes wäre noch, wie startest du deinen Worker denn? Ich hoffe doch dass du die doInBackground Methode nicht direkt aufrufst. Hab dir ein Beispiel gemacht:Anhang anzeigen WorkerCancel.java
 
Was hat er Swingworker überhaupt für einen Sinn, wenn er nie publish/process aufruft um den Ladebalken zu aktualisieren?
 
Erstmal danke für den Blog-Eintrag. Der SwingWorker ist mir nun noch etwas klarer geworden. Hab das lereren des Dialogs nun in den Swingworker mit eingebaut. Das Funktioniert schon besser. Das Problem ist, das immer noch die Fehlenden Bilder (die beim Abbruch nicht mehr geladen werden sollen) geladen werden.

Der überarbeitete SwingWorker:
Java:
public class ImportDataSwingWorker extends SwingWorker<Void, Void> {

	AddFilmDialogController addFilmDialogController;


	/**
	 * Übergibt den Formularcontroler
	 * 
	 * @param addFilmDialogController
	 *            Controller
	 */
	public ImportDataSwingWorker( AddFilmDialogController addFilmDialogController ) {

		this.addFilmDialogController = addFilmDialogController;
	}


	/**
	 * Ausführung der Aufgabe
	 */
	@Override
	protected Void doInBackground() throws Exception {

		addFilmDialogController.disableDialog();
		addFilmDialogController.clearDialog();
		
		if ( addFilmDialogController.isImportFieldEmpy() ) {
			addFilmDialogController.setImportError( "Bitte geben Sie eine TMDb-ID ein!" );
		} else {
			
			try {
				addFilmDialogController.loadMovie();
			} catch ( IOException | ParserConfigurationException | SAXException e ) {
				e.printStackTrace();
			}
			
			if(addFilmDialogController.importIdExist()){
				addFilmDialogController.setImportError( "" );
				try {
					addFilmDialogController.importData();
				} catch ( MalformedURLException e ) {
					e.printStackTrace();
				}
			}else{
				addFilmDialogController.setImportError( "Die TMDB-ID existiert nicht!" );
			}
			
		}

		addFilmDialogController.enableDialog();
		
		return null;
	}
	
	/**
	 * Aufruf bei Endes des Swingworkers
	 */
    @Override
    protected void done() {
        Boolean completed = isCancelled();
        if (completed) {
    		addFilmDialogController.clearDialog();
                System.out.println("Abgebrochen");
        }
    }

Die Konsolenausgabe ist nun:

Code:
INTERRUPTED while loading Image
Abgebrochen

Um den Fehler vll besser Verfolgen zu können hier die
Code:
importData()
Methode die u.a. den Coverload auslöst!

Java:
	public void importData() throws MalformedURLException {

		[...]

		splashScreen.setActionLabel( "Cover..." );
		importCoverData();

		splashScreen.closeWindow();
		addFilmDialog.toFront();
	}

Die
Code:
importCoverData()
hohlt die URL aus einer Datei und übergibt sie dann an die Oben genannte methode zum Laden der Bilder.

Java:
	/**
	 * Füllt das Panel "Cover"
	 * 
	 * @throws MalformedURLException
	 */
	private void importCoverData() throws MalformedURLException {

		LinkedList<HashMap<String, String>> coverData = tmdbMl.getCoverData();

		coverPanelList = new LinkedList<CoverPanel>();

		for ( int i = 0 ; i < coverData.size() ; i++ ) {
			HashMap<String, String> element = coverData.get( i );

			coverPanelList.add( new CoverPanel( pictureHandler.loadPictureOnline( element.get( "url" ), 112, 168 ), addFilmDialog.getCoverButtonGroup() ) );

			addFilmDialog.addCover( coverPanelList.get( i ) );
			splashScreen.incrementProgress();
		}
	}
(
Code:
loadPictureOnline()
ruft die
Code:
loadPicture()
auf)


So das ist nun der komplette Coverladevorgang der nach Abbruch trotzdem weitergeführt wird.
 
Du brauchst für die for Schleife in importCoverData eine weitere Abbruchbedingung für den Fall, dass der SwingWorker abgebrochen wird, sonst wird diese ja einfach weiter durchlaufen.
 
Danke nun klappts. Das ich die Schleife seperat abbrechen muss war mir nicht bekannt. Ich dachte wenn der Thread gecancelt wird, wird auch alles abgebrochen was sich in seinem Ausführungsstrang befindet (so auch die Schleife).

Java:
if(swingWorker.isCancelled()){
     clearDialog();
     break;
}

Das hat geholfen!
 
Ah noch eine Info die nicht schadet 😉. Womit wir beim nächsten "ich dachte" wären: Ich dachte mit dem SwingWorker cancelt auch der Thread! Weniger annehmen mehr Doku lesen 😀
 

Neue Themen


Zurück
Oben