# JList / ListSelectionListener / sehr eigenartig



## Thomas Lorenz (18. Jan 2010)

Servus Gemeinde, 

also bei meinem Frame lade ich beim Aufruf ca. 11.000 Straßen in das Model meiner JList.
Anschließend kann ich über ein Textfeld anhand der Eingabe die Einträge der JList hervorragend filtern.
Klappt super.

Auch wenn ich die Eingabe im Textfeld ändere, passt sich die JList immer an.

Wenn ich aber aus der JList einen Eintrag per Maus auswähle, dann macht er auch was er soll. Er setzt die entsprechende Straße in das Textfeld und gut ist.
Nun schreibe ich per Tastatur in das Textfeld eine neue Straße und schon läuft es nicht mehr richtig.
Er passt das Model zwar an, aber das dauert sehr, sehr lange.

Das tritt immer dann auf, nachdem ich per Maus einen Eintrag ausgewählt habe und danach per Hand was neues eintrage.
Wenn ich z.B. immer mit der Maus auswähle ist auch alles in Ordnung.

Hier meine Klassen : 


```
package _Pol649;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;


public class LocationDataFrame extends JFrame implements ActionListener, FocusListener, ListSelectionListener{
    
    private static boolean locationFlag = true;
    
    JFrame 	Location 		= new JFrame("Einsatzort");
   
    JLabel	lb_infoLabel		= new JLabel("<html><b>Änderungen werden nach dem erneuten Programmstart aktiv</b></html>");
    JLabel	lb_location		= new JLabel("Einsatzort");
    JLabel	lb_locationNumber	= new JLabel("Hausnr.");
    JPanel  	panel 			= new JPanel();
    JPanel  	pan_north		= new JPanel();
    JPanel  	pan_northLeft		= new JPanel();
    JPanel  	pan_northRight		= new JPanel();
    JPanel  	pan_center		= new JPanel();
    JPanel  	pan_south		= new JPanel();
    JPanel  	pan_top			= new JPanel();
    JPanel  	pan_bottom		= new JPanel();
    
    
    
    JList	jl_listOfLocationData	= new JList(LocationDataHelper.model);
    JScrollPane scr_listOfLocationData	= new JScrollPane(jl_listOfLocationData);
    
    JTextField tf_locationOne		= new JTextField();
    
    JTextField tf_locationTwo		= new JTextField();
    JTextField tf_locationNumberOne	= new JTextField();
    JTextField tf_locationNumberTwo	= new JTextField();
    
    
    GridLayout 	lay_panel 		= new GridLayout(3,1);
    GridLayout 	lay_panNorth		= new GridLayout(1,2);
    GridLayout  lay_panNorthLeft 	= new GridLayout(3,1);
    GridLayout  lay_panNorthRight 	= new GridLayout(3,2);
    GridLayout	lay_center		= new GridLayout(1,1);
    GridLayout 	lay_panSouth		= new GridLayout(2,1);
    GridLayout 	lay_panTop		= new GridLayout(1,2);
    GridLayout 	lay_panBottom		= new GridLayout(1,1);
    JButton	bt_deleteFirstLoc	= new JButton("löschen");
    JButton	bt_deleteSecondLoc	= new JButton("löschen");
    
    JButton 	bt_save		 	= new JButton("übernehmen");
    JButton	bt_close 		= new JButton ("zur Hauptansicht");
    
    SystemData _Sys;
    ErrorHelper _Error;
    PropertyData _Data;
    MainFrame _Main;
    LocationDataHelper _loc;
    
    JFrame 	main; 
    
    
    
    Message msg = new Message();
    private Timer 	messageTimer;
    private boolean 	timerFlag = true;
    
    public LocationDataFrame(){
	this._Sys = SystemData.getInstance();
	    this._Error = ErrorHelper.getInstance();
	    this._Data = PropertyData.getInstance();
	    this._Main = (MainFrame)CollectionController.getObject("MainFrame");
	
    }
    
    
    public Container addComponentsToPane(){
	
	 messageTimer = new Timer(_Sys.getTimerInfo(), new ActionListener() {
        public void actionPerformed(final ActionEvent e) {
    	
        }
    });
 messageTimer.setRepeats(false);
   final Container pane = getContentPane();
  
   panel.setBorder(new EmptyBorder (0,0,0,0));
   panel.setLayout(lay_panel);
   panel.setBackground(_Sys.getBackground());
   
   pan_north.setLayout(lay_panNorth);
   pan_north.setBorder(new EmptyBorder(0,0,0,0));
   
   pan_northLeft.setLayout(lay_panNorthLeft);
   pan_northLeft.setBorder(new EmptyBorder(60,20,60,20));
   

   pan_northLeft.add(lb_location);
   pan_northLeft.add(tf_locationOne);
   tf_locationOne.addFocusListener(this);
   tf_locationOne.getDocument().addDocumentListener(new LocationDocListener(tf_locationOne,this));
   
   tf_locationTwo.addFocusListener(this);
   tf_locationTwo.getDocument().addDocumentListener(new LocationDocListener(tf_locationTwo, this));
   
   pan_northLeft.add(tf_locationTwo);
    
   pan_north.add(pan_northLeft);
   
   pan_northRight.setLayout(lay_panNorthRight);
   pan_northRight.setBorder(new EmptyBorder(60,25,60,70));
   
   pan_northRight.add(lb_locationNumber);
   
   pan_northRight.add(new JLabel());
   pan_northRight.add(tf_locationNumberOne);
   //tf_locationNumberOne.getDocument().addDocumentListener(new LocationDocListener(tf_locationNumberOne, this));
   tf_locationNumberOne.addFocusListener(this);
   
   pan_northRight.add(this.bt_deleteFirstLoc);
   bt_deleteFirstLoc.addActionListener(this);
   pan_northRight.add(tf_locationNumberTwo);
   tf_locationNumberTwo.addFocusListener(this);
   pan_northRight.add(this.bt_deleteSecondLoc);
   bt_deleteSecondLoc.addActionListener(this);
   
   pan_north.add(pan_northRight);
   
   pan_center.setLayout(lay_center);
   pan_center.setBorder(new EmptyBorder(0,20,0,20));
   
   jl_listOfLocationData.addListSelectionListener(this);
  
   
   pan_center.add(scr_listOfLocationData);
   
   pan_south.setLayout(lay_panSouth);
   pan_south.setBorder(new EmptyBorder(20,0,0,0));
   
   pan_top.setLayout(lay_panTop);
   pan_top.setBorder(new EmptyBorder(40,20,30,20));
   pan_top.add(this.bt_close);
   bt_close.addActionListener(this);
   bt_save.addActionListener(this);
   pan_top.add(this.bt_save);
   
   pan_bottom.setLayout(lay_panBottom);
   pan_bottom.setBorder(new EmptyBorder(0,20,10,20));
   Border loweredbevel;
	loweredbevel = BorderFactory.createLoweredBevelBorder();
	lb_infoLabel.setSize(new Dimension(300,300));
	lb_infoLabel.setBorder(loweredbevel );
	lb_infoLabel.setOpaque(true);
	lb_infoLabel.setBackground(_Sys.getBackground());
	lb_infoLabel.setForeground(Color.black);
	msg.setText("<html>" + "" + "<br>" + "" + "<br>" +
			"" + "<br> " + ""  + "<br>" + "" + "<br>" +  "</B/html>");
	lb_infoLabel.setToolTipText(_Data.getToolTipTextsForButtons().elementAt(29));
	
	lb_infoLabel.setText(msg.getText());
   pan_bottom.add(this.lb_infoLabel);
   
   
   pan_south.add(pan_top);
   pan_south.add(pan_bottom);
   
   panel.add(pan_north);
   panel.add(pan_center);
   panel.add(pan_south);
   pane.add(panel);
   
   return pane;
   
}
    
   


    public void createAndShowGUI(final JFrame Main){
	    this.main = Main;
	    Location.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
	    Location.setContentPane(addComponentsToPane());
	    Location.setBackground(_Sys.getBackground());
	    Location.setResizable(false);  
	    Location.setTitle("Einsatzort");
	    Location.setSize(600, 650);
	    Location.setLocationRelativeTo(null);	// Bildschirmmitte
	    Location.setVisible(true);
	    
	    
	}


    @Override
    public void actionPerformed(ActionEvent e) {
	JButton but = (JButton)e.getSource();
	if(but == this.bt_close){
	    Location.setVisible(false);
		main.setEnabled(true);
		main.repaint();
	}
	if(but == this.bt_save){
	    
	    // Wenn kein 1.Einsatzort, sondern ein 2.Einsatzort eingetragen wurde
	    if(this.tf_locationOne.getText().equals("") && 
		    (!this.tf_locationTwo.getText().equals(""))){
		..
		    clearFrameAndClose();
		    
		    return;
	    }
	 // Wenn kein Einsatzort eingetragen wurde, erfolgt ein Abbruch
	    if(this.tf_locationOne.getText().equals("") &&
	    	this.tf_locationTwo.getText().equals("")){
		_Error.getErrorMessage(242,
			    ..
		    return;
	    	    
	    	}
	    else{
	   
	    // Wenn der 1.Einsatzort verändert wurde
	    if(!checkLocation(this.tf_locationOne.getText())){
		_Error.getErrorMessage(244,
			    new Exception().getStackTrace()[0].getClassName()
			..
		    return;
		
	    }
	 // Wenn der 2.Einsatzort verändert wurde und
	    // nicht leer ist
	    if(!checkLocation(this.tf_locationTwo.getText()) &&
		   ! this.tf_locationTwo.getText().equals("")){
		_Error.getErrorMessage(245,
			   ..
		    return;
		
	    }
	    _Main.tf_firstLocation.setText(this.tf_locationOne.getText());
	    _Main.tf_firstLocationNumber.setText(this.tf_locationNumberOne.getText());
	    _Main.tf_secondLocation.setText(this.tf_locationTwo.getText());
	    _Main.tf_secondLocationNumber.setText(this.tf_locationNumberTwo.getText());
	    clearFrameAndClose();
	    }
	    
	}
	if(but == this.bt_deleteFirstLoc){
	    this.tf_locationOne.setText("");
	    this.tf_locationNumberOne.setText("");
	    this.tf_locationOne.grabFocus();
	    _Error.getErrorMessage(241,
		    new Exception().getStackTrace()[0].getClassName()
			    + "/"
			    + new Exception().getStackTrace()[0]
				    .getMethodName(), "");
	    setInfoText(_Error.getErrorClassification(), _Error
		    .getErrorText1(), _Error.getErrorText2(), _Error
		    .getErrorText3(), _Error.getErrorText4(), _Error
		    .getExtraText());
	}
	if(but == this.bt_deleteSecondLoc){
	    this.tf_locationTwo.setText("");
	    this.tf_locationNumberTwo.setText("");
	    this.tf_locationTwo.grabFocus();
	    _Error.getErrorMessage(240,
		    new Exception().getStackTrace()[0].getClassName()
			    + "/"
			    + new Exception().getStackTrace()[0]
				    .getMethodName(), "");
	    setInfoText(_Error.getErrorClassification(), _Error
		    .getErrorText1(), _Error.getErrorText2(), _Error
		    .getErrorText3(), _Error.getErrorText4(), _Error
		    .getExtraText());
	}
	
	
	
    }
    
    /** Gibt 'true' zurück, wenn der Inhalt des Textfeldes identisch
     * mit einer Straße aus dem Straßenverzeichnis ist.
     * Somit wird gewährleistet, dass nur schreibweisen übernommen werden, 
     * die auch im Verzeichnis vorhanden sind.
     * @param location
     * @return
     */
    public boolean checkLocation(String location){
	for(int i = 0; i< LocationDataHelper.model.size(); i++){
	    if(location.trim().equals(LocationDataHelper.model.get(i).toString().trim())){
		return true;
	    }
	}
	return false;
    }
    
    /** Löscht alle Felder zur Örtlichkeit
     * 
     */
    public void clearFrameAndClose(){
	this.tf_locationOne.setText("");
	    this.tf_locationNumberOne.setText("");
	    this.tf_locationNumberTwo.setText("");
	    this.tf_locationTwo.setText("");
	    Location.setVisible(false);
	    _Main.Main.setEnabled(true);
    }
    
    public void setInfoText(final int errorClassification, final String error1,
	    final String error2, final String error3, final String error4, final String extraText)
{
	..
}

public void clearInfoWindow(){
    if(timerFlag){
       	// .. und nun wird nach der eingestellten Zeit (_Sys.getTimerInfo())
               //die letzte Meldung mit einer Standardanzeige überschrieben
               final SimpleDateFormat fmt = new SimpleDateFormat();
               fmt.applyPattern(" HH:mm:ss");
               final Calendar cal = Calendar.getInstance();
               lb_infoLabel.setBackground(_Sys.getBackground());
               lb_infoLabel.setForeground(Color.black);
               lb_infoLabel.setText("");
           }
}


    @Override
    public void focusGained(FocusEvent e) {
	JTextField text = (JTextField)e.getSource();
	if(text == tf_locationOne ||
		text == tf_locationNumberOne){ 
	    locationFlag = true;
	    tf_locationOne.setBackground(_Sys.getBackgroundInfoYellow());
	    tf_locationNumberOne.setBackground(_Sys.getBackgroundInfoYellow());
	    tf_locationTwo.setBackground(Color.white);
	    tf_locationNumberTwo.setBackground(Color.white);
	    }
	if(text == tf_locationTwo ||
		text == tf_locationNumberTwo) { locationFlag = false;
	    tf_locationOne.setBackground(Color.white);
	    tf_locationNumberOne.setBackground(Color.white);
	    tf_locationTwo.setBackground(_Sys.getBackgroundInfoYellow());
	    tf_locationNumberTwo.setBackground(_Sys.getBackgroundInfoYellow());}
	
    }


    @Override
    public void focusLost(FocusEvent e) {
	// TODO Auto-generated method stub
	
    }


    @Override
    public synchronized void valueChanged(ListSelectionEvent e) {
	if (e.getValueIsAdjusting() == false) {

	    if (this.jl_listOfLocationData.getSelectedIndex() == -1) {
	    //No selection, disable fire button.
		

	    } else {
		System.out.println(e.getFirstIndex()+"--firstInd-------" + LocationDocListener.flag);
		if(isLocationFlag()){
		   String location = (String) this.jl_listOfLocationData.getSelectedValue();
		   
		  System.out.println(location);
		   
		   LocationDocListener.locationOne = location;

		  //LocationDocListener.flag = true;
		  this.tf_locationOne.setText(location);
		  
		 // this.jl_listOfLocationData.removeListSelectionListener(this);
	    //Selection, enable the fire button.
	    
	    }
	    }

	
	  
	  
	  
	  
	}
	if(!isLocationFlag()){
	    
	    System.out.println("Frame / locationFlag == false");
	   
	   
	}
	
    }


    /**
     * @return the locationFlag
     */
    public static boolean isLocationFlag() {
        return locationFlag;
    }


    /**
     * @param locationFlag the locationFlag to set
     */
    public static void setLocationFlag(boolean locationFlag) {
        LocationDataFrame.locationFlag = locationFlag;
    }
    
    public void setListSelectionListenerForJList(){
	this.jl_listOfLocationData.addListSelectionListener(this);
    }
    

}
```

Jetzt der DocumentListener mit der Textbehandlung:


```
package _Pol649;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class LocationDocListener implements DocumentListener ,Cloneable {
    JTextField text ;
    LocationDataFrame frame;
    public static boolean flag = true;
    private boolean foundFlag = false;
    public static String locationOne = "";
    public static String locationTwo = "";
    
    public LocationDocListener( JTextField text, LocationDataFrame location){
	this.text = text;
	this.frame = location;
	
    }
    
   

    @Override
    public synchronized void changedUpdate(DocumentEvent e) {
	final Document doc = (Document)e.getDocument();
	SwingUtilities.invokeLater(new Runnable() {
		public void run() {
	try{
	    if(flag){
	    searchForString(doc.getText(0, text.getText().length()));
	    }
	}
	catch (BadLocationException e1){
	    // TODO Auto-generated catch block
	    e1.printStackTrace();
	}
		}});
	

    }

    @Override
    public synchronized void insertUpdate(DocumentEvent e) {
	
	final Document doc = (Document)e.getDocument();
	SwingUtilities.invokeLater(new Runnable() {
		public void run() {
	try{
	    if(flag){
	    searchForString(doc.getText(0, text.getText().length()));
	    }
	}
	catch (BadLocationException e1){
	    // TODO Auto-generated catch block
	    e1.printStackTrace();
	}
		}});
	
	
    }

    @Override
    public  synchronized void removeUpdate(DocumentEvent e) {
	final Document doc = (Document)e.getDocument();
	SwingUtilities.invokeLater(new Runnable() {
		public void run() {
	try{
	    checkModelSize();
	    if(!flag){
		
	    }
	    if(flag){
	    searchForString(doc.getText(0, text.getText().length()));
	    }
	    
	}
	catch (BadLocationException e1){
	    // TODO Auto-generated catch block
	    e1.printStackTrace();
	}
		}});
	

    }
    
    
    /** Überprüft, ob der übergebene Text des Textfeldes im Modelvektor vorkommt.
     * Hierbei werden auch Teilstrings zugelassen.
     * Sollte der übergebene Text vorkommen, wird das Model entsprechend 
     * geändert.
     * @param text
     */
    public void searchForString(String text){
	LocationDataHelper.modelClone.clear();
	    this.frame.jl_listOfLocationData.setModel(LocationDataHelper.model);
	// Kommt der String im Model vor?
	
	for(int i = 0; i < LocationDataHelper.model.size(); i++){
	    
	    System.out.println("Daten einlesen-----" + i + "LocationFlag :" + 
        LocationDataFrame.isLocationFlag() + "--- Flag: " + flag);
	    if(LocationDataHelper.model.get(i).toString().startsWith(text) ||
		    LocationDataHelper.model.get(i).toString().equals(text) ||
		LocationDataHelper.model.get(i).toString().toLowerCase().contains(text.toLowerCase())){
		// Dem geklonten Model werden die gefundenen Einträge übergeben
		LocationDataHelper.modelClone.addElement(LocationDataHelper.model.get(i).toString().trim());
		// Die JList bekommt das geklonte Model übergeben
		this.frame.jl_listOfLocationData.setModel(LocationDataHelper.modelClone);
	    }
	    
	    
	}
	// Wenn nur noch ein Eintrag in der JList steht..
	if(LocationDataHelper.modelClone.size()==1){
	    flag = false;
	    System.out.println("hier");
	    // .. und es sich um das 1.Textfeld (isLocationFlag == true) handelt..
	    if(LocationDataFrame.isLocationFlag()){	
		// .. bekommt das Textfeld den übriggebliebenen Eintrag
		this.frame.tf_locationOne.setText(LocationDataHelper.modelClone.
           firstElement().toString().trim());
		// das Textfeld wird komplett markiert
		//this.frame.tf_locationOne.selectAll();
		// eine Hilfsvariable für das 1.Textfeld bekommt den einzigen Eintrag aus dem geklonten Model
		setLocationOne(LocationDataHelper.modelClone.firstElement().toString().trim());
		// Um weitere Eingaben zu unterbinden / unterbrechen, wird eine Meldung ausgegeben, 
		// die bestätigt werden muss
		JOptionPane.showMessageDialog(frame, "Die letzte verbliebene Straße wurde übernommen");
		this.frame.tf_locationNumberOne.grabFocus();
		
		
		
	   }
	    if(!LocationDataFrame.isLocationFlag()){
		// .. und es sich um das 2.Textfeld (isLocationFlag == false) handelt..
		this.frame.tf_locationTwo.setText(LocationDataHelper.modelClone.
          firstElement().toString().trim());
		// das Textfeld wird komplett markiert
		this.frame.tf_locationTwo.selectAll();
		// eine Hilfsvariable für das 2.Textfeld bekommt den einzigen Eintrag aus dem geklonten Model
		setLocationTwo(LocationDataHelper.modelClone.firstElement().toString().trim());
		// Um weitere Eingaben zu unterbinden / unterbrechen, wird eine Meldung ausgegeben, 
		// die bestätigt werden muss
		JOptionPane.showMessageDialog(frame, "Die letzte verbliebene Straße wurde übernommen");
		this.frame.tf_locationNumberTwo.grabFocus();
	    }
	    //this.frame.setListSelectionListenerForJList();
	    checkModelSize();
		
	} 
    
	
    
	if(LocationDataHelper.modelClone.size()==0){		
	    JOptionPane.showMessageDialog(frame, "Keine Übereinstimmung.\n\nIhre Eingabe : " + text);
	    if(LocationDataFrame.isLocationFlag()){
		this.frame.tf_locationOne.setText(this.frame.tf_locationOne.getText().substring(
                  0, this.frame.tf_locationOne.getText().length()-1));
		this.frame.tf_locationOne.grabFocus();
		this.frame.tf_locationOne.select(0, this.frame.tf_locationOne.getText().length());
		this.frame.tf_locationOne.setCaretPosition(this.frame.tf_locationOne.getText().length());
	    	
	    	//this.frame.tf_locationOne.setCaretPosition(this.frame.tf_locationOne.getText().length());
	    	//this.frame.tf_locationOne.sel
	    }
	    if(!LocationDataFrame.isLocationFlag()){
		this.frame.tf_locationTwo.setText(this.frame.tf_locationTwo.getText().substring(
                  0, this.frame.tf_locationTwo.getText().length()-1));
		
	    	
	    	this.frame.tf_locationTwo.setCaretPosition(this.frame.tf_locationTwo.getText().length());
	    }
	    
	}
	else{return;}
	
    }
	
    
    
    
    /** Überprüft die aktuelle Größe des geklonten Models
     * 
     */
    public synchronized void checkModelSize(){
	// Wenn es sich um das 1.Textfeld handelt..
	if(LocationDataFrame.isLocationFlag()){
	    
	    	// Wenn sich der Inhalt des Textfeldes von der Hilfsvariablen unterscheidet
	    	// (z.B. wenn der Anwender einen Buchstaben gelöscht hat)
	    	// und nur noch ein Eintrag im geklonten Model enthalten ist
        	if(!this.frame.tf_locationOne.getText().equals(getLocationOne()) &&
        		LocationDataHelper.modelClone.size() <=1){
        	    SwingUtilities.invokeLater(new Runnable() {
        		public void run() {
        	flag = true;
		
		// Das Model wird geleert
		LocationDataHelper.modelClone.clear();
			// und mit den gesamten Straßenverzeichnis (model) gefüllt.
		for(int y = 0; y < LocationDataHelper.model.size(); y++){
		    System.out.println("CheckModelSize 3 --"+y);
		    LocationDataHelper.modelClone.addElement(LocationDataHelper.model.get(y));
		    
		}
	
        		}});
        		 // Die JList bekommt alle Straßen
            	    this.frame.jl_listOfLocationData.setModel(LocationDataHelper.model);
            	    // Die Hilfsvariable wird gelöscht
            	    setLocationOne("");
        	    
        	 }
	}
	// Wie oben , nur für das 2.Textfeld
	if(!LocationDataFrame.isLocationFlag()){
	if(!this.frame.tf_locationTwo.getText().equals(getLocationTwo()) &&
		LocationDataHelper.modelClone.size() <=1){
	    flag = true;
	    LocationDataHelper.modelClone.clear();
		for(int y = 0; y < LocationDataHelper.model.size(); y++){
		    LocationDataHelper.modelClone.addElement(LocationDataHelper.model.get(y));
		}
	    this.frame.jl_listOfLocationData.setModel(LocationDataHelper.model);
	    setLocationOne("");
	 }
	}
    }

    /**
     * @return the locationOne
     */
    public String getLocationOne() {
        return locationOne;
    }

    /**
     * @return the locationTwo
     */
    public String getLocationTwo() {
        return locationTwo;
    }

    /**
     * @param locationOne the locationOne to set
     */
    public void  setLocationOne(String locationOne) {
        this.locationOne = locationOne;
    }

    /**
     * @param locationTwo the locationTwo to set
     */
    public void setLocationTwo(String locationTwo) {
        this.locationTwo = locationTwo;
    }
    
    

}
```

und .. 

```
package _Pol649;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;

import javax.swing.DefaultListModel;
import javax.swing.JOptionPane;
import javax.swing.ListModel;
import javax.swing.event.ListDataListener;

public class LocationDataHelper  {
    
    private String street ; 
    static DefaultListModel model = new DefaultListModel();
    static DefaultListModel modelClone = new DefaultListModel();
    



public LocationDataHelper(String street){
    this.street = street;
    model.addElement(street);
    
    //this.zip= zip;
}

public static void getModelData(){
    for(int i = 0; i <  model.size(); i++){
	
    }
}

public static void sortModelData(String text){
    

    
}

}
```


----------



## Thomas Lorenz (20. Jan 2010)

Ich dachte nur, dass ich die Lösung habe.
Ist aber nicht der Fall.
Deshalb ist das Thema wieder offen.


----------



## Ebenius (21. Jan 2010)

Ich tippe einfach mal ins Blaue: Wenn Du den neuen Text eingibst, dann wird erstmal der gesamte Filter ausgesetzt, weil der Filtertext ja ein Leerstring ist und damit jede Straße sichtbar sein soll. Wenn zuvor nur eine Straße in der Liste zu sehen war (oder nur eine Handvoll), dann werden ungefähr elftausend Straßen der Liste hinzugefügt während Du tippst. Das kann natürlich dauern.

Deinen Code habe ich mir nur ganz flüchtig angesehen, weil das ein bisschen viel war. Du arbeitest auf mehreren Modellen und schaltest diese um, oder? Das ist nie eine gute Idee. Als Lösungsvorschlag: Mach Dir *ein* eigenes ListModel, das vernünftig filtern kann. Sowas in etwa:

```
/* $Id$ */

/* Copyright 2010 Sebastian Haufe

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.util.*;

import javax.swing.AbstractListModel;

public class FilteringListModel extends AbstractListModel {

  private final String[] allValues;
  private List<String> matches = new ArrayList<String>();
  private String filter = null;

  FilteringListModel(String[] values) {
    allValues = values.clone();
    matches.addAll(Arrays.asList(values));
  }

  public String getFilter() {
    return filter;
  }

  public void setFilter(String newFilter) {
    final String oldValue = this.filter;
    this.filter = newFilter;
    if (oldValue == null || newFilter.startsWith(oldValue)) {
      // filter narrowed
      for (ListIterator<String> it = matches.listIterator(); it.hasNext();) {
        final String test = it.next();
        if (!test.startsWith(newFilter)) {
          final int index = it.previousIndex();
          it.remove();
          fireIntervalRemoved(this, index, index);
        }
      }
    } else if (oldValue.startsWith(newFilter)) {
      // filter widened
      for (int i = 0, j = 0; i < allValues.length; i++) {
        final String test = allValues[i];
        if (test.startsWith(newFilter)) {
          if (matches.size() <= j || matches.get(j) != test) {
            matches.add(j, test);
            fireIntervalAdded(this, j, j);
          }
          j++;
        }
      }
    } else {
      // another change; complete rebuild
      final int oldSize = matches.size();
      if (oldSize != 0) {
        matches.clear();
        fireIntervalRemoved(this, 0, oldSize - 1);
      }
      for (final String test : allValues) {
        if (test.startsWith(newFilter)) {
          matches.add(test);
        }
      }
      final int newSize = matches.size() - 1;
      if (newSize != 0) {
        fireIntervalAdded(this, newSize, newSize);
      }
    }
  }

  public Object getElementAt(int index) {
    return matches.get(index);
  }

  public int getSize() {
    return matches.size();
  }
}
```
Wenn die Performance nicht reicht, kann man auch noch die Events zusammenfassen; dafür hab ich aber grad keine Zeit. 

Ebenius


----------



## Thomas Lorenz (23. Jan 2010)

Guten Morgen, 

ich danke Dir für Deinen Code und habe ihn - leicht modifiziert - eingebaut. 
Aber es kommt weiterhin zu diesem Fehler.

Das ist ja keine kurze Verzögerung!
Ich meine damit ca. 30 Sekunden, und dafür habe nun kein Verständnis.

Aber ich habe gerade gelesen : "Do not use a DocumentListener für input validation".

Daher werde ich es mit einem DocumentFilter probieren.

Was daraus geworden ist, werde ich hier noch bekannt geben.


----------



## Ebenius (23. Jan 2010)

Die InputVerifier springen erst an, wenn das Textfeld den Fokus verliert. Das sollte für Dich kaum das richtige sein.

Ebenius


----------



## Ebenius (23. Jan 2010)

Hm, hier mal ein Beispiel wie's bei mir mit meinem FilteringListModel halbwegs flüssig funktioniert: 
	
	
	
	





```
/* $Id$ */

/* Copyright 2010 Sebastian Haufe

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.BorderLayout;
import java.util.Random;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class FilteringListTestGUI {

  /**
   * Test main method.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {
    final String[] values = new String[20000];
    final Random rnd = new Random();
    for (int i = 0; i < values.length; i++) {
      values[i] = randomString(rnd);
    }

    final FilteringListModel listModel = new FilteringListModel(values);
    final JList list = new JList(listModel);

    final JTextField filterTF = new JTextField(10);
    filterTF.getDocument().addDocumentListener(new DocumentListener() {

      public void removeUpdate(DocumentEvent e) {
        updateFilter(listModel, e);
      }

      public void insertUpdate(DocumentEvent e) {
        updateFilter(listModel, e);
      }

      public void changedUpdate(DocumentEvent e) {
        updateFilter(listModel, e);
      }

      private void updateFilter(FilteringListModel listModel, DocumentEvent e) {
        final Document doc = e.getDocument();
        try {
          listModel.setFilter(doc.getText(0, doc.getLength()));
        } catch (BadLocationException ex) {
          assert false;
        }
      }
    });

    final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
    contentPane.add(new JScrollPane(list), BorderLayout.CENTER);
    contentPane.add(filterTF, BorderLayout.SOUTH);

    final JFrame f = new JFrame("Test Frame: FilteringListTestGUI");
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }

  private static String randomString(Random rnd) {
    return Long.toString(rnd.nextLong(), 16);
  }
}
```
Natürlich kann man das ListModel noch beschleunigen, hab ich aber immer noch nich gemacht. :-D

Ebenius


----------



## Ebenius (23. Jan 2010)

Und hier nochmal so, dass das Texfeld auch noch mit aktualisiert wird. So willst Du's wahrscheinlich: 
	
	
	
	





```
/* $Id$ */

/* Copyright 2010 Sebastian Haufe

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.BorderLayout;
import java.util.Random;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class FilteringListTestGUI {

  private static class FilterHandler
    implements DocumentListener, ListSelectionListener {

    private final FilteringListModel listModel;
    private final JList list;
    private final Document doc;

    boolean inEventProcessing = false;

    /** Creates a new {@code FilterHandler}. @param listModel */
    FilterHandler(JList list, FilteringListModel listModel, Document doc) {
      this.list = list;
      this.listModel = listModel;
      this.doc = doc;
    }

    public void removeUpdate(DocumentEvent e) {
      updateFilter(listModel, e);
    }

    public void insertUpdate(DocumentEvent e) {
      updateFilter(listModel, e);
    }

    public void changedUpdate(DocumentEvent e) {
      updateFilter(listModel, e);
    }

    private void updateFilter(FilteringListModel listModel, DocumentEvent e) {
      inEventProcessing = true;
      final Document doc = e.getDocument();
      try {
        listModel.setFilter(doc.getText(0, doc.getLength()));
      } catch (BadLocationException ex) {
        assert false;
      } finally {
        inEventProcessing = false;
      }
    }

    public void valueChanged(ListSelectionEvent e) {
      if (!inEventProcessing) {
        inEventProcessing = true;
        try {
          final ListSelectionModel sm = list.getSelectionModel();
          if (sm.getMinSelectionIndex() == sm.getMaxSelectionIndex()) {
            doc.remove(0, doc.getLength());
            doc.insertString(0, (String) list.getSelectedValue(), null);
          }
        } catch (BadLocationException ex) {
          assert false;
        } finally {
          inEventProcessing = false;
        }
      }
    }
  }

  /**
   * Test main method.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {
    final String[] values = new String[20000];
    final Random rnd = new Random();
    for (int i = 0; i < values.length; i++) {
      values[i] = randomString(rnd);
    }

    final FilteringListModel listModel = new FilteringListModel(values);
    final JList list = new JList(listModel);

    final JTextField filterTF = new JTextField(10);
    final FilterHandler handler =
          new FilterHandler(list, listModel, filterTF.getDocument());
    filterTF.getDocument().addDocumentListener(handler);

    list.getSelectionModel().addListSelectionListener(handler);

    final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
    contentPane.add(new JScrollPane(list), BorderLayout.CENTER);
    contentPane.add(filterTF, BorderLayout.SOUTH);

    final JFrame f = new JFrame("Test Frame: FilteringListTestGUI");
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }

  private static String randomString(Random rnd) {
    return Long.toString(rnd.nextLong(), 16);
  }
}
```
Ebenius


----------



## Thomas Lorenz (23. Jan 2010)

Ich habe das soeben ausprobiert und es läuft fast perfekt.

Fast aus dem Grund, weil beim Auswählen mittels Maus immer der 
erste Listeneintrag übernommen wird.

Trotzdem ein großes Danke für Deine Hilfe.

Ich weiß nicht genau wofür "inEventProcessing" steht, aber ich vermute, dass es sich 
auf die Methoden des DocumentListeners auswirkt und ggf. verhindert, dass der 
DocumentListener weiter aktiv ist.


----------



## Ebenius (24. Jan 2010)

Thomas Lorenz hat gesagt.:


> Fast aus dem Grund, weil beim Auswählen mittels Maus immer der
> erste Listeneintrag übernommen wird.


Das verstehe ich nicht richtig. Erklär mal anders...



Thomas Lorenz hat gesagt.:


> Ich weiß nicht genau wofür "inEventProcessing" steht, aber ich vermute, dass es sich auf die Methoden des DocumentListeners auswirkt und ggf. verhindert, dass der DocumentListener weiter aktiv ist.


So ähnlich. Beide Modelle benachrichtigen sich ja gegenseitig. Man muss ja verhindern, dass Modell A (das Dokument) eine Veränderung an Modell B (ListModel) verursacht die dann wieder Modell A verändern will. Ein Teufelskreis. 



Thomas Lorenz hat gesagt.:


> Trotzdem ein großes Danke für Deine Hilfe.


Kein Problem. Wir bekommen's schon noch so hin wie Du willst...

Ebenius


----------



## Thomas Lorenz (24. Jan 2010)

Wenn ich aus der Liste z.B. den 10.Eintrag auswähle, dann fügt er in das Textfeld den allerersten Eintrag ein.
Das habe ich mir mal mit System.out.println angesehen.

Hierbei war zu sehen, dass er sehr wohl zunächst den ausgewählten (also den 10.Eintrag) auf der Konsole ausgibt.
Das aber mehrmals.
Und dann gibt er den 1.Eintrag aus - ebenfalls mehrmals - .

Also wird er so auch mit dem Textfeld verfahren. Erst den ausgewählten Eintrag nehmen und dann mit dem 
1.Eintrag überschreiben.

Wenn das exakt so laufen soll wie ich es mir vorstelle, dann wird sobald nur noch ein möglicher Eintrag in der
Liste steht , dieser letzte Eintrag automatisch in das Textfeld geschrieben.

Dies hatte ich schon probiert. Mit der Abfrage des Models (getSize()), ob die Size == 1 ist. Aber so richtig setzt er 
mir das nun erste Element nicht in das Textfeld. 

Aber Schritt für Schritt.


----------



## Ebenius (24. Jan 2010)

So, da hab ich mich doch gleich nochmal dran gesetzt. Hier nun eine Version die so funktionieren sollte wie Du's brauchst: 
	
	
	
	





```
/* $Id$ */

/* Copyright 2010 Sebastian Haufe

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.awt.BorderLayout;
import java.awt.event.*;
import java.util.Random;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;

public class FilteringListTestGUI {

  private static class FilterHandler extends MouseAdapter
    implements DocumentListener, ListSelectionListener, KeyListener {

    private final FilteringListModel listModel;
    private final JList list;
    private final Document doc;
    private boolean selectionListenerDisabled;

    /** Creates a new {@code FilterHandler}. @param listModel */
    FilterHandler(JList list, FilteringListModel listModel, Document doc) {
      this.list = list;
      this.listModel = listModel;
      this.doc = doc;
    }

    private void processDocumentEvent(DocumentEvent e) {
      final Document doc = e.getDocument();
      try {
        setFilterValue(doc.getText(0, doc.getLength()));
      } catch (BadLocationException ex) {
        assert false;
      }
    }

    private void filterBySelection() {
      try {
        doc.remove(0, doc.getLength());
        final String value = (String) list.getSelectedValue();
        doc.insertString(0, value, null);
        setFilterValue(value);
      } catch (BadLocationException ex) {
        assert false;
      }
    }

    void setFilterValue(String value) {
      selectionListenerDisabled = true;
      listModel.setFilter(value);
      if (listModel.getSize() == 1) {
        list.setSelectedIndex(0);
      }
      selectionListenerDisabled = false;
    }

    // -----------------------------------------------------------------------
    // Event handling
    // -----------------------------------------------------------------------

    public void removeUpdate(DocumentEvent e) {
      processDocumentEvent(e);
    }

    public void insertUpdate(DocumentEvent e) {
      processDocumentEvent(e);
    }

    public void changedUpdate(DocumentEvent e) {
      processDocumentEvent(e);
    }

    @Override
    public void mouseReleased(MouseEvent e) {
      final int index = list.locationToIndex(e.getPoint());
      if (index != -1) {
        filterBySelection();
      }
    }

    public void valueChanged(ListSelectionEvent e) {
      if (e.getValueIsAdjusting()) {
        return;
      }
      if (!selectionListenerDisabled) {
        filterBySelection();
      }
    }

    public void keyReleased(KeyEvent e) {
      switch (e.getKeyCode()) {
      case KeyEvent.VK_ENTER:
      case KeyEvent.VK_SPACE:
        e.consume();
        filterBySelection();
      }
    }

    public void keyPressed(KeyEvent e) {}

    public void keyTyped(KeyEvent e) {}
  }

  /**
   * Test main method.
   * 
   * @param args ignored
   */
  public static void main(String[] args) {
    final String[] values = new String[20000];
    final Random rnd = new Random();
    for (int i = 0; i < values.length; i++) {
      values[i] = randomString(rnd);
    }

    final FilteringListModel listModel = new FilteringListModel(values);
    final JList list = new JList(listModel);
    list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

    final JTextField filterTF = new JTextField(10);
    final Document doc = filterTF.getDocument();
    final FilterHandler handler = new FilterHandler(list, listModel, doc);
    doc.addDocumentListener(handler);
    list.addMouseListener(handler);
    list.addKeyListener(handler);
// list.getSelectionModel().addListSelectionListener(handler);

    final JPanel contentPane = new JPanel(new BorderLayout(6, 6));
    contentPane.add(new JScrollPane(list), BorderLayout.CENTER);
    contentPane.add(filterTF, BorderLayout.SOUTH);

    final JFrame f = new JFrame("Test Frame: FilteringListTestGUI");
    f.setContentPane(contentPane);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.setVisible(true);
  }

  private static String randomString(Random rnd) {
    return Long.toString(rnd.nextLong(), 16);
  }
}
```
Beachte: Du kannst zum Test Zeile 141 und 142 auskommentieren und 143 aktivieren. Das funktioniert ebenfalls, allerdings wird die Bedienung mit der Tastatur dann äußerst unschön, da jede Bewegung mit den ↓↑ Pfeiltasten dazu führt, dass die Liste nur noch einen Eintrag hat (logisch und unschön). 

Wenn Dir die Variante mit KeyListener und MouseListener so gefällt, dann kannst Du den Handler natürlich kürzen, indem Du die Variable [c]selectionListenerDisabled[/c], all deren Auftauchen, die Methode [c]valueChanged[/c] und [c]ListSelectionListener, [/c] in Zeile 31 entfernst.

Achtung, im [c]FilteringListModel[/c] oben befindet sich noch ein Bug, der zwar mit der Liste und dem Dokument nicht auftritt, aber eben trotzdem ein Bug ist. Zeile 77 muss natürlich so aussehen: 
[java=77]        fireIntervalAdded(this, 0, newSize);[/code]
Du kannst aber auch gleich diese Version nehmen, die fasst die Events noch in Blöcke zusammen, was die Verarbeitungsgeschwindigkeit besonders bei sortierten Daten deutlich erhöht:

```
/* $Id$ */

/* Copyright 2010 Sebastian Haufe

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       [url]http://www.apache.org/licenses/LICENSE-2.0[/url]

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License. */

package com.ebenius;

import java.util.*;

import javax.swing.AbstractListModel;

public class FilteringListModel extends AbstractListModel {

  private final String[] allValues;
  private List<String> matches = new ArrayList<String>();
  private String filter = null;

  FilteringListModel(String[] values) {
    allValues = values.clone();
    matches.addAll(Arrays.asList(values));
  }

  public String getFilter() {
    return filter;
  }

  public void setFilter(String newFilter) {
    final String oldValue = this.filter;
    this.filter = newFilter;
    if (oldValue == null || newFilter.startsWith(oldValue)) {
      // filter narrowed
      int start = -1;
      int end = -1;
      for (ListIterator<String> it = matches.listIterator(); it.hasNext();) {
        final String test = it.next();
        if (!test.startsWith(newFilter)) {
          final int index = it.previousIndex();
          it.remove();
          if (start == -1) {
            start = end = index;
          } else {
            end++;
          }
        } else if (start != -1) {
          fireIntervalRemoved(this, start, end);
          start = -1;
        }
      }
      if (start != -1) {
        fireIntervalRemoved(this, start, end);
      }
    } else if (oldValue.startsWith(newFilter)) {
      // filter widened
      int start = -1;
      int end = -1;
      for (int i = 0, j = 0; i < allValues.length; i++) {
        final String test = allValues[i];
        if (test.startsWith(newFilter)) {
          if (matches.size() <= j || matches.get(j) != test) {
            matches.add(j, test);
            if (start == -1) {
              start = end = j;
            } else {
              end++;
            }
          } else if (start != -1) {
            fireIntervalAdded(this, start, end);
            start = -1;
          }
          j++;
        }
      }
      if (start != -1) {
        fireIntervalAdded(this, start, end);
      }
    } else {
      // another change; complete rebuild
      final int oldSize = matches.size();
      if (oldSize != 0) {
        matches.clear();
        fireIntervalRemoved(this, 0, oldSize - 1);
      }
      for (final String test : allValues) {
        if (test.startsWith(newFilter)) {
          matches.add(test);
        }
      }
      final int newSize = matches.size() - 1;
      if (newSize != 0) {
        fireIntervalAdded(this, 0, newSize);
      }
    }
  }

  public Object getElementAt(int index) {
    return matches.get(index);
  }

  public int getSize() {
    return matches.size();
  }
}
```
Haben Sie Spaß!
Ebenius


----------



## Thomas Lorenz (25. Jan 2010)

Servus Ebenius, 

das ist genau das, was ich haben wollte !!
Ein weiteres großes Danke an Dich (jetzt Dein 'DankeKonto' ausgeglichen )

Ich hatte noch ein paar Anpassungen:
-für zwei Textfelder, es gibt ja auch Kreuzungen
- außerdem schreibt er , wenn nur noch eine Straße im Model steht, diese letzte Straße automatisch ins Textfeld


Schön, dass Du Dich so intensiv damit beschäfigt hast.

Bis dann
Thomas


----------

