Problem mit CTabFolder und dem Setzen von TabItem Controls

Japster

Grünschnabel
Hi,

ich habe vor, ein kleines Chatprogramm mit Java und SWT zu schreiben. Dieses Programm soll es außerdem ermöglichen, mit mehreren Benutzern gleichzeitig kommunizieren zu können, dafür möchte ich jeden Chat in einem eigenen Tab darstellen (das soll dann so aussehen, wie das "Tabbed Browsing" bei Firefox).
Ich habe mir das so vorgestellt, dass ich einen CTabFolder als Grundlage nehme und für jeden Chat einen eigenen TabItem aufmache und der Inhalt soll immer der gleiche sein, nämlich ein Konversationsfenster, eine Eingabezeile und ein Senden-Button, welcher nur aktiviert werden soll, wenn auch im Textfeld tatsächlich was eingegeben wurde.
Da habe ich mir gedacht, da ich ja auf jeder Seite das gleiche haben will, schreibe ich einfach mein Chat-Fenster in eine eigene Klasse und setze diese dann als Composite auf meinen jeweiligen TabItem, aber leider funktioniert das nicht richtig und ich frage mich verzweifelt, warum... Man kann nämlich immer nur im letzten Item den Button aktivieren, bzw. eine Nachricht schicken. Hier mal mein Code:

Main.java (die Hauptklasse):
Java:
package test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

public class Main {

	static Display		display;
	static Shell		shell;
	static CTabFolder	tabFolder;
	static CTabItem		tabItem;
	static ChatPanel	chatPanel;

	private static void addTabItem(String nick) {

		tabItem = new CTabItem(tabFolder, SWT.NONE);
		tabItem.setText(nick);
		chatPanel = new ChatPanel(tabFolder);
		tabItem.setControl(chatPanel);
		tabFolder.setSelection(tabItem);

	}

	public static void main(String[] args) {

		display = new Display();
		shell = new Shell(display, SWT.SHELL_TRIM);
		shell.setText("SWT Tabbed Chat");

		shell.setLayout(new FillLayout());

		tabFolder = new CTabFolder(shell, SWT.CLOSE);
		tabFolder.setBorderVisible(true);
		tabFolder.setSimple(true);

		addTabItem("TEST");
		addTabItem("test2");

		shell.setSize(640, 480);
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		display.dispose();

	}

}

ChatPanel.java (Hier wird ein Chat-Fenster erzeugt):
Java:
package test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;

public class ChatPanel extends Composite {

	static Display		parentDisplay;
	static GridLayout	layout;
	static GridData		data;
	static Text			messages;
	static Text			input;
	static Button		send;

	public ChatPanel(Composite parent) {

		super(parent, SWT.NONE);
		parentDisplay = parent.getDisplay();

		layout = new GridLayout(2, false);
		this.setLayout(layout);

		data = new GridData(GridData.FILL_BOTH);
		data.horizontalSpan = 2;
		messages = new Text(this, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
		messages.setEditable(false);
		messages.setBackground(new Color(parentDisplay, 255, 255, 255));
		messages.setLayoutData(data);

		data = new GridData(GridData.FILL_HORIZONTAL);
		input = new Text(this, SWT.BORDER);
		input.setLayoutData(data);

		data = new GridData();
		send = new Button(this, SWT.PUSH);
		send.setText("Nachricht senden");
		send.setEnabled(false);
		send.setLayoutData(data);

		input.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {

				if (input.getText() != "") {
					send.setEnabled(true);
				} else {
					send.setEnabled(false);
				}
			}
		});

		send.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {

				addMessage("test", input.getText());

			}
		});

	}

	public static void addMessage(String nick, String message) {

		messages.append(nick + ": " + message + "\n");

	}

}

Meine Fragen sind jetzt folgende:
1.) Wie mache ich das, damit man auf jeder Seite chatten kann und nicht nur auf der letzten?
2.) Das Textfeld mit der Konversation muss auch von außen (etwa von einem Netzwerk-Thread, der auf ankommende Nachrichten wartet) beschreibbar sein, deshalb ist die Methode "addMessage" auch public static, nur wie kann ich von außen unterscheiden, in welchen Tab ich schreiben soll?

Ich hoffe, mein (wahrscheinlich recht simples) Problem ist einigermaßen verständlich, ich habe zwar schon etwas Erfahrung mit Java-Programmierung, bin aber erst am Anfang bei SWT, da ich bisher nur mit der Console gearbeitet habe und nicht mit einer GUI. Ich danke in Voraus für eure Hilfe!

Grüße, Japster
 
Zuletzt bearbeitet:
Hey,

Ich finde die Idee für jedes Chat-Panel ein Composite zu erzeugen nicht schlecht, jedoch wäre es einfacher für jedes Chat-Panel
ein eigenes CTabItem zu erstellen und dann dieses nur noch zum CTabFolder hinzuzufügen...

Freundliche Grüsse
CKingZesi
 
Hi,

danke für deine Antwort! Ich habe den Code in der ChatPanel.java jetzt so umgeschrieben, dass die Klasse direkt einen CTabItem repräsentiert, welchen ich nun in der Hauptklasse auf den CTabFolder setze. Leider ist das Problem dadurch nicht gelöst, auch so funktionieren die Listener nur auf der letzten Seite... :(
Übrigens brauche ich das Composite so oder so, weil ich nur ein fertiges Control auf einen CTabItem setzen kann und kein Layout mit Steuerelementen (das geht nur beim CTabFolder selbst und bringt mir dort nix).

Hier mal mein neuer Code:

ChatPanel.java:
Java:
package test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;

public class ChatPanel extends CTabItem {

	static Display		parentDisplay;
	static Composite	composite;
	static GridLayout	layout;
	static GridData		data;
	static Text			messages;
	static Text			input;
	static Button		send;

	public ChatPanel(CTabFolder parent) {

		super(parent, SWT.NONE);
		parentDisplay = parent.getDisplay();

		composite = new Composite(parent, SWT.NONE);

		layout = new GridLayout(2, false);
		composite.setLayout(layout);

		data = new GridData(GridData.FILL_BOTH);
		data.horizontalSpan = 2;
		messages = new Text(composite, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
		messages.setEditable(false);
		messages.setBackground(new Color(parentDisplay, 255, 255, 255));
		messages.setLayoutData(data);

		data = new GridData(GridData.FILL_HORIZONTAL);
		input = new Text(composite, SWT.BORDER);
		input.setLayoutData(data);

		data = new GridData();
		send = new Button(composite, SWT.PUSH);
		send.setText("Nachricht senden");
		send.setEnabled(false);
		send.setLayoutData(data);

		input.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {

				if (input.getText() != "") {
					send.setEnabled(true);
				} else {
					send.setEnabled(false);
				}
			}
		});

		send.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {

				addMessage("test", input.getText());

			}
		});

		this.setControl(composite);

	}

	public static void addMessage(String nick, String message) {

		messages.append(nick + ": " + message + "\n");

	}

}

Die Methode zum Setzen des Tabs sieht jetzt so aus:
Java:
	private static void addTabItem(String nick) {

		chatPanel = new ChatPanel(tabFolder);
		chatPanel.setText(nick);
		tabFolder.setSelection(chatPanel);

	}

Die Sache scheint wohl doch verzwickter zu sein, als auf den ersten Blick angenommen...

Grüße, Japster
 
Hey,

Ich finde den Code so jetzt brauchbarer. Also der Fehler liegt irgendwo bei den statischen Methoden und/oder Variablen. Ich habe deinen Code ein wenig umgeschrieben und jetzt funktioniert das Ganze.
Ich habe noch etwas eingefügt: Nach dem Senden der Nachricht wird das Input-Feld gelöscht und der Button wieder auf Disabled gesetzt, bis eine neue Nachricht eingegeben wird.

Hier der Code:
Main.java
Code:
package test;

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

public class Main
{

  public static void main(String[] args)
  {

    Display display = new Display();
    Shell shell = new Shell(display, SWT.SHELL_TRIM);
    shell.setText("SWT Tabbed Chat");
    shell.setLayout(new FillLayout());

    MainWindow mainWindow = new MainWindow(shell);
    mainWindow.addTabItem("TEST");
    mainWindow.addTabItem("test2");

    shell.setSize(640, 480);
    shell.open();
    while(!shell.isDisposed())
    {
      if(!display.readAndDispatch()) display.sleep();
    }
    display.dispose();

  }

}

MainWindow.java
Code:
package test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.widgets.Shell;

public class MainWindow
{

  private Shell shell;
  private CTabFolder cTabFolder;

  public MainWindow(Shell shell)
  {

    this.shell = shell;
    this.createContents();

  }

  private void createContents()
  {

    cTabFolder = new CTabFolder(shell, SWT.CLOSE);
    cTabFolder.setBorderVisible(true);
    cTabFolder.setSimple(true);

  }

  public void addTabItem(String nick)
  {

    ChatPanel chatPanel = new ChatPanel(cTabFolder);
    chatPanel.setText(nick);
    cTabFolder.setSelection(chatPanel);

  }

}

ChatPanel.java
Code:
package test;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;

public class ChatPanel extends CTabItem
{

  private Display    parentDisplay;
  private Composite  composite;
  private GridLayout layout;
  private GridData   data;
  private Text       messages;
  private Text       input;
  private Button     send;

  public ChatPanel(CTabFolder parent)
  {

    super(parent, SWT.NONE);
    parentDisplay = parent.getDisplay();

    composite = new Composite(parent, SWT.NONE);

    layout = new GridLayout(2, false);
    composite.setLayout(layout);

    data = new GridData(GridData.FILL_BOTH);
    data.horizontalSpan = 2;
    messages = new Text(composite, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI);
    messages.setEditable(false);
    messages.setBackground(new Color(parentDisplay, 255, 255, 255));
    messages.setLayoutData(data);

    data = new GridData(GridData.FILL_HORIZONTAL);
    input = new Text(composite, SWT.BORDER);
    input.setLayoutData(data);

    data = new GridData();
    send = new Button(composite, SWT.PUSH);
    send.setText("Nachricht senden");
    send.setEnabled(false);
    send.setLayoutData(data);

    input.addModifyListener(new ModifyListener()
    {

      public void modifyText(ModifyEvent e)
      {

        if (input.getText() != "") send.setEnabled(true);
        else                       send.setEnabled(false);

      }

    });

    send.addSelectionListener(new SelectionAdapter()
    {

      public void widgetSelected(SelectionEvent e)
      {

        addMessage("test", input.getText());
        input.setText("");
        send.setEnabled(false);

      }

    });

    this.setControl(composite);

  }

  public void addMessage(String nick, String message)
  {

    messages.append(nick + ": " + message + "\n");

  }

}

Freundliche Grüsse
CKingZesi
 
Hi,

vielen Dank, jetzt funktioniert es!
Du hast Recht, es lag tatsächlich an den statischen Variablen in der ChatPanel.java, bei denen die Listener nur in der letzten Instanz griffen, jetzt gehen sie auf jeder Seite.

Meine 2.te Frage konnte ich inzwischen selbst beantworten: Nachdem ich mir das so gedacht habe, dass jeder Nick nur 1-Mal verwendet werden kann, vergleiche ich einfach den Nick in der eingehenden Nachricht mit dem Text auf den CTabItems. Wenn es eine Übereinstimmung gibt, wird die Nachricht in den entsprechenden Tab geschrieben, ansonsten wird ein neuer aufgemacht. Ist eine simple If-Abfrage, ich glaube, den Code dazu muss ich jetzt nicht extra anfügen :)

Problem gelöst, nochmal vielen Dank an CKingZesi!

Grüße, Japster
 
Zurück