Anzeige:
Ergebnis 1 bis 8 von 8

Thema: [SWT] non-gui-Thread + Gui wird nur aktualisiert wenn Fenster aktiv

  1. #1
    Registrierter Benutzer
    Registriert seit
    24.03.2003
    Beiträge
    71

    [SWT] non-gui-Thread + Gui wird nur aktualisiert wenn Fenster aktiv

    Hallo,

    versucht gerade wieder etwas fitter in Java zu werden und wollte zum warm werden einen kleinen IRC-Client mit SWT schreiben. Soweit so gut. Mein Problem im Moment ist, dass ich nicht genau weiss wie ich am besten das Chatfenster aktualisiere. Im Moment habe ich eine Connection-Klasse, die das Interface Runnable implementiert, und sobald am InputStream etwas anliegt (in.ready()) es eine Variable auf true schält.
    In meiner GUI-Klasse überwache ich innerhalb des Eventloops eben jene Variable und sobald sie auf true steht, hole ich mir die neue Nachricht von der Verbindung.
    Das klappt eigentlich auch, allerdings erscheinen die neuen Nachrichten erst, wenn ich mit der Maus über meinem Chatfenster bin oder dieses aktiv ist.
    Das ist nat. etwas nervig, da der chat auch im Hintergrund aktualisiert werden sollte.

    Wo ist mein Denkfehler?

    GUI-Klasse:
    Code:
    import org.eclipse.swt.*;
    import org.eclipse.swt.widgets.*;
    import org.eclipse.swt.layout.*;
    import org.eclipse.swt.custom.StyledText;
    
    public class MainWindow{
    	private Display display;
    	private Shell shell;
    	private StyledText textArea;
    	private List nickList;
    	private Connection conn;
    	private Text input;
    	private Button btnSend;
    	
    	MainWindow() {
    		display = new Display();
    		shell = new Shell(display);
    		shell.setText("JIRC - SWT-based Java IRC client");
    		conn = new Connection();
    		createGUI();
    		nickList.add("AceTheFace");
    		shell.open();
    		while(!shell.isDisposed())	{
    			if(!display.readAndDispatch())
    				display.sleep();
    			if(conn.hasNewMessages()) {
    				String text = conn.getMessage();
    				if(text!="")
    					textArea.append(text+System.getProperty("line.separator"));
    			}
    		}
    		
    		
    	}
    	
    	private void createGUI() {
    		GridLayout layout = new GridLayout();
    		layout.numColumns = 2;
    		shell.setLayout(layout);
    		GridData g1 = new GridData(GridData.FILL_BOTH);
    		GridData g2 = new GridData(SWT.END);
    		GridData g3 = new GridData(GridData.FILL_HORIZONTAL);
    		GridData g4 = new GridData();
    		//create TextArea
    		textArea = new StyledText(shell,SWT.FULL_SELECTION|SWT.READ_ONLY);
    		textArea.setCursor(null);
    		textArea.setToolTipText("Gelaber im Channel");
    		textArea.setLayoutData(g1);
    		//create NickList
    		nickList = new List(shell,SWT.SINGLE);
    		nickList.setToolTipText("Leute im Channel");
    		nickList.setLayoutData(g2);
    		//create InputField
    		input = new Text(shell, SWT.SINGLE);
    		input.setToolTipText("Gib' hier deinen Text ein...");
    		input.setLayoutData(g3);
    		//create sendButton
    		btnSend = new Button(shell,SWT.PUSH);
    		btnSend.setText("Senden");
    		btnSend.setToolTipText("Klicken zum Abschicken");
    		btnSend.setLayoutData(g4);
    	}
    
    }
    Connection-Klasse:
    Code:
    import java.io.*;
    import java.net.*;
    
    public class Connection implements Runnable {
    
    	private Socket socket = null;
    	private PrintWriter out = null;
    	private BufferedReader in = null;
    	private boolean newMessages;
    	private String nick;
    	private String realName;
    	
    	Connection() {
    		nick = "AceTheFklace";
    		realName = "T.H.";
    		try {
    			socket = new Socket("localhost",6667);
    			out = new PrintWriter(socket.getOutputStream(),true);
    			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		} catch(UnknownHostException e) {
    			System.err.println("Unknown Host...");
    			System.exit(1);
    		} catch(IOException e) {
    			System.err.println("I/O-Error :(");
    			System.exit(1);
    		}
    		sendMessage("USER "+realName+" * * "+realName);
    		sendMessage("NICK "+nick);
    		new Thread(this).start();
    	}
    	
    	public boolean hasNewMessages() {
    		return newMessages;
    	}
    	
    	public String getMessage() {
    		String text;
    		try{
    			if(in.ready()) {
    				text = in.readLine();
    				newMessages=false;
    				return text;
    			}
    			else return "";
    		} catch(IOException e) {
    			System.err.println("IO-Error: "+e);
    			System.exit(1);
    			return null;
    		}
    	}
    	
    	public void run() {
    		try {
    			while(true) {
    				if(in.ready())
    					newMessages = true;
    				Thread.sleep(100);
    			}
    		} catch(IOException e) {
    			System.err.println("IO-Error: "+e);
    			System.exit(1);
    		} catch(InterruptedException e) {
    			System.err.println("uh oh"+e);
    			System.exit(1);
    		}
    	}
    	
    	public void sendMessage(String msg) {
    			out.append(msg+System.getProperty("line.seperator"));
    			System.out.println(msg);
    			out.flush();
    	}
    	
    	public void close() {
    		try {
    			in.close();
    			out.close();
    		} catch(IOException e) {
    			System.err.println("IOException: "+e);
    			System.exit(1);
    		}
    		
    	}
    	
    }
    Gruß und danke,
    Ace

  2. #2
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Das Problem ist wohl dass

    Code:
    display.sleep();
    so lange wartet bis es Events zu verarbeiten gibt. Und das ist dann erst der Fall wenn da was neu gezeichnet werden muss oder so - oder das Fenster wurde aktiviert...

    Am besten verwendest du um sowas zu erreichen die Funktion Display.asyncExec() - also in Connection sowas ähnliches:
    Code:
    if(in.ready())
    // text lesen
    //...
    display.asyncExec(new Runnable() {
       public void run() {
          textArea.append(text+System.getProperty("line.separator"));
       }
    }
    );
    Der Code da funktioniert wohl nicht 100%ig - meine SWT-Zeit ist schon etwas her.

    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
    24.03.2003
    Beiträge
    71
    Hm, eigentlich wollte ich alles GUI-Technische aus so Sachen wie der Connection-Klasse raushalten.
    Aber ich werds nachher trotzdem mal probieren, danke.

    Gruß,
    Ace

  4. #4
    Registrierter Benutzer
    Registriert seit
    09.03.2005
    Beiträge
    5
    Und, klappts ?

  5. #5
    Registrierter Benutzer
    Registriert seit
    24.03.2003
    Beiträge
    71
    Ich hab' das jetzt so gelöst:

    Code:
    while(!shell.isDisposed())	{
             //neue Nachrichten ausspucken
    	display.asyncExec(new Runnable() {
    		public void run() {
    			if(conn.hasNewMessages()) {
    				String text = conn.getMessage();
    				if(text!="") {
    				       textArea.append(text+System.getProperty("line.separator"));
    			               textArea.setTopIndex(textArea.getLineCount()-1);
    				}
    			}				
    		}
    	});
    	if(!display.readAndDispatch())
    		display.sleep();
    }
    Also direkt in der Eventloop. So habe ich dann immernoch die Verbindung von der GUI getrennt.

    Aber ich hab schon wieder ein Problem

    Gruß,
    Ace
    Geändert von AceTheFace (23-05-2006 um 14:52 Uhr)

  6. #6
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Ich hab auch nicht mehr ganz 100%ig im Kopf wie das ganze läuft - aber bist du sicher dass das nicht den Eventloop in den Wahnsinn treibt indem es immer neue Events generiert - quasi im Eventloop selber?

    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)

  7. #7
    Registrierter Benutzer
    Registriert seit
    24.03.2003
    Beiträge
    71
    Zitat Zitat von peschmae
    Ich hab auch nicht mehr ganz 100%ig im Kopf wie das ganze läuft - aber bist du sicher dass das nicht den Eventloop in den Wahnsinn treibt indem es immer neue Events generiert - quasi im Eventloop selber?

    MfG Peschmä
    Na ja, kommt mir auch irgendwie komisch vor...aber es funktioniert bestens, und das ist ja eigentlich die Hauptsache
    Aber wenn du noch'ne andere (sauberere) Lösung, immer her mit. Nur bitte nichts in der Connection-Klasse

    Gruß,
    Ace

  8. #8
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Du könntest - das treibt den Aufwand natürlich etwas in die Höhe - in der Connection Klasse ein Listener-Ding implementieren.
    D.h. von deinem Hauptprogramm aus registrierst du dann bei deiner Connection-Klasse einen "ConnectionTextAvailableListener" in dessen Implementierung du dann das asyncExec() reintust.

    So Zeugs hab ich zumindest recht oft gemacht. Damals. Allerdings wusste ich nie so sicher wie die "beste" Implementierung für so eine Listenerverwaltung (hab dann jeweils ArrayLists genommen - mit der trimToSize()-Methode einigermassen Speichersparsam) aussehen würde deshalb war die jedes Mal etwas anders

    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
  •