IndexOutOfBoundsException bei neuen Daten in JTable

Ollek

Bekanntes Mitglied
Hallo,

ich erhalte wie im Titel des Themas beschrieben eine IndexOutOfBoundsException, wenn ich neue Daten in eine JTable lade.

Folgende Anwendung:

Es ist eine Server/Client Anwendung.
Die Anwendung dient zum verwalten von so genannten Jobs.
Aktuell besteht das Problem beim löschen eines Jobs. Vom Client wird ein Command an den Server geschickt, der das löschen dieses Jobs veranlasst. Der Server gibt einen Command an alleine mit dem Server verbundenen Clients zurück, dass die ihre JobListe, diese wird in der JTable dargestellt, neuladen.

Und genau bei diesem neuladen tritt die o.g. Fehlermeldung auf.
Ich weiß nicht, wo ich den Bug habe, werde hier die passenden relevanten Klassen posten. Ich verzweifle an diesem Problem, bin seit vorgestern morgen dran und komme nicht weiter.. Viele SystemOuts gemacht, aber der Fehler tritt immer und immer wieder auf.

Meine Vermutung ist, dass der Ordner vom Server nocht nicht gelöscht ist, wenn der Client die liste neu zeichnen soll. Aber das ist nur eien Vermutung.. Aber eigentlich sollte der Server doch erst die Message an den Client senden, wenn dieser Job auch wirklich gelöscht ist. Vielleicht habe ich dort auch den Fehler gemacht. Ist meine erste Server/Client Anwendung.
habt Nachsicht, wenn der Code nicht gut ist.. ;(

Folgende Fehlermeldung
Java:
Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Invalid index
	at javax.swing.DefaultRowSorter.convertRowIndexToModel(Unknown Source)
	at javax.swing.JTable.convertRowIndexToModel(Unknown Source)
	at javax.swing.JTable.getValueAt(Unknown Source)
	at javax.swing.JTable.prepareRenderer(Unknown Source)
	at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
	at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
	at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
	at javax.swing.plaf.ComponentUI.update(Unknown Source)
	at javax.swing.JComponent.paintComponent(Unknown Source)
	at javax.swing.JComponent.paint(Unknown Source)
	at javax.swing.JComponent.paintToOffscreen(Unknown Source)
	at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
	at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
	at javax.swing.RepaintManager.paint(Unknown Source)
	at javax.swing.JComponent._paintImmediately(Unknown Source)
	at javax.swing.JComponent.paintImmediately(Unknown Source)
	at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
	at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
	at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
	at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
	at java.awt.event.InvocationEvent.dispatch(Unknown Source)
	at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
	at java.awt.EventQueue.access$000(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.awt.EventQueue$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

ServerSocket
Java:
package de.ernsting.network;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Hashtable;

import org.apache.log4j.Level;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.StdSchedulerFactory;

import de.ernsting.command.JobCommand;
import de.ernsting.util.Config;
import de.ernsting.util.Log4JLogger;

public class Server {

	private Config config = Config.getInstance();
	private Log4JLogger logger = Log4JLogger.getInstance();
	private Hashtable outputStreams = new Hashtable();
	private ServerSocket serverSocket;
	private Scheduler sched;
	
	public void listen(){
		try {
			serverSocket = new ServerSocket(Integer.parseInt(config.getProperty("network.socket.port")));
			System.out.println("Server gestartet auf " + serverSocket.getInetAddress().getHostAddress()  + ":" + serverSocket.getLocalPort());
			
			String timeout = config.getProperty("network.socket.timeout");
	       
			if(!timeout.equalsIgnoreCase("never")) {
	        	  serverSocket.setSoTimeout(Integer.parseInt(timeout));
	        }
			
	        while(true){
	        	Socket socket = serverSocket.accept();
	        	System.out.println("Verbunden mit " + socket.getInetAddress().getHostAddress());
	        	
	        	ObjectOutputStream oOut = new ObjectOutputStream(socket.getOutputStream());
	        	outputStreams.put(socket, oOut);
	        	
	        	new ServerThread(this, socket);
	        }
		} catch (NumberFormatException e) {
			logger.log(Level.ERROR, this.getClass(), "Servern konnte nicht auf dem Port gestartet werden...", e);
			System.exit(1);
		} catch (IOException e) {
			logger.log(Level.ERROR, this.getClass(), "ServerSocket konnte nicht gestartet werden. da er schon läuft", e);
			System.exit(1);
		}
		try {
			serverSocket.close();
		} catch (IOException e) {
			logger.log(Level.ERROR, this.getClass(), "ServerSocket konnte nicht geschlossen werden.", e);
			System.exit(1);
		}
	}

	/**
	 * Gibt die Outputstreams als
	 * Enumeration zurück
	 * 
	 * @return
	 */
	public Enumeration getOutputstreams(){
		return outputStreams.elements();
	}

	/**
	 * Sendet das übergebene Objekt an alle
	 * verbundenen Clients
	 * 
	 * @param object
	 */
	public void sendToAll(JobCommand command){
		synchronized (outputStreams) {
			for(Enumeration e = getOutputstreams(); e.hasMoreElements();){
				ObjectOutputStream oos = (ObjectOutputStream) e.nextElement();
				try {
					oos.writeObject(command);
					oos.flush();
				} catch (IOException ex) {
					logger.log(Level.ERROR, this.getClass(), "Probleme beim Senden des Jobs an die Clients", ex);
				}
			}
		}
	}
	

	/**
	 * Socketverbindung wird getrennt
	 * 
	 * @param socket - zu trennendes Socket
	 */
	public void removeConnection(ServerThread socket) {
		outputStreams.remove(socket);
		synchronized (outputStreams) {
			System.out.println("Trenne Verbindung zum Client " + socket.getSocket().getInetAddress());
			try {
				
				socket.close();
				logger.log(Level.INFO, this.getClass(), "Der ServerThread wurde erfolgreich beendet.");
			} catch (IOException e) {
				logger.log(Level.ERROR, this.getClass(), "Konnte die Verbindung zum Client-Socket nicht schließen", e);
			}
		}
		
	}
	
}

ServerThread
Java:
package de.ernsting.network;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

import org.apache.log4j.Level;
import org.ietf.jgss.Oid;

import de.ernsting.command.JobCommand;
import de.ernsting.fileaccess.FileIO;
import de.ernsting.upload.Upload;
import de.ernsting.util.Log4JLogger;

public class ServerThread extends Thread {
	
	private Log4JLogger logger = Log4JLogger.getInstance();
	private Socket socket;
	private Server server;
	private FileIO fileIO;
	private ObjectInputStream oIn;
	
	public ServerThread(Server server, Socket socket){
		this.socket = socket;
		this.server = server;
	
		// Thread starten
		start();
	}

	@Override
	public void run() {
		fileIO = new FileIO();
		try {
			oIn  = new ObjectInputStream(this.socket.getInputStream());
			while(true){
				JobCommand commandFromClient = (JobCommand) oIn.readObject();
				JobCommand commandToClient = new JobCommand();
				
				if(commandFromClient != null){
					boolean result = false;
//						if( commandFromClient.getMessage().equals("upload") && commandFromClient.getJob() != null){
//							System.out.println("ServerThread.run() - UPLOAD");
//							Upload upload = new Upload();
//							boolean result = upload.upload(commandFromClient.getJob());
//							if(result){
//								commandToClient.setMessage("reload");
//							}
						if( commandFromClient.getMessage().equals("delete") && commandFromClient.getJob() != null){
							System.out.println("ServerThread.run() - DELETE");
							result = fileIO.deleteDirectory(commandFromClient.getJob().getSourceDirectory());
							commandToClient.setMessage("reload");
							System.out.println("LÖSCHRESULT: " + result);
							logger.log(Level.INFO, this.getClass(), commandFromClient.getJob().getName() + " wurde erfolgreich gelöscht!");
						} else if( commandFromClient.getMessage().equals("reload")){
							System.out.println("ServerThread.run() - RELOAD");
							commandToClient.setMessage("reload");
						}
						if(result){
							logger.log(Level.INFO, this.getClass(), "MESSAGE to Clients");
							server.sendToAll(commandToClient);
						}
				}
			}
		} catch (IOException e) {			
			logger.log(Level.ERROR, this.getClass(), "Der Job wurde nicht verarbeitet", e);
		} catch (ClassNotFoundException e) {
			 logger.log(Level.ERROR, this.getClass(), "Die Klasse des Commands wurde nicht gefunden", e);
		}finally {
			server.removeConnection(this);
		}
	}
	
	public void close() throws IOException{
		oIn.close();
		socket.close();
	}
	
	private JobCommand getDataFromClient( ObjectInputStream oIn ) throws IOException {
        JobCommand  commandFromClient = null;         
        while ( commandFromClient == null ){
           try {
              commandFromClient = (JobCommand) oIn.readObject();
           } catch ( ClassNotFoundException e ) {
        	   logger.log(Level.ERROR, this.getClass(), "Konnte den Command nicht finden", e);
           }
        }
        System.out.println( "Get: " + commandFromClient.getMessage() );
     return commandFromClient;
    } 
	
	public Socket getSocket() {
		return socket;
	}
}

ClientSocket
Java:
public class Client implements Runnable{

	private Config config = Config.getInstance();
	private Log4JLogger logger = Log4JLogger.getInstance();
	private Socket clientSocket;
	private ObjectOutputStream oOut;
	private ObjectInputStream oIn;
	private JobController controller;
	
	public Client(JobController controller){
		this.controller = controller;
		connect();
	}
	
	/**
	 * Verbindet das Socket mit dem 
	 * ServerSocket
	 */
	public void connect(){
		try {
			clientSocket = new Socket(config.getSocketHost(), config.getServerPort());
			oOut = new ObjectOutputStream(clientSocket.getOutputStream());
			oIn = new ObjectInputStream(clientSocket.getInputStream());
			
			controller.setFrametitle(clientSocket.getInetAddress().getHostAddress());
			
			new Thread(this).start();
		} catch (UnknownHostException e) {
			logger.log(Level.ERROR, this.getClass(), "Host konnte nicht gefunden werden.", e);
			e.printStackTrace();
		} catch (IOException e) {
			logger.log(Level.ERROR, this.getClass(), "Konnte nicht mit dem Host verbunden werden.", e);
		}
	}
	
	/**
	 * Schickt einen Command an den Server
	 * 
	 * @param job
	 */
	public void sendCommandToServer(JobCommand commandToServer){
		if(clientSocket.isConnected()){
			try {
			System.out.println("Client.processJob()");
				oOut.writeObject(commandToServer);
				oOut.flush();
			} catch (IOException e) {
				logger.log(Level.ERROR, this.getClass(), "Job konnte nicht an den Server geschickt werden", e);
			}
		}
	}

		
	/**
	 * Schließ die Input- und OutputStream 
	 * und die Verbindung zum Socket
	 */
	public void close(){
		try {
			oOut.close();
			oIn.close();
			clientSocket.close();
		} catch (IOException e) {
			logger.log(Level.ERROR, this.getClass(), "Probleme beim Schließen der Verbindung zum Server", e);
		}
	}
	
	/**
	 * Thread um Sendungen vom Server
	 * anzunehmen und abzuarbeiten
	 */
	public void run(){
		while(true){
			System.out.println("Client.run() - while()");
			try {
				JobCommand commandFromServer = (JobCommand) oIn.readObject();
				
				if(commandFromServer.getMessage().equals("reload")){
					logger.log(Level.INFO, this.getClass(), "Client.run() - RELOAD");
					controller.updateJobList();
				}
			} catch (IOException e) {
				logger.log(Level.ERROR, this.getClass(), "Der Job konnte nicht verarbeitet werden.", e);
			} catch (ClassNotFoundException e) {
				logger.log(Level.ERROR, this.getClass(), "Der Job konnte nicht verarbeitet werden.", e);
			}
			
		}
	}
}

JobController - habe hier nur die relevanten Methoden stehen lassen
Java:
public class JobController {
	
	private JMain view;
	private JobService service;
	private FileIO fileIO;
	private Config config = Config.getInstance();
	private Log4JLogger logger = Log4JLogger.getInstance();
	private Client socket;
	
	public JobController(){
		this.view = new JMain();
    	this.service = JobService.getInstance();
		this.fileIO = new FileIO();
		
    	view.getTable().getModel().setJobList(service.listJobs());
    	view.getTblJobDelete().getModel().updateJobList(service.listJobsToDelete());
    	
		addListener();
		
		socket = new Client(this);
	}
	
	public void addListener(){
		view.getBtnBar().setUploadStartListener(new UploadStartListener());
		view.getBtnBar().setCreateFolderListener(new CreateFolderListener());
		view.getBtnBar().setRefreshListener(new RefreshListener());
		view.getBtnBar().setDeleteListener(new DeleteFolderListener());
	}
		
	private class DeleteFolderListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			ArrayList<Job> selectedJobs = view.getTable().getModel().getSelectedJobs();
			for (Job job : selectedJobs) {			
				socket.sendCommandToServer(getCommandToServer("delete", job));				
			}
//			updateJobList();
		}
	}


	/**
	 * Liest die Jobs neu ein
	 */
	public void updateJobList(){
		System.out.println("JobController.updateJobList()");
		view.getTable().getModel().updateJobList(service.listJobs());
	}

	private JobCommand getCommandToServer(String command, Job job){
		JobCommand commandToServer = new JobCommand();
		commandToServer.setMessage(command);
		commandToServer.setJob(job);
		return commandToServer;
	}

JTableModel
Java:
public class JobTableModel extends AbstractTableModel {
	
	//Columns Number.
    public static final int    JOB_SEL_COL = 0;                                   
    public static final int    JOB_NAME_COL = 1;
    public static final int    JOB_SOURCE_COL = 2;
    public static final int    JOB_FOLDERS_COL = 3;
    public static final int    JOB_DATE_COL = 4;
	
    private String[] columnNames = new String[]{"Upload", "Job Name", "Verzeichnis", "Unterordner", "Datum" };
	private ArrayList<Job> jobList;
	private ArrayList<Job> jobListSeleted;
	
	public JobTableModel(){
		super(); 
		this.jobList = new ArrayList<Job>();
		this.jobListSeleted = new ArrayList<Job>();
		this.addTableModelListener(new TableModelListener() {
			
			@Override
			public void tableChanged(TableModelEvent e) {
				int column = e.getColumn();
				int row = e.getFirstRow();
				//aktuellen Job holen
				Job job = (Job) getValueAt(row);
				if(job.isUpload())
					jobListSeleted.add(job);
				else
					jobListSeleted.remove(job);
			}
		});
	}
	
	
	@Override
	public int getColumnCount() {
		return columnNames.length;
	}

	@Override
	public int getRowCount() {
		return jobList.size();
	}
	
	/**
	 * Aktualisiert die Daten im TableModel
	 * nachdem diese in der Tabelle geändert 
	 * wurden
	 */
	public void setValueAt(Object value, int row, int col){
		
		Job job = jobList.get(row);	
		
		switch(col){
		case JOB_SEL_COL: job.setUpload((Boolean)value); break;
		case JOB_NAME_COL: job.setName((String)value); break;
		case JOB_SOURCE_COL: job.getSourceDirectory(); break;
		case JOB_FOLDERS_COL: value.toString(); break;
		case JOB_DATE_COL: job.setDate((String)value); break;
		}
		fireTableCellUpdated(row, col);
	}

	/**
	 * Gibt den Wert, welcher sich in den 
	 * übergebenen Parametern befindet zurück
	 * 
	 */
	@Override
	public Object getValueAt(int row, int column) {
		Job job = jobList.get(row);
		
		String folders = "";
		if(job.getSourceFolders().length > 0){
			for (File folder : job.getSourceFolders()) {
				if(folders.isEmpty())
					folders += folder.getName();
				else
					folders += "\n" + folder.getName();
			}
		}
		
		switch(column){
		case JOB_SEL_COL: return job.isUpload();
		case JOB_NAME_COL: return job.getName();
		case JOB_SOURCE_COL: return job.getSourceDirectory();
		case JOB_FOLDERS_COL: return folders;
		case JOB_DATE_COL: return job.getDate();
		default: return new Object();
		}
	}
	
	/**
	 * Gibt das Object zurück, was sich
	 * in der übergebenen Zeile befindet
	 * zurück
	 * 
	 * @param row
	 * @return
	 */
	public Object getValueAt(int row){
		return jobList.get(row);
	}
	
	public String getColumnName(int iColumn){
		return columnNames[iColumn];
	}
	
	// passendes Format in der Spalte wird angezeigt
	public Class getColumnClass(int columnIndex){
		switch(columnIndex){
			case 0: 	return Boolean.class;
			default: 	return String.class;
		}
	}
	
	public boolean isCellEditable(int row, int col) {
        //Note that the data/cell address is constant,
        //no matter where the cell appears onscreen.
        return col == 0;
    }
	
	public ArrayList<Job> getSelectedJobs() {
		System.out.println("JobTableModel.getSelectedJobs() " + jobListSeleted.size());
		return jobListSeleted;
	}

	public void setSelectedJobs(ArrayList<Job> arrlSelectedJobs) {
		this.jobListSeleted = arrlSelectedJobs;
	}
	
	public ArrayList<Job> getJobList() {
		return jobList;
	}

	public void setJobList(ArrayList<Job> jobList){
		this.jobList = jobList;
	}

	public void updateJobList(ArrayList<Job> jobList) {
		this.jobList.clear();
		this.jobListSeleted.clear();
		if(!jobList.isEmpty()){
			this.jobList = jobList;
			this.fireTableDataChanged();
		} else if(jobList.size() > 0){
			this.fireTableDataChanged();
		}
	}
	
}

JTable
Java:
public class JobTable extends JTable {
	
	private JobTableModel model;
	private Config config = Config.getInstance();
	private FileIO fileIO = new FileIO();
	
	
	public JobTable(){
		init();
	}

	private void init() {
		model = new JobTableModel();			

		this.setModel(model);
		this.setAutoCreateRowSorter(true);
		this.setSurrendersFocusOnKeystroke(true);
		this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);	
			
		// Setzen der passenden Ausrichtung innerhalb der Zelle
		this.setDefaultRenderer(Object.class, new DefaultTableCellRenderer()
		{
			public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
			{
				/* Sollten die Spalten durch den User neu sortiert sein,
				 * dann haben die spalten einen neuen Index. Man benötigt den Modelindex
				 */
				final int modelColumn = table.convertColumnIndexToModel(column);
				switch (modelColumn)
				{
						/* alignment left setzen */
					default :
						setVerticalAlignment(JLabel.TOP);
				}
				return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
			}
		});
		
		// Tabellen Header Einstellungen - aktuellen holen, von der JTable um damit abreiten zu können
		JTableHeader tblHeader = this.getTableHeader();
		tblHeader.setResizingAllowed(false);
		tblHeader.setReorderingAllowed(false);
				
		// Spaltenbreite setzen
		this.getColumnModel().getColumn(0).setMaxWidth(43);
		this.getColumnModel().getColumn(1).setMinWidth(120);
		this.getColumnModel().getColumn(2).setMinWidth(380);
		this.getColumnModel().getColumn(3).setMinWidth(100);
		this.getColumnModel().getColumn(4).setMinWidth(20);
		
		
		TableColumn column = this.getColumnModel().getColumn(3);
		column.setCellRenderer(new TwoLinesCellRenderer());
			
	}
	

	
	public JobTableModel getModel(){
		return model;
	}
	

	/**
	 * Renderer für eine mehrzeilige Zellen.
	 * 
	 * @author leifken
	 *
	 */
	private class TwoLinesCellRenderer extends JTextArea implements TableCellRenderer {

		@Override
		public Component getTableCellRendererComponent(JTable table,
				Object value, boolean isSelected, boolean hasFocus, int row,
				int column) {
			
			if (isSelected){		    	
	      		setForeground(table.getSelectionForeground());
	      		setBackground(table.getSelectionBackground());
		    }	 
	    	else{
	      		setForeground(table.getForeground());
	      		setBackground(table.getBackground());
	    	} 
			
			setFont(table.getFont());
			setText(value.toString());
			
			// Passt die Zellenhöhe nur an, wenn die aktuelle ungleich der TA ist und die Tabelle Daten hat
			if (table.getRowHeight() != (int) this.getMinimumSize().height && table.getModel().getRowCount() > 0){ 
				table.setRowHeight(row, (int) this.getMinimumSize().height);
			}
			
			return this;
		}
	}
}

Wenn noch andere Dinge am Code auffallen, ich bin für jeden Ratschlag dankbar...

Hoffe ich kann das Problem mit eurer Hilfe nun endlich beenden.. :rtfm:

Viele Grüße
 

fastjack

Top Contributor
Du hast überall "Unknown source", führ das mal mit einem JDK aus und kompilere mit (debug=on). Gibt es keine Cause-Exception, oder mehr Exceptions? Debug mal die Methoden getValueAt und checke die row-Angabe. Dadurch das das Model eine getJobList-Methode hat, wird da vielleicht etwas nebenläufig angefügt oder entfernt? Das bekommt dann dein Model nämlich nicht mit.

Code:
        this.jobList.clear();
        this.jobListSeleted.clear();
        if(!jobList.isEmpty()){
            this.jobList = jobList;
            this.fireTableDataChanged();
        } else if(jobList.size() > 0){
            this.fireTableDataChanged();
        }

würde ich lieber so machen:

Code:
        this.jobList.clear();
        this.jobListSeleted.clear();
        if(!jobList.isEmpty()){
            this.jobList.addAll(jobList);
        }
        this.fireTableDataChanged();

this.jobList und jobList in einer Methode kann unübersichtlich werden, nenn den Parameter lieber newJobList oder so...
 

Ollek

Bekanntes Mitglied
Das hat leider nicht geholfen..

Deine Codeverbesserungen hab ich umgesetzt..

Sonst noch jemand eventuell eine Idee? ???:L
 
S

SlaterB

Gast
updateJobList() wird von einem zur GUI parallelen Thread aufgerufen,
während die GUI potentiell irgendwas macht, z.B. erst eine Anzahl Zeilen abfragen und dann die Zeilen durchläuft,
werden die GUI-Daten geändert -> Exception

GUI-Daten dürfen nur vom AWT-Thread geändert werden, erreichbar mit Ablegen dieser Kommandos in
SwingUtilies.invokeLater(Runnable)

die gesamte Berechnung mit Server-Anfrage besser nicht, denn solange ist die GUI blockiert,
nur wenn die Ergebnisse fertig formatiert und in neuen Listen abgefüllt sind oder was immer nötig,
dann den hoffentlich kurzen Moment der Verlinkung im TableModel durch invokeLater() ausführen lassen


Threading with Swing: SwingUtilities.invokeLater
 

Ollek

Bekanntes Mitglied
Danke.

Also wenn ich das ganze richtig verstanden habe, soll ich bei jeder Aktion, die durch einen Button ausgelöst wird und die Anzeige in irgendeiner Art verändert, diese mit SwingUtilities.invokeLater ( new Runnable(){} ausführen?

Meine Awendung wird ebenfalls schon dadurch gestartet.
 
S

SlaterB

Gast
Buttons werden standardmäßig eh vom GUI-Thread ausgeführt, da ist das im Grundmodus nicht nötig,
wenn von Button aus lange Aktionen ausgeführt werden, blockiert die GUI solange,
deswegen parallele Threads,
in deinem Fall scheint es um den generell laufenden Client-Thread zu gehen,

für parallele Threads wird invokeLater dann interessant,
und wie schon gesagt: wenn invokeLater, dann möglichst kurze Abschnitte, nicht die Server-Anfrage

die main-Methode ist übrigens auch so ein paralleler Thread, deswegen ist das schon ganz schlau,
aber dort am Anfang geht es glaube ich nicht primär um Datenänderungen
 

Ollek

Bekanntes Mitglied
Die Serveranfrage läuft schon in einem eigenen Thread.

Aber ich rufe in der Aktion vom Button eine Methode des Clients auf bzw. übergebe den zu löschenden Job.

Daran kann es aber nicht liegen, oder?
 
S

SlaterB

Gast
meines Wissens gehts um updateJobList(), welches ich in Client.run() sehe,
meinst du DeleteFolderListener? dort ist es doch auskommentiert,

durch Logging kannst du herausfinden welches updateJobList() Probleme macht, falls du nicht schon den Durchblick hast


> Die Serveranfrage läuft schon in einem eigenen Thread.
+
> Aber ich rufe in der Aktion vom Button eine Methode des Clients auf bzw. übergebe den zu löschenden Job.

ist mir zu ungenau, da schaue ich jetzt nicht nach, welche Codestellen meinst du denn genau, welche Abläufe gibt es?
wenn Listener X einen Thread Y Bescheid sagt und Y dann was macht, ist das genau so zu behandeln als ob Thread Y was macht, denn es ist ja Thread Y der was macht ;)
wer wann vor Urzeiten einen Befehl dazu gegeben hat, scheint aus meiner Sicht wenig relevant, falls das deine Frage ist
 

Ollek

Bekanntes Mitglied
Wenn ich da ein fireTableDataChange setze und die ArrayList ist leer, wird ebenfalls eine Exception geschmissen.

@SlaterB

Also in dem Client wird über den Controller nur die Methode zum Updaten der Liste aufgerufen.
Das ist doch richtig, oder sehe ich das falsch?
Der Client hat keine eigene Methode zum Updaten.
 
S

SlaterB

Gast
> Das ist doch richtig, oder sehe ich das falsch?
wie kannst du bei einer trivialen Aussage sowas nachfragen, natürlich ist es richtig dass 'über den Controller die Methode zum Updaten der Liste aufgerufen wird'
interessanter sind die Wörter 'nur' + 'doch', was implizierst du damit, worin siehst du einen Widerspruch, schreibe doch deine Gedanken lang und ausführlich hin

zusammen mit
> Der Client hat keine eigene Methode zum Updaten.
ist die einzige Spekulation, die mir einfällt, die, dass es deiner Meinung nach eine Rolle spielen würde, wo der Code steht,
'der Thread ruft die Methode nur auf, der Methodencode steht aber im TableModel bzw. der Controller ist auch noch dazwischen, daher ...'
wie die ... weitergehen sollten weiß ich aber wiederum nicht,

jeder Code, egal wo er steht, wird von einem Thread ausgeführt,
meine Vermutung ist, dass updateJobList() von einem Thread deines Programms ausgeführt wird,
damit parallel/ nebenläufig/ gleichzeitig zum AWT-Thread läuft, der auf die Daten für irgendwelche Zwecke zugreift und nicht mit willkürlichen Änderungen zwischendurch (etwa zwischen Anfang und Ende eines paint-Vorgangs) rechnet,
ergo Exception halbwegs verständlich
 

bERt0r

Top Contributor
Java:
this.addTableModelListener(new TableModelListener() {
            
            @Override
            public void tableChanged(TableModelEvent e) {
                int column = e.getColumn();
                int row = e.getFirstRow();
                //aktuellen Job holen
                Job job = (Job) getValueAt(row);
                if(job.isUpload())
                    jobListSeleted.add(job);
                else
                    jobListSeleted.remove(job);
            }
        });
Du kannst in einem TableModelListener nicht einfach direkt auf die ModelDaten zugreifen und da Werte löschen. Nach jeder änderung am Model muss eine passende fire Methode ausgeführt werden um die Listener zu benachrichtigen. Listener sind nicht nur dein selbstgebauter, sonder auch der JTable und sein Rowsorter, der dir deine Exception wirft.
Wenn du von deinem Listener aus etwas löschen möchtest, musst du eine Methode wie removeRow benutzen.
 
S

SlaterB

Gast
hab nicht alle Verwendungen nachgeschaut, aber direkt im Model scheint ja jobList die Hauptdatenmenge zu sein, die wird nicht verändert,
jobListSeleted ist was anderes
 

bERt0r

Top Contributor
Stimmt, aber das verstößt einfach gegen das Model Prinzip.
Die Direktzuweisung der neuen Arralist ist auch nicht gut:
Java:
    public void updateJobList(ArrayList<Job> jobList) {
        this.jobList.clear();
        this.jobListSeleted.clear();
        if(!jobList.isEmpty()){
            this.jobList = jobList;
            this.fireTableDataChanged();
        } else if(jobList.size() > 0){
            this.fireTableDataChanged();
        }
    }
Was soll das ganze überhaupt. Wieso clear(), wieso Abfrage auf isEmpty()? Und wenn dein service, den du nicht gepostet hast, von dem die joblist jetzt ein clear auf seine ArrayList macht, betrifft das auch die vom Table und die Exception fliegt. Folgendes sollte doch ausreichen:

Java:
public void updateJobList(ArrayList<Job> jobList) {
        this.jobListSeleted.clear();
       this.joblist=joblist.clone();
this.fireTableDataChanged();}
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
D java.lang.IndexOutOfBoundsException: AWT, Swing, JavaFX & SWT 18
G JavaFX ChoiceBox selectFirst IndexOutOfBoundsException AWT, Swing, JavaFX & SWT 7
A JTable und java.lang.IndexOutOfBoundsException AWT, Swing, JavaFX & SWT 3
L FreeChart java.lang.IndexOutOfBoundsException AWT, Swing, JavaFX & SWT 4
E Swing TableModel fireTableDataChanged führt zu IndexOutOfBoundsException AWT, Swing, JavaFX & SWT 9
Developer_X Swing IndexOutOfBoundsException, aber warum?! AWT, Swing, JavaFX & SWT 15
A Nach klick auf Button neuen Inhalt im gleichen Fenster AWT, Swing, JavaFX & SWT 3
J Swing Neuen Command für "show"? AWT, Swing, JavaFX & SWT 2
C Swing JList zeigt keine neuen Einträge an AWT, Swing, JavaFX & SWT 1
F neuen Menüpunkt in jcombobox einfügen AWT, Swing, JavaFX & SWT 1
Z AWT JLabel setzt kein neuen Text AWT, Swing, JavaFX & SWT 6
O Neuen JFrame öffnen und alten schließen AWT, Swing, JavaFX & SWT 7
W Bei Button-klick neuen button in array hinzufügen AWT, Swing, JavaFX & SWT 7
H Swing Probleme beim erstellen eines neuen Objektes durch einen Button AWT, Swing, JavaFX & SWT 10
F JTabbedPane mit Button zum Hinzufügen eines neuen Tabs AWT, Swing, JavaFX & SWT 6
R SWT TreeViewer neuen Input setzen AWT, Swing, JavaFX & SWT 3
T JTabbedPane - neuen Tab zwischen zwei anderen Tabs hinzufügen AWT, Swing, JavaFX & SWT 2
M PropertyChangeListener - JTable bei neuen Objekten updaten? AWT, Swing, JavaFX & SWT 3
D Swing FileChooser mit einem neuen Rootordner AWT, Swing, JavaFX & SWT 6
D Aufruf neuer Klasse ohne Erzeugung eines neuen Fensters AWT, Swing, JavaFX & SWT 3
E Applet Neuen Tab aus Applet öffnen AWT, Swing, JavaFX & SWT 3
Ollek Realisierung: JTable zur Laufzeit mit neuen Daten füllen AWT, Swing, JavaFX & SWT 3
T Neuen JInternalFrame von JLabel "herunterziehen" AWT, Swing, JavaFX & SWT 6
O Swing es können keine neuen Labels hinzufügt werden während der Timer läuft AWT, Swing, JavaFX & SWT 14
N Neuen Kunden anlegen AWT, Swing, JavaFX & SWT 26
R SWT Statusmeldung im neuen Fenster blockiert aufrufendes Fenster AWT, Swing, JavaFX & SWT 2
G JFile Chooser "Buttons" wie Neuen Ordner erstellen AWT, Swing, JavaFX & SWT 3
S BufferedImage & Scaling: Altes Problem im neuen Gewand AWT, Swing, JavaFX & SWT 2
G JList Neuen Eintrag sofort anzeigen AWT, Swing, JavaFX & SWT 10
M Focus beim öffnen eines neuen JFrames AWT, Swing, JavaFX & SWT 6
D JButton einen neuen ImageIcon setzen? AWT, Swing, JavaFX & SWT 2
S Problem, neuen JInternalFrame zur Laufzeit anzuzeigen AWT, Swing, JavaFX & SWT 8
G Screen nach Auswahl schließen und neuen öffnen?wie mach ichs AWT, Swing, JavaFX & SWT 8
O Brauche ich einen neuen Frame? AWT, Swing, JavaFX & SWT 2
H JTree nach setzen eines neuen TreeModels aufklappen AWT, Swing, JavaFX & SWT 2
H JTabel - RowFilter Daten für Berechnung filtern AWT, Swing, JavaFX & SWT 6
M Daten zufällig Einlesen aus einer Datei (binäres Format) AWT, Swing, JavaFX & SWT 7
W Nullpointer Exception beim übertragen von Daten von Scene zu Scene AWT, Swing, JavaFX & SWT 6
W Daten von Controller zu Controller übertragen AWT, Swing, JavaFX & SWT 7
D Columns unabhängig voneinander mit Daten füllen JavaFx AWT, Swing, JavaFX & SWT 1
H Daten aus einer XML(x83-Datei) in einem JFrame anzeigen lassen AWT, Swing, JavaFX & SWT 9
T Anbinden der Tabelle an die Daten AWT, Swing, JavaFX & SWT 5
F JavaFX Tabelle mit Daten füllen AWT, Swing, JavaFX & SWT 9
A JavaFX Daten in eine HTML-Table mit JS schreiben AWT, Swing, JavaFX & SWT 3
ralfb1105 JavaFX Daten zwischen Controllern austauschen- neue Frage AWT, Swing, JavaFX & SWT 7
ralfb1105 JavaFX Daten zwischen Controller "austauschen" AWT, Swing, JavaFX & SWT 65
B AWT Bot um Daten auf Website einzugeben und die Antwort zu bekommen AWT, Swing, JavaFX & SWT 2
L Daten bearbeiten ohne GUI zu blockieren - daten haltung/zurück geben AWT, Swing, JavaFX & SWT 15
ralfb1105 Swing JComboBox update der Daten AWT, Swing, JavaFX & SWT 8
ralfb1105 Swing Dynamischer Graph zum anzeigen Perfomance Daten AWT, Swing, JavaFX & SWT 35
D MySQL Daten in JTable anzeigen AWT, Swing, JavaFX & SWT 2
K TreeTableView (cellFactory) - wie Daten in Spalten einfügen AWT, Swing, JavaFX & SWT 0
A JTable mit Daten füllen AWT, Swing, JavaFX & SWT 1
J TableView Daten werden nicht ausgegeben AWT, Swing, JavaFX & SWT 9
A Swing Wie Daten in der Form speichern? Array oder ArrayList AWT, Swing, JavaFX & SWT 2
C Swing Daten in JTable wiedergeben per TableModel und MVC Pattern AWT, Swing, JavaFX & SWT 16
T JavaFX Model Daten übergeben AWT, Swing, JavaFX & SWT 4
D Swing Größe einer JComboBox im GridBagLayout aufgrund der maximalen Länge der enthaltenen Daten AWT, Swing, JavaFX & SWT 7
J JavaFX Tableview Daten hinzufügen aus anderer Klasse AWT, Swing, JavaFX & SWT 7
J Tableview Daten hinzufügen und aktualisieren AWT, Swing, JavaFX & SWT 5
S AWT Daten über TextField und Button in array speichern AWT, Swing, JavaFX & SWT 5
G Event Handling TableView daten in ein neues Fenster herauslesen? AWT, Swing, JavaFX & SWT 3
S JavaFX (Best Practise) Daten zwischen Controllern austauschen AWT, Swing, JavaFX & SWT 1
thet1983 JavaFX TableView Objekt Daten anzeige AWT, Swing, JavaFX & SWT 2
L JavaFX Verzögerung beim Laden von Daten AWT, Swing, JavaFX & SWT 6
L Daten in neuem Fenster AWT, Swing, JavaFX & SWT 2
Tort-E JavaFX Daten an WebView Komponente AWT, Swing, JavaFX & SWT 1
I JTable: Doppelklick auf Table soll neues Fenster öffnen und Daten aus JTable anzeigen AWT, Swing, JavaFX & SWT 4
S JTable Daten aus Array AWT, Swing, JavaFX & SWT 9
M Java FX Daten an Controller übergeben AWT, Swing, JavaFX & SWT 3
S JList ist leer, aber DefaultListModel hat die Daten? AWT, Swing, JavaFX & SWT 9
M JavaFX Von FXML-Controllerdatei Daten zurückgeben AWT, Swing, JavaFX & SWT 6
F JavaFX Daten aus Tabelle in ComboBox AWT, Swing, JavaFX & SWT 9
B Swing JTable mit Daten - Reihen-Größe anpassen AWT, Swing, JavaFX & SWT 0
D Applet GWT speichert Daten nicht in Datenbank AWT, Swing, JavaFX & SWT 2
S SWT In Listen den Einträgen Daten zuordnen AWT, Swing, JavaFX & SWT 2
T SWT Table (mit Spinner Spalte) Daten auslesen AWT, Swing, JavaFX & SWT 4
F Swing JTable: Daten voreinstellen AWT, Swing, JavaFX & SWT 4
B Daten in eine JTable schreiben AWT, Swing, JavaFX & SWT 3
H Swing JfreeChart aktualisieren - mit daten aus thread AWT, Swing, JavaFX & SWT 3
J valueChanged()-Methode liefert unbrauchbare Daten AWT, Swing, JavaFX & SWT 4
B Datenübergabe zwischen Tabs und Daten speichern AWT, Swing, JavaFX & SWT 2
D SWT TreeViewer: Daten aus Model gelöscht... trotzdem noch im Baum AWT, Swing, JavaFX & SWT 4
D Daten von JDialog an JTable in JFrame übergeben AWT, Swing, JavaFX & SWT 7
O JTable zeigt die alte Daten wieder AWT, Swing, JavaFX & SWT 23
H JTable zeigt keine Daten an AWT, Swing, JavaFX & SWT 5
M Swing Daten von JPanel zu JFrame senden AWT, Swing, JavaFX & SWT 13
C Swing JTable Daten einfügen AWT, Swing, JavaFX & SWT 6
J Swing JTable-Daten Speichern und bei zeilen-änderung beibehalten. AWT, Swing, JavaFX & SWT 6
A Daten umherschieben zwischen zwei Klassen AWT, Swing, JavaFX & SWT 40
L [SWT] Daten und Bilder drucken AWT, Swing, JavaFX & SWT 2
M Trotz richtiger Daten, falsches Bild wird gezeichnet?! AWT, Swing, JavaFX & SWT 4
O JFrame: Daten alle paar Sekunden aktualisieren AWT, Swing, JavaFX & SWT 3
C Daten aus DB -> JTable aktualisieren klappt nicht AWT, Swing, JavaFX & SWT 16
A Swing(Daten zugreifen) AWT, Swing, JavaFX & SWT 25
S JComboBox - veränderliche Daten AWT, Swing, JavaFX & SWT 6
T Daten mittels ComboBox in ein JTable adden AWT, Swing, JavaFX & SWT 7
GianaSisters Swing jTable Daten unsichtbar AWT, Swing, JavaFX & SWT 12
T JTree Daten in DB schreiben am besten SQL AWT, Swing, JavaFX & SWT 21
W Daten auf Textfeld in anderer Klasse verwenden AWT, Swing, JavaFX & SWT 4

Ähnliche Java Themen

Neue Themen


Oben