Anzeige:
Ergebnis 1 bis 6 von 6

Thema: SWT-Widgets per Thread immer wieder neu zeichnen?

  1. #1
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53

    SWT-Widgets per Thread immer wieder neu zeichnen?

    Hallo,

    ich bin's mal wieder mit meinem SWT. Dieses Mal mit folgendem Problem...

    Ich lade einige Dateien per FTP hoch. Weil das ganze zusammen mit einem Logwindow, eine ProgressBar und anderen netten Spielereien läuft, habe ich jeden Upload in einen syncExec gepackt (damit nicht X Dateien gleichzeitig hochgeladen werden).
    Wenn die Datei jetzt etwas größer ist, dauert es natürlich länger, bis der Thread fertig ist. Das Ergebnis ist, daß alle meine Widgets nicht mehr da sind, wenn ich das Fenster mal minimiere z.B. Ich dachte, gut, dann mach ich eben noch einen asyncExec-Thread, der alle 250ms meine Widgets neu zeichnet -- aber Pustekuchen, weder mit update() noch mit redraw() kriege ich das hin, das Programm bleibt dann stehen. Der Effekt bleibt derselbe.

    Hat jemand eine Idee, wie man Widgets in SWT einfach nur neu zeichnen kann?

    Gruß,
    das Techl

  2. #2
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Äh was? Du machst die ganze Arbeit in einem Syncexec?

    Kein Wunder kommt er nicht zum neuzeichnen - schliesslich wird das was du mit display-syncexec ausführst im Hauptthread ausgeführt (der deshalb nicht dazu kommt die Nachrichtenschleife abzuarbeiten und entsprechend auch nicht neu zeichent)...

    Im syncexec tut nur die Widgetinhalte ändern - nicht mehr. Sonst könntest du genau so gut eine single-thread Anwendung machen ...

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

  3. #3
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53
    Das eigentliche Iterieren, Datei öffnen, usw., läuft in einem Extrathread. Aber wie soll ich denn das Kopieren sonst regeln, wenn ich -- je nach Datei -- noch ein Label ändern und den Fortschrittsbalnken zeichnen muß? Sonst blöckt SWT doch wieder mit einer IllegalThreadAccessException...
    Geändert von Technaton (31-05-2005 um 08:38 Uhr)

  4. #4
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53
    Jetzt, wo ich wieder dran bin, will ich auch noch einen Codeabriß liefern. Zur Erklärung: Die Methoden summon() und die() kommen aus einer Factory (Creature ist die abstrakte Methode dazu) und werden von einer zentralen Stelle aus aufgerufen. summon() bastelt erst das Design und ruft dann den Kopierthread in einer asyncExec-Methode auf. Aus dem heraus wieder sollen die ProgressBar und das "Kopiert gerade Datei: xy"-Label aktualisiert werden.

    Code:
    public class Ftpcopy extends Creature {
    	private static ProgressBar	pbar;
    	private	static Label		currentFileLabel;
    	// TODO replace this with some value read from some options file
    	private	static final String	sourceFileName		=	"source.zip";
    	private static ZipFile		productArchive;
    	
    	class Copyer extends Thread {
    		private ZipEntry zipentry; 
    		private int iter = 1;
    		public Copyer() {
    			super("Copyer");
    		}
    		
    		public synchronized void run () {
    			// set wait cursor
    			innerArea.getShell().setCursor
    				(new Cursor(innerArea.getDisplay(),SWT.CURSOR_WAIT));
    			
    			try {
    				productArchive = new  ZipFile(sourceFileName);
    				pbar.setSelection(0);
    				pbar.setMaximum(productArchive.size());
    		
    				FtpManager.initConnection();
    				FtpManager.changeToDestDir();
    		
    				
    				for(Enumeration e = productArchive.entries(); 
    				e.hasMoreElements();) {
    					iter++;
    					final ZipEntry zipentry = (ZipEntry)e.nextElement();
    					pbar.setSelection(iter);
    					setCurrentFileLabelDesc(zipentry.getName());
    					if(zipentry.isDirectory())
    						FtpManager.makeDirectory(zipentry.getName());
    					else
    						FtpManager.uploadZipEntry(productArchive,zipentry);
    				}
    			} catch (Exception e) { // TODO DEBUG
    				System.err.println("Exception when uploading: "+e.toString()
    					+"\n- - - - - - - - -\n");
    				e.printStackTrace();
    			}
    			
    			// restore layout
    			proceedBtn.setEnabled(true);
    			cancelBtn.setEnabled(true);
    			innerArea.getShell().setCursor
    				(new Cursor(innerArea.getDisplay(),SWT.CURSOR_ARROW));
    		}
    	}
    	
    	/**
    	 * Patch label together. Saves typework. :P
    	 * @param desc
    	 **/
    	private void setCurrentFileLabelDesc(String desc) {
    		if(desc.length() > 80) {
    			desc = "..."+desc.substring((desc.length()-77),desc.length());
    		}
    		currentFileLabel.setText(
    			WizardDialogueFactory.getP("Ftpcopy","currentfilelabeldesc")
    			+" "+desc
    		);
    	}
    	
    	/* * * 
    	 * (non-Javadoc)
    	 * @see de.trionic.mpi.gui.creatures.Creature#summon(de.trionic.mpi.gui.DialoguePage)
    	 * * */
    	public void summon(DialoguePage diag) {
    		/* some init stuff */
    		innerArea	= diag.innerArea;
    		proceedBtn	= diag.submitBtn;
    		cancelBtn	= diag.cancelBtn;
    		proceedBtn.setEnabled(false);
    		cancelBtn.setEnabled(false);
    		/* end init stuf */
    		
    		/* BEGIN layout creation */
    		// ... SWT layout blabla...
    		/* END layout creation */
    		
    		/* BEGIN copy */
    		innerArea.getDisplay().asyncExec(new Copyer());
    		/* END copy */
    	}
    
    	/* (non-Javadoc)
    	 * @see de.trionic.mpi.gui.creatures.Creature#die()
    	 */
    	public void die() {
    		FtpManager.closeConnection();
    	}
    }

  5. #5
    Registrierter Benutzer
    Registriert seit
    02.01.2005
    Beiträge
    53
    Ok, ich habe jetzt verstanden, was du mit deiner Aussage meintest. Ich hatte etwas anderes angenommen.

    Ich habe jetzt das
    Code:
    innerArea.getDisplay().asyncExec(new Copyer());
    durch
    Code:
    Copyer copy = new Copyer();
    copy.start();
    ersetzt, und innerhalb der Copyer-Klasse die Methoden, die was am Dialog ändern, in eine syncExec gepackt. Jetzt geht das auch, und das war wahrscheinlich auch, was du meintest.

    Kleine Frage zum Schluß: Aufgrund der Architektur des Programmes muß ich häufig mit anderen Threads arbeiten, die am GUI selbst was ändern müssen. Jedes Mal eine anonyme Threadklasse dafür zu schreiben ist etwas mühsam, deswegen dachte ich mir, ich implementiere eine Methode, der ich eine andere Methode als Parameter übergebe. Den Parameter führe ich dann in einem sync oder asyncExec aus. Ich bin jetzt soweit zum Rumpf gekommen:
    Code:
    public void execSwtFromOutside(final Method method) {
    	innerArea.getDisplay().asyncExec(new Runnable() {
    		public void run () {
    			try {
    				method.invoke(this,null);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	});
    }
    , aber wie übergebe ich eine Methode? Von Perl bin ich etwas a la execSwtFromOutside( { .... } ); gewohnt, aber das geht wohl nicht. execSwtFromOutside(new Method() { ... }); funktioniert auch nicht, also wie heißt der korrekte Aufruf?!

  6. #6
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Zitat Zitat von Technaton
    copy.start();[/code] ersetzt, und innerhalb der Copyer-Klasse die Methoden, die was am Dialog ändern, in eine syncExec gepackt. Jetzt geht das auch, und das war wahrscheinlich auch, was du meintest.
    Genau. Wenn du was mit asyncExec() ausführst ist das nämlich kein Thread. (Der Methodenname ist insofern etwas unklar - aber die Beschreibung hingegen schon).

    Kleine Frage zum Schluß: Aufgrund der Architektur des Programmes muß ich häufig mit anderen Threads arbeiten, die am GUI selbst was ändern müssen.
    Das kommt mir bekannt vor...

    Jedes Mal eine anonyme Threadklasse dafür zu schreiben ist etwas mühsam, deswegen dachte ich mir, ich implementiere eine Methode, der ich eine andere Methode als Parameter übergebe.
    Funktionspointer gibts eben nicht in Java. Leider - das wäre ja genau das was du hier brauchen würdest. Darum geht das nicht. Das ist imo einer der Nachteile von Java - das ständige Implementieren von anonymen Klassen als Listener/Thread oder sonstwas ist mühsam und unübersichtlich.

    Falls du trotzdem irgend eine brauchbare einfache Lösung finden solltest würde mich das natürlich freuen

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •