Labelinhalt über Thread ändern...

Ronin-Jay

Erfahrenes Mitglied
Hallo zusammen,

ich bin gerade ein wenig verzweifelt. Und zwar versuche ich den Inhalt eines Labels über einen Thread zu ändern. Das ganze sieht nachher so aus, das über den Thread per RMI in gewissen Zeitintervallen ein Wert geholt werden soll. Wie kann ich jedoch in dem Thread auf das Label zugreifen, bzw über eine get/set Methode den Wert ändern? Ich habe mal ein simples Beispiel angehängt, welches mich allerdings in den Wahnsinn treibt, da ich im Thread immer eine Exception bekomme....

Her wer von Euch vielleicht noch einen Hinweis für mich?

Code:
aktualisierter Source s.u.
 
Zuletzt bearbeitet:
Hallo,

du solltest erstmal in deinem Programm nicht alles static zu deklarieren. Es reicht normal aus, wenn die main-Methode static ist, es sei denn du möchtest kein Object von deiner Klasse anlegen oder auf die Methoden oder Variablen zugreifen ohne ein Object der Klasse instanziert zu haben.
Also am besten machst du alles aus deiner main-Methode im Konstruktor und legst in der main dann ein Object deiner Klasse an. Dann brauchst du nichts als static zu deklarieren. Bei deinem Thread kannst du dann am besten entweder das Object deiner displ-Klasse übergeben und über die getter-Methode auf dein Label zugreifen oder du übergibst direkt das Label an den Thread und änderst dann den Text.

MFG

zEriX
 
du solltest erstmal in deinem Programm nicht alles static zu deklarieren. Es reicht normal aus, wenn die main-Methode static ist, es sei denn du möchtest kein Object von deiner Klasse anlegen oder auf die Methoden oder Variablen zugreifen ohne ein Object der Klasse instanziert zu haben....
Shell, display und label sind static, weil ich auf display und shell in der statischen main zugreife und das label habe ich nachträglich static gemacht - das war der Versuch auf das Label mittels Methoden zuzugreifen....

...Bei deinem Thread kannst du dann am besten entweder das Object deiner displ-Klasse übergeben und über die getter-Methode auf dein Label zugreifen oder du übergibst direkt das Label an den Thread und änderst dann den Text....
Genau das habe ich auch schon versucht, aber es führt zu einer Exception:

Code:
Parallel-Thread arbeitet
Exception in thread "Thread-0" org.eclipse.swt.SWTException: Invalid thread access
	at org.eclipse.swt.SWT.error(SWT.java:3374)
	at org.eclipse.swt.SWT.error(SWT.java:3297)
	at org.eclipse.swt.SWT.error(SWT.java:3268)
	at org.eclipse.swt.widgets.Widget.error(Widget.java:435)
	at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:331)
	at org.eclipse.swt.widgets.Label.setText(Label.java:365)
	at ECM.anzeige.setLabel(anzeige.java:59)
	at ECM.myThread.run(anzeige.java:21)

Quelltext habe ich auch noch mal ein wenig Übersichtlicher gemacht:
Java:
package ECM;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;


class myThread extends Thread{
	anzeige disp;

	public myThread(anzeige displ) {
		// TODO Auto-generated constructor stub
		disp = displ;
	}

	public void run(){
		while(true){
			System.out.println("Parallel-Thread arbeitet");
			try {
				Thread.sleep(1000);
				disp.setLabel("THREADLABEL");
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}
	
}

public class anzeige {
	static Display display;
	static Shell shell;
	Label label;
	
	/**
	 *  Constructor.
	 */
	private anzeige() {
		display = new Display();
		shell = new Shell(display);
	}

	
	/**
	 * 
	 */
	public void createGUI(){
		shell.setLayout (new FillLayout ());
		label = new Label(shell, SWT.NONE);
		label.setText("test");
	}
	
	
	/**
	 * setLabel (newLabel)
	 */
	public void setLabel(String newLabel){
		label.setText(newLabel);
	}
	
	
	/**
	 * getLabel
	 */
	public String getLabel(){
		return label.getText();
	}
	
	
	/**
	 * MAIN
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		anzeige displ = new anzeige();
		displ.createGUI();
		
		myThread mth = new myThread(displ);
		mth.start();
		

		shell.pack();
		shell.open();
		while(!shell.isDisposed())
			if(!display.readAndDispatch())
				display.sleep();
		mth.stop();
	}
}


:confused: Any hints? :confused:
 
Hallo,

wenn du unter SWT das UI aus einem anderen Thread heraus als dem UI / Main Thread manipulieren willst musst du das über die asyncExec/syncExec Methoden des Displays machen:
Java:
/**
 * 
 */
package de.tutorials;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;

/**
 * @author Thomas.Darimont
 * 
 */
public class SWTThreadingExample {

    /**
     * @param args
     */
    public static void main(String[] args) {
        final Display display = new Display();
        Shell shell = new Shell(display);
        shell.setLayout(new FillLayout());
        final Label label = new Label(shell, SWT.NONE);

        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.execute(new Runnable() {

            final Runnable updateTimeLabel = new Runnable() {
                @Override
                public void run() {
                    label.setText("Current time:" + new Date());
                }
            };

            @Override
            public void run() {
                while (true) {
                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        //ignore
                    }

                    if (null != display && !display.isDisposed()) {
                        display.asyncExec(updateTimeLabel);
                    } else
                        break;
                }
            }

        });

        shell.setText("SWTThreadingExample");
        shell.pack();
        shell.open();

        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }

        System.exit(0);
    }

}

Gruß Tom
 
@ Thomas:

Vielen Dank für das Beispiel. Ich hatte Deinen Hinweis darauf schon in einen anderen Thread im Forum gelesen, allerdings hat er mich nicht wirklich weitergebracht. Werde das angehängte Beispiel morgen mal ausprobieren....

Edit [09.05.]:
So, ich habe es mal ausprobiert und es funktioniert wunderbar. VIELEN DANK für die Mühe.
 
Zuletzt bearbeitet:
Moin zusammen,
ich hab' grad ein ähnliches Problem, komme aber irgendwie mit euren Lösungsansätzen nicht zum Ziel...

Meine Problemstellung gestaltet sich folgendermaßen, dass es verschiedene Klassen gibt, die jeweils als Threads laufen sollen, und zwar
-> Die Hauptklasse des Programmes mit der void main, die die komplette kontrolle hat
sie startet alle Threads
-> Klassen mit Anwendungslogik, die von der Hauptklasse in Threads gestartet werden und ihre Resultate an die Hauptklasse weitergeben
->Die GUI-Klasse. Sie stößt in der Hauptklasse operationen an und soll auch von dieser Informationen empfangen.

Schematisch geht's um folgende Klassen (ich hab das jetzt auf funktionale Dummies abgebildet, der tatsächliche Code würde hier den Rahmen sprengen...)

Hauptklasse (die Main, die alles verwaltet)
Code:
public class testMain {
private testVisual gui;
	
public static void main(String[] args) {
		testMain t= new testMain();
		
		t.makeGui();
		

	}
private void makeGui(){
	gui = new testVisual(this);
	Thread tGui = new Thread(gui);
	tGui.start();
	
	
}
public void sendToGui(String s){
	gui.addToTree(s);
}
public void startCountUp(){
	Thread c = new Thread(new testThread(this));
	c.start();
	
}	
}

Die GUI
Code:
import java.util.ArrayList;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Button;

public class testVisual implements Runnable {

	private Shell sShell = null;  //  @jve:decl-index=0:visual-constraint="56,33"
	private Tree tree = null;
	private Label label = null;
	private Button button = null;
	private testMain mainProgramm;
	private ArrayList treeitems = new ArrayList();

	public testVisual(testMain mainProgram){
		this.mainProgramm=mainProgram;
	}
	private void createSShell() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 3;
		sShell = new Shell();
		sShell.setLayout(gridLayout);
		sShell.setSize(new Point(654, 204));
		tree = new Tree(sShell, SWT.NONE);
		label = new Label(sShell, SWT.NONE);
		label.setText("Sehr langer fülltext");
		button = new Button(sShell, SWT.NONE);
		button.setText("Start");
		button.addMouseListener(new org.eclipse.swt.events.MouseAdapter() {
			public void mouseUp(org.eclipse.swt.events.MouseEvent e) {
				mainProgramm.startCountUp();
				
			}
		});
	}

	public void run() {
		Display display = Display.getDefault();
		
		this.createSShell();
		this.sShell.open();

		while (!this.sShell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();
		createSShell();
		
	}
	public void addToTree(String s){
		label.setText(s);
		TreeItem t = new TreeItem(tree,0);
		t.setText(s);
		treeitems.add(t);
		
	}

}

Die eigentliche Anwendungslogik
Code:
public class testThread implements Runnable {
	private testMain mainclass;
	
	public testThread(testMain mainclass){
		
		this.mainclass = mainclass;
	}
	public void run() {
		// TODO Auto-generated method stub
		for(int i=0;i<1000000;i++){
			if((i%5)==0){
				
				
			
			if((i%47)==0)
				mainclass.sendToGui("Test bei: "+i +"");
			}
	}
	}

}

Wenn ich das ganze nun so implementiere, bekomme ich den bereits beschriebenen Fehler, von wegen dass es dem Thread nicht erlaubt sei, auf die SWT-Komponente zuzugreifen.


Hat mir jemand einen Tip?
 
Zurück