# JTable: Eingabe nur für bestimmte Var.Typen zulassen



## Scrimau (22. Nov 2009)

Hi, ich möchte in meiner Tabelle (JTable) für eine Spalte nur bestimmte Eingaben zulassen, z.B nur Integer für die erste Spalte, Doubles für die 2. Spalte, etc. 
Ich dachte ich könnte das mit einem eigens abgeleiteten DefaultTableModel bewerkstelligen, klappte allerdings nicht (dann verwarf er alles was ich eingab):


```
import javax.swing.table.DefaultTableModel;

public class Tabelle extends DefaultTableModel{

    @Override
    public void setValueAt(Object aValue, int row, int col) {
        if (aValue instanceof Integer) {
            super.setValueAt(aValue, row, col);
        }
    }
}
```

Edit: Habe jetzt mal diese Sache hier ausprobiert:

```
@Override
    public void setValueAt(Object aValue, int row, int col) {
        if (Integer.valueOf(aValue.toString())!=null) {
            super.setValueAt(aValue, row, col);
        }
```

Nun lässt er zwar nur Integer zu, aber es gibt eine Exception: 
Exception in thread "AWT-EventQueue-0" java.lang.NumberFormatException: For input string: "sfsfs"

kann ich die vielleicht einfach missachten?  (oder halt mit try catch abfangen und dann einfach ignorieren?)
Oder bin ich auf dem völlig falschen Weg?


Bin dankbar für jeden Vorschlag


----------



## Marco13 (22. Nov 2009)

Hast du dir sowas wie How to Use Tables (The Java™ Tutorials > Creating a GUI With JFC/Swing > Using Swing Components) schon angesehen?


----------



## HannsW (22. Nov 2009)

Ich würde es mit try-catch machen. Im catch-Zweig setzt Du dann deinen Wert auf " " ( leeren string), DAs dürfte auch mit Double klappen.
Hanns


----------



## hdi (22. Nov 2009)

Du musst die Methode getColumnClass() überschreiben und für diese Spalte Integer.class zurückgeben. Dann kommt bei der instanceof Prüfung auch true raus und er setzt den Wert - defaultmässig wird alles als String behandelt.


----------



## Scrimau (23. Nov 2009)

hdi hat gesagt.:


> Du musst die Methode getColumnClass() überschreiben und für diese Spalte Integer.class zurückgeben. Dann kommt bei der instanceof Prüfung auch true raus und er setzt den Wert - defaultmässig wird alles als String behandelt.



Danke, so hatte ich mir das vorgestellt jetzt nur noch 1 kleine Sache, wie begrenze ich jetz z.B. die EIngabe auf einen bestimmten Bereich sagen wir von 1..100, hatte mir das so gedacht, das funzt aber wieder nicht:


```
import javax.swing.table.DefaultTableModel;

public class Tabelle extends DefaultTableModel{

    Integer max;

    public void setmax(Integer wert)
    {
        this.max=wert;
    }

   public Integer getmax()
    {
        return this.max;
    }

    @Override
    public void setValueAt(Object aValue, int row, int col)
    {
        
        if ((aValue>=0 && aValue<max) || col==3)
        {
            super.setValueAt(aValue, row, col);
        }
    }

    @Override
    public Class getColumnClass(int col)
    {
        if (col==1 || col==2)
            return Integer.class;
        else
            return Double.class;
    }
}
```

Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: Uncompilable source code - operator >= cannot be applied to java.lang.Object,int


----------



## SlaterB (23. Nov 2009)

tja, ohne instanceof + Cast kein Rechnen oder Vergleich auf > 0,


----------



## Scrimau (23. Nov 2009)

Habs jetz so:


```
import javax.swing.table.DefaultTableModel;

public class Tabelle extends DefaultTableModel{

    Integer max;

    public void setmax(Integer wert)
    {
        this.max=wert;
    }

   public Integer getmax()
    {
        return this.max;
    }

    @Override
    public void setValueAt(Object aValue, int row, int col)
    {
       
        if (aValue instanceof Integer)
        {
            if ((Integer.valueOf(aValue.toString())>=0 && Integer.valueOf(aValue.toString())<max) || col==3)
            {
                super.setValueAt(Integer.valueOf(aValue.toString()), row, col);
            }            
        }

    }

    @Override
    public Class getColumnClass(int col)
    {
        if (col==1 || col==2)
            return Integer.class;
        else
            return Double.class;
    }
}
```

Aber da funktioniert es in der 2.Spalte (weiss der Geier, warum) aber in den übrigen Spalten setzt er es immer wieder zurück, egal welcher Eingabewert.

Hat wer nen Lösungsvorschlag?


----------



## hdi (23. Nov 2009)

1) Der Spaltenindex beginnt bei 0, nicht bei 1.
D.h. deine Klassen für die Spalten intern sind für die *2.* und *3.*Spalte Integer, für alle anderen Double.
2) Deshalb kannst du in der 2. *und* 3. Spalte auch einen int-Wert setzen (das dürfte nicht nur in der 2. Spalte funktionieren)
3) Da alle anderen Spalten einen Double enthalten, wird die_ instanceof Integer_ Prüfung in der setValue() für diese Spalten niemals true, deshalb passiert da auch nix.

Also nochmal zum Verständnis: Was du bei getColumnClass() für eine Klasse zurückgibst, bestimmt von welchem Typ dann in der setValue() dein Objekt "aValue" ist. Jeweils für den Spaltenindex halt. Und es gilt: 1.Spalte in der Ansicht = Index 0, wie bei Arrays.


----------



## Scrimau (23. Nov 2009)

Klappt jetzt alles, danke, Leute.

Hier noch zum Abschluss der ganze Quelltext:

```
import javax.swing.table.DefaultTableModel;

public class Tabelle extends DefaultTableModel{

    Integer max;

    public void setmax(Integer wert)
    {
        this.max=wert;
    }

   public Integer getmax()
    {
        return this.max;
    }

    @Override
    public void setValueAt(Object aValue, int row, int col)
    {

        if (aValue instanceof Integer)
        {
            if ((Integer.valueOf(aValue.toString())>=0 && Integer.valueOf(aValue.toString())<max))
            {
                super.setValueAt(Integer.valueOf(aValue.toString()), row, col);
            }
        }
        else
            super.setValueAt(aValue, row, col);

    }

    @Override
    public Class getColumnClass(int col)
    {
        if (col==0 || col==1)
            return Integer.class;
        else
            return Double.class;
    }
}
```

/close


----------



## hdi (23. Nov 2009)

Ich hab noch was zu bemängeln 
1) Attribut "max" private machen, sonst haben Getter und Setter keinen Sinn
2) Namenskonventionen bei Methoden: set*M*ax, get*M*ax
3) deine setValue()-Methode ist noch etwas umständlich. Besser zB so:

```
@Override
    public void setValueAt(Object aValue, int row, int col)
    {
        // abort if value is out of bounds
        if (aValue instanceof Integer)
        {
          int value = ((Integer)aValue).intValue();
          if(value < 0 || value > max){
              return;
          }
        }
        // save okay here
        super.setValueAt(aValue, row, col);
    }
```


----------



## Scrimau (23. Nov 2009)

Nochmal danke

Final Version:


```
import javax.swing.table.DefaultTableModel;

public class TabelleVerb extends DefaultTableModel{

    private Integer max;

    public void setMax(Integer max)
    {
        this.max=max;
    }

    public Integer getMax()
    {
        return this.max;
    }

    @Override
    public void setValueAt(Object aValue, int row, int col)
    {
        // abort if value is out of bounds
        if (aValue instanceof Integer)
        {
          int value = ((Integer)aValue).intValue();
          if(value < 0 || value > max)
          {
              return;
          }
        }
        // save okay here
        super.setValueAt(aValue, row, col);
    }

    @Override
    public Class getColumnClass(int col)
    {
        if (col==0 || col==1)
        {
            return Integer.class;
        }
        else
        {
            return Double.class;
        }
    }
}
```


----------



## hdi (23. Nov 2009)

nicht ganz final  (Ich will dich nicht stressen, aber solange es noch was zu lernen gibt warum nicht).


```
if (col==0 || col==1)
            return Integer.class;
        else
            return Double.class;
```

sowas ist auch böse, kann leicht zu Fehlern führen. *Immer* einen Block nach if's oder else's machen, auch wenn nur eine einzige Anweisung folgt:

```
if (col==0 || col==1){
    return Integer.class;
}
else{
    return Double.class;
}
```

ein Setter nutzt üblicherweise als Parameternamen den Namen des zu ändernden Attributes:

```
public void setMax(Integer max) // statt "wert"
{
     this.max=max;
}
```
Jetzt macht nämlich auch das "this" Sinn 

...und zu guter letzt: Formatier den Code mal, damit alles schön sauber und gleichmässig eingerückt ist. Wenn du das alles getan hast ist das ne "officially professional class"  ^^


----------



## HannsW (24. Nov 2009)

```
@Override
    public void setValueAt(Object aValue, int row, int col)
    {
        // abort if value is out of bounds
        if (aValue instanceof Integer)
        {
          int value = ((Integer)aValue).intValue();
          if(value < 0 || value > max){
              return;
          }
        }
        // save okay here
        super.setValueAt(aValue, row, col);
    }
 
[/Java]

Mein Problem mit diesem Code :
Es wird garantiert, daß in "Integer-Spalten" nur ints geschriebene werden.
Was aber passiert, wenn ein "IntegerObject" in eine "Double-Spalte" geschrieben werden ?
Werden diese dann automatisch gewandelt?
```


----------



## hdi (24. Nov 2009)

Ja genau, in diesem Fall wird wohl der Integer unboxed, dann wird ein double drausgemacht, und dieser wieder geboxed. Der Wertebereich von Fließkommazahlen enthält ja den von ganzen Zahlen.


----------

