# Neues Model für JTextField erstellen



## gizmo (27. Aug 2005)

Hallo Zussammen!

Ich will für ein JTextField ein neues Model machen. Man übergibt ein Objekt, welches einen String als Attribut hat, mit entsprechenden gettern/settern und den Namen des Attributs. Nun soll dieses Objekt verwendet werden, um die Eingaben des Textfelds zu speichern. Dies funktioniert leider noch nicht ganz, es wird nur ein Zeichen angezeigt und die Reihenfolge der Eingaben stimmt auch nicht.

Vielleicht sieht jemand von euch den Überlegungsfehler...

Hier mein Code:
	
	
	
	





```
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Vector;
import javax.swing.text.*;
import javax.swing.undo.*;

public class ContentAdapter
    implements javax.swing.text.AbstractDocument.Content
{
    class MyPosition
        implements Position
    {

        public int getOffset()
        {
            return position;
        }

        private int position;

        public MyPosition(int position)
        {
            this.position = position;
        }
    }

    class InsertUndo extends AbstractUndoableEdit
    {

        public void undo()
            throws CannotUndoException
        {
            super.undo();
            try
            {
                string = getString(offset, length);
                remove(offset, length);
            }
            catch(BadLocationException bl)
            {
                throw new CannotUndoException();
            }
        }

        public void redo()
            throws CannotRedoException
        {
            super.redo();
            try
            {
                insertString(offset, string);
                string = null;
            }
            catch(BadLocationException bl)
            {
                throw new CannotRedoException();
            }
        }

        protected int offset;
        protected int length;
        protected String string;

        protected InsertUndo(int offset, int length)
        {
            this.offset = offset;
            this.length = length;
        }
    }

    class RemoveUndo extends AbstractUndoableEdit
    {

        public void undo()
            throws CannotUndoException
        {
            super.undo();
            try
            {
                insertString(offset, string);
                string = null;
            }
            catch(BadLocationException bl)
            {
                throw new CannotUndoException();
            }
        }

        public void redo()
            throws CannotRedoException
        {
            super.redo();
            try
            {
                string = getString(offset, length);
                remove(offset, length);
            }
            catch(BadLocationException bl)
            {
                throw new CannotRedoException();
            }
        }

        protected int offset;
        protected int length;
        protected String string;
        protected Vector posRefs;

        protected RemoveUndo(int offset, String string)
        {
            this.offset = offset;
            this.string = string;
            length = string.length();
        }
    }


    public ContentAdapter(Object anObject, String aPropertyName)
        throws IllegalParameterException
    {
        model = null;
        getter = null;
        setter = null;
        String getterName = "get" + aPropertyName;
        try
        {
            getter = anObject.getClass().getMethod(getterName, null);
            if(!java.lang.String.class.isAssignableFrom(getter.getReturnType()))
                throw new IllegalParameterException("Methode " + getterName + " in " + anObject.getClass() + " liefert keinen String");
        }
        catch(SecurityException e)
        {
            e.printStackTrace();
            throw new IllegalParameterException("Kein Zugriff auf " + getterName + " in " + anObject.getClass());
        }
        catch(NoSuchMethodException e)
        {
            e.printStackTrace();
            throw new IllegalParameterException("Methode " + getterName + " nicht in " + anObject.getClass() + " vorhanden");
        }
        String setterName = "set" + aPropertyName;
        try
        {
            Class parameters[] = {
                java.lang.String.class
            };
            setter = anObject.getClass().getMethod(setterName, parameters);
        }
        catch(SecurityException e)
        {
            e.printStackTrace();
            throw new IllegalParameterException("Kein Zugriff auf " + setterName + " in " + anObject.getClass());
        }
        catch(NoSuchMethodException e)
        {
            e.printStackTrace();
            throw new IllegalParameterException("Methode " + setterName + " nicht in " + anObject.getClass() + " vorhanden");
        }
        model = anObject;
    }

    public String get()
    {
        try
        {
            String ret = (String)getter.invoke(model, null);
            return ret == null ? "" : ret;
        }
        catch(IllegalArgumentException e)
        {
            e.printStackTrace();
        }
        catch(IllegalAccessException e)
        {
            e.printStackTrace();
        }
        catch(InvocationTargetException e)
        {
            e.printStackTrace();
        }
        return "";
    }

    public void set(String newString)
    {
        try
        {
            setter.invoke(model, new Object[] {
                newString != null ? newString : ""
            });
        }
        catch(IllegalArgumentException e)
        {
            e.printStackTrace();
        }
        catch(IllegalAccessException e)
        {
            e.printStackTrace();
        }
        catch(InvocationTargetException e)
        {
            e.printStackTrace();
        }
    }

    public int length()
    {
        return get().length();
    }

    public String getString(int aWhere, int aLen)
        throws BadLocationException
    {
        return get().substring(aWhere, aWhere + aLen);
    }

    public Position createPosition(int anOffset)
        throws BadLocationException
    {
        return new MyPosition(anOffset);
    }

    public void getChars(int aWhere, int aLen, Segment aTxt)
        throws BadLocationException
    {
        int end = aWhere + aLen;
        if(aWhere < 0 || end < 0)
            throw new BadLocationException("Invalid location", -1);
        if(end > length() || aWhere > length())
            throw new BadLocationException("Invalid location", length() + 1);
        try
        {
            aTxt.array = get().substring(aWhere, aWhere + aLen).toCharArray();
            aTxt.offset = aWhere;
            aTxt.count = aLen;
            System.out.println(getClass().getName() + ": " + aTxt.count);
            System.out.print(getClass().getName() + ": ");
            for(int i = 0; i < aTxt.count; i++)
                System.out.print(aTxt.array[i]);

            System.out.println();
            System.out.println(getClass().getName() + ": " + get());
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public UndoableEdit remove(int offset, int length)
        throws BadLocationException
    {
        set((new StringBuffer(get())).replace(offset, offset + length, "").toString());
        return new RemoveUndo(offset, get().substring(offset, offset + length));
    }

    public UndoableEdit insertString(int aWhere, String aStr)
        throws BadLocationException
    {
        set((new StringBuffer(get())).replace(aWhere, aWhere, aStr).toString());
        return new InsertUndo(aWhere, aStr.length());
    }

    private Object model;
    private Method getter;
    private Method setter;
}
```


```
import javax.swing.text.PlainDocument;

public class MyDocument extends PlainDocument
{

    public MyDocument(Object anObject, String aPropertyName)
        throws IllegalParameterException
    {
        super(new ContentAdapter(anObject, aPropertyName));
    }
}
```


```
import java.awt.Container;
import java.io.PrintStream;
import javax.swing.JFrame;
import javax.swing.JTextField;

public class TestTextfieldModel extends JFrame
{

    public TestTextfieldModel()
    {
        data = null;
        data = "\n";
    }

    public String getData()
    {
        return data;
    }

    public void setData(String aData)
    {
        data = aData;
    }

    public static void main(String args[])
    {
        TestTextfieldModel textfieldModel = new TestTextfieldModel();
        JTextField textField = new JTextField();
        javax.swing.text.Document document = null;
        try
        {
            document = new MyDocument(textfieldModel, "Data");
        }
        catch(IllegalParameterException e)
        {
            e.printStackTrace();
        }
        int where = 1;
        String a = "an";
        String b = "Sdro";
        System.out.println("Test: " + b.substring(0, where) + a + b.substring(where));
        textField.setDocument(document);
        textfieldModel.getContentPane().add(textField);
        textfieldModel.pack();
        textfieldModel.setDefaultCloseOperation(3);
        textfieldModel.setVisible(true);
    }

    private String data;
}
```


----------



## MPW (28. Aug 2005)

Das ist ja ganz nett, aber was willst du denn bezwecken? Wenn du grafisch was umgestallten willst(und zwar nur das), dann würde ich die Klasse dem orginal JTextField extenden lassen und dann die entsprechenden Methoden bloß überschreiben, du versuchst ja was ganz neues...das ist viel zu aufwendig.


----------



## gizmo (28. Aug 2005)

Graphisch will ich es nicht verändern, das soll genau so sein, wie das Original. Ich will nur die Datenhaltung ändern. Sonst müsste ich mit Listenern immer schauen wann sich der Text ändert und ihn dann in meinem Model neu setzen. Was ich bezwecken will ist, dass die Daten welche ich im Textfield eingebe direkt in meinem Model landen. Ohne einen Umweg über Listener zu machen.


----------



## MPW (28. Aug 2005)

hm...wo ist das Problem mit den Listenern? naja egal...musst du ja wissen....

Ähm hast du schonmal an Threads gedacht? einfach alle 0,5 oder 0,2 Sekunden einen abgleich machen, das kann man in 10 Zeilen Code machen....nicht so seitenweise wie du...

Ähm, hab' jetzt nicht genau gefunden, wo du die eingaben machst, du brauchst doch die neuen Buchstaben nur in der anderen Reihenfolge dran zu hängen, dann hast du die Reihenfolge, die du willst;-)


----------



## Roar (28. Aug 2005)

gizmo hat gesagt.:
			
		

> Graphisch will ich es nicht verändern, das soll genau so sein, wie das Original. Ich will nur die Datenhaltung ändern. Sonst müsste ich mit Listenern immer schauen wann sich der Text ändert und ihn dann in meinem Model neu setzen. Was ich bezwecken will ist, dass die Daten welche ich im Textfield eingebe direkt in meinem Model landen. Ohne einen Umweg über Listener zu machen.



wenn ich dich richtig verstehe hast du: ein JTextField und ein EinModel und der text soll in EinModel direkt beim tippen aktualisiert werden?  :autsch: nunja ich verstehe zwar nicht wozu das gut sein soll aber ladde. warum nicht mit listenern? warum auch immer: wenn du das machen willst was ich denke, dann ist dein code da doch wohl mehr als überflüssiger quark. du könntest von PlainDocument ableiten, was du jetzt schon machst und den text in der insertStrign() bzw remove() methode updaten, aber bringen tuts im vergleich zu listenern nichts.


----------



## MPW (28. Aug 2005)

Roar hat gesagt.:
			
		

> wenn ich dich richtig verstehe hast du: ein JTextField und ein EinModel und der text soll in EinModel direkt beim tippen aktualisiert werden?  :autsch: nunja ich verstehe zwar nicht wozu das gut sein soll aber ladde. warum nicht mit listenern? warum auch immer: wenn du das machen willst was ich denke, dann ist dein code da doch wohl mehr als überflüssiger quark. du könntest von PlainDocument ableiten, was du jetzt schon machst und den text in der insertStrign() bzw remove() methode updaten, aber bringen tuts im vergleich zu listenern nichts.



^^das das Quark ist habe ich mir auch schon gedacht, wollte es nur nicht so direkt sagen, da ich nicht so durchschaut habe, was er eigentlich will....aber im Prinzip ist es doch egal ob ich Action = Reaktio in einem Listener stecke oder durch einen normalen Methodenaufruf regele, oder?


----------



## gizmo (28. Aug 2005)

Ich wollte zuerst auch von PlainDocument ableiten und dort Methoden überschreiben. Weil aber die Daten im Content liegen, wäre das keine saubere Lösung. Ausserdem gibt es nicht nur zwei Methoden, welche ich überschreiben müsste, der Aufwand wäre grösser. 

Lasst doch bitte mich entscheiden, ob es sinnvoll ist, was ich mache. Ich habe einige Textfelder, deren Inhalt ich im Model halten will. Der Aufwand ist kleiner, einmal setDocument aufzurufen und dort ein Objekt und einen String zu übergeben, als für jedes Textfeld einen ActionListener zu erstellen. Eine andere Möglichkeit wäre es gewesen, einen universellen Listener zu erstellen, aber der wäre weniger universell. Ausserdem ist es auch eine Herausforderung mal etwas neues zu versuchen.

Es wäre mir viel lieber, ihr könntet mir einen Lösungsansatz bieten, anstatt zu sagen, dass mein Code Quark ist, denn das weiss ich auch selbst, sonst würde er schliesslich funktionieren.

Grüsse Gizmo


----------



## Roar (28. Aug 2005)

gizmo hat gesagt.:
			
		

> Ich wollte zuerst auch von PlainDocument ableiten und dort Methoden überschreiben. Weil aber die Daten im Content liegen, wäre das keine saubere Lösung. Ausserdem gibt es nicht nur zwei Methoden, welche ich überschreiben müsste, der Aufwand wäre grösser.



doch, 2 methoden: insertString() und remove(). üebrschreibt diese, ruf die super methode auf und setze die daten in deinem model: model.setData(getText());


----------



## gizmo (28. Aug 2005)

Wow!

Ok, du hattest recht, tut mir leid... Nun ist auch der Code nicht mehr so lang. Auf die Idee super aufzurufen wäre ich nicht gekommen, ist zwar eigentlich logisch. Die Daten sind zwar nun vermutlich doppelt gespeichert, aber hauptsache es funktioniert...

Danke


----------

