JTable effektiv angezeigter Text ausgeben nicht Inhalt vom Model

  • Themenstarter Themenstarter Gelöschtes Mitglied 56712
  • Beginndatum Beginndatum
G

Gelöschtes Mitglied 56712

Gast
Guten Abend

Problem:
ich habe eine Spalte Betrag in der JTable.
Wird perfekt formatiert im TableCellRenderer. -> 1'500.00
Im Model steht aber 1500.

Ich bräuchte aber den formatierten Text der Zelle nicht den Eintrag im Model.

Ich habe ein ToolTip geschrieben der mir den Inhalt der Zelle als ToolTip anzeigt, sofern er breiter ist als die Spalte -> [1'500...]
Wenn ich jetzt den Model-Eintrag nehme (1500) dann ist er weniger Breit als die Spalte und wird somit nicht als Hover angezeigt.

Wie kann ich den effektiven formatierten Inhalt der Zelle in einen String laden, der dann als ToolTip angezeigt wird weil breiter als die Spalte.

Die spalte erreiche ich mit: int column = columnModel.getColumnIndexAtX(e.getX());
Die row erreiche ich mit int row = e.getY()/getRowHeight();

Habe es schon mit Component get... versucht und genau da komme ich nicht weiter.

Hat jemand eine Idee wie man an den Zellen-Inhalt, nicht an den Eintrag des Models getValue(row, column) kommt?

Vielen Dank
Richi
 
Prinzipiell sollte es möglich sein, dass Du
1) den TableCellRenderer der JTable holst per JTable.getCellRenderer.
2) Dann kannst Du den TableCellRenderer nutzen um den Wert rendern zu lassen per getTableCellRendererComponent Aufruf.
3) Von der Komponente kannst Du dann getText aufrufen.

Aber wie hast Du denn den Code afgebaut? Du hast die Formatierung doch irgendwo in dem Code und da wirst du ggf. auch direkt ohne diesen Weg den Wert rendern können. oder?
 
Vielen Dank.
RTableCellRenderer tcr = new TableCellRenderer();
1) habe ich so erstellt -> setDefaultRenderer(Object.class, tcr(this));
2) genau da liegt mein Problem. Ich komme nicht an den Component.
Renderer:
Java:
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
//        tab.setColumnIndex(column);
        if(value instanceof Boolean) {
            boolean bool = Boolean.parseBoolean(value.toString());
            CB cb = new CB(tab, bool, row, column);
         
            if(isMarked() && aktRow == row) {
                cb.setBackground(tab.getHoverColor());
            }
            else {
                if(row %2 == 0) {
                    cb.setBackground(tab.getZebraLine());
                }
                else {
                    cb.setBackground(tab.getBgColor());
                }
            }
            return cb;    //new CB(tab, bool, row, column);
        }
     
        setText(value.toString());
        setName("Zelle-"+row+"x"+column);
        setFont(myFont);
        setOpaque(true);
        if(value instanceof Integer) {
          [I]String txt = z1plus.format(Integer.parseInt(value.toString()));[/I]
            setText(txt);
            setHorizontalAlignment(0);
        }
        else {
            setHorizontalAlignment(2);
        }
        if(isMarked() && aktRow == row) {
            setBackground(tab.getHoverColor());
        }
        else {
            if(row %2 == 0) {
                setBackground(tab.getZebraLine());
            }
            else {
                setBackground(tab.getBgColor());
            }
        }
        return this;
    }

Zeile 27 formatiere ich mit new DecimalFormat ("#,##0.0");

3) Wie komme ich jetzt an diese Componente ?

Er bringt mir immer den letzten Spalteninhalt.
 
Nachtrag:
Der TableCellRenderer holt sich die SpaltenInfos aus dem TableModel:
Java:
    @Override
    public Class<?> getColumnClass(int columnIndex) {
        Class<?> cl = null;
        switch(columnIndex) {
        case 7:
            cl = CB.class;
            break;
        default:
            cl = String.class; //throw new UnsupportedOperationException("no such column: " + columnIndex);
        }
        return cl;
    }

auch diese habe ich der JTable hinzugefügt: setModel(new RTableModel(spalten, this))
da kommt je nachdem wie ich es aufrufe entweder null oder eine Exception zurück.

Vielen Dank für Ihre Zeit.
Richi
 
Java:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class TableTest {

    private void createAndShowGui() {
        DefaultTableModel model = new DefaultTableModel(new Object[][] {
                { "Ein sehr, sehr, sehr, sehr langer Zelleninhalt" }
        }, new Object[] { "Text" });

        JTable table = new JTable(model);
       
        JButton button = new JButton("Text anzeigen");
        button.addActionListener(e -> {
            Object valueToRender = table.getModel().getValueAt(0, 0);
            TableCellRenderer renderer = table.getCellRenderer(0, 0);
            JLabel label = (JLabel) renderer.getTableCellRendererComponent(
                    table, valueToRender, false, false, 0, 0);
            String text = label.getText();
            JOptionPane.showMessageDialog(button, text);
        });

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(new JScrollPane(table));
        frame.add(button, BorderLayout.SOUTH);
        frame.setSize(200, 200);
        frame.setVisible(true);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new TableTest().createAndShowGui());
    }
}

Schau Dir den actionListener des Buttons an.
 
Also nur zum Verständnis: Die Schritte 1-3 sind ein universeller Weg, mit dem Du an den formatierten Wert kommen kannst. Also etwas wie:
Java:
    public static String getFormatedValue(JTable table, int row, int column) {
        TableCellRenderer renderer =  table.getCellRenderer(row, column);
        Component component = renderer.getTableCellRendererComponent(table, table.getValueAt(row, column), false, false, row, column);
        if (component instanceof JLabel label) {
            return label.getText();
        }

        return null;
    }
(Hnweis: Das nutzt ein aktuelles JDK. Ich habe gerade nicht im Kopf, ab wann man dem instanceof noch die neue Variable mitgeben kann. Sollte das nicht gehen, weil Du ein ältere JDK nutzt, dann musst Du das separat machen. Das zeige ich weiter unten!)

Aber das ist unnötig. Du hast ja die Formatierung bereits. Das ist ja das z1plus.format - Statt so etwas aufzurufen wie ich da gezeigt habe, kannst Du dies auch einfach selbst machen...

Und bezüglich Deines Codes: Es ist Unnötig, Werte in einen String umzuwandeln und dann zu parsen. Also etwas wie:
Java:
        if(value instanceof Boolean) {
            boolean bool = Boolean.parseBoolean(value.toString());

value ist vom Typ Boolean, also kannst Du da direkt einen cast machen:
Java:
        if(value instanceof Boolean) {
            boolean bool = (Boolean) value;

Bzw. in aktuellen JDKs:
Java:
        if(value instanceof Boolean bool) {
            // hier einfach die Variable bool nutzen
 
Du hast ja die Formatierung bereits. Das ist ja das z1plus.format - Statt so etwas aufzurufen wie ich da gezeigt habe, kannst Du dies auch einfach selbst machen...
Also nur um das noch etwas auszuführen:
Das kann man durchaus noch weiter extrahieren: Du willst die Formatierung des Integer Wertes halt an mehreren Stellen haben. Daher macht es Sinn, das in eine eigene Methode oder gar Klasse zu packen. Also diesen Aufruf von z1plus.format machst Du in eine Methode. Dann hast Du im Renderer und auch an der Stelle, wo Du den formatierten Wert haben willst einfach nur den Aufruf: formatMyCoolInteger(intValue). Damit hast Du das an einer zentralen Stelle. Das verhindert, dass Du im Renderer noch ein z2plus hast, das dann das z1plus ersetzt aber an anderer Stelle hast Du noch z1plus benutzt. Daher eine eigene Methode. Und diese könnte in einer Klasse sein, die dann generell die Visuelle Darstellung der Werte kapselt. Du hast dann also evtl. sowas wie eine Entity klasse und eine EntityFormater Klasse oder so (Über die Namen habe ich jetzt wenig nachgedacht. Die sollten natürlich sinnvoll gewählt werden!)
 
Vielen Dank @KonradN

if(value instanceof Boolean) { boolean bool = Boolean.parseBoolean(value.toString()); }
wenn die Daten z.B. aus einer INI-Datei kommen, kann da alles möglicht (durch den Benutzer händisch geändert) drin stehen.
somit wird der Boolesche wert immer false sein, wenn nicht 1 oder true drin steht.
Darum parse ich es lieber. Wenn die Daten aus eine Datenbank kommen bräuchte ich das nicht aber ich möchte alle möglichkeiten anbieten.

Habe das mit den Formaten so gelösst:
Java:
 public void setFormate(Object[] formate) {

        columnFormate = formate;

    }

// Object[] formate können manuell erstellt oder die Spalten-Infos der Datenbank enthalten

// Fehler werden abgefangen und ggF. null zurückgegeben.


    public String getFormatedInhalt(int column) {

        String str = getValueAt(row, column).toString();

        try {

            f = columnFormate[column];

            if(format instanceof DecimalFormat) {
                DecimalFormat f = (DecimalFormat) format;
                str = f.format(Integer.parseInt(str));
            }
            else if(...){...}    // alle zur verfügung gestellte formate.

            // geht auch in einer Schleife um alle zu holen.
        } catch (Exception e) {}
        return str;
    }
Dieses Problem wäre also gelösst! Vielen Dank nochmals.
 
Zuletzt bearbeitet von einem Moderator:
wenn die Daten z.B. aus einer INI-Datei kommen, kann da alles möglicht (durch den Benutzer händisch geändert) drin stehen.
somit wird der Boolesche wert immer false sein, wenn nicht 1 oder true drin steht.
mit instanceOf prüfst Du den Typ der Variable, Und wenn das ein Boolean ist, dann ist es ein Boolean. Da kann dann nur true oder false drin stehen und nichts anderes (einmal von null abgesehen).

Daher der Hinweis: Der Code macht nichts., außer den bestehenden Boolean in ein String umzuwandeln und dann wieder zu parsen.

Und das ist 1:1 auch bei dem Integer so.

Bei deinem Code: str wird mit null initialisiert und nicht gesetzt, ehe Du Integer.parseInt darauf aufrufst. Aber ich nehme an, dass Du da einfach beim kopieren des Codes etwas vergessen hast...

Das neue Problem kann ich nicht ganz nachvollziehen. Wo ist das genaue Problem? Du hast doch eine Klasse, mit der Du die Datenbank ansprichst und da kannst Du das dann doch handhaben. Also sowohl die Umsetzung von Spaltennamen als auch das Entschlüsseln von Werten.
Wie das im Detail aussehen muss, kann ich - ohne Details zu kennen - natürlich nicht sagen.
 
Bei deinem Code: str wird mit null initialisiert und nicht gesetzt, ehe Du Integer.parseInt darauf aufrufst. Aber ich nehme an, dass Du da einfach beim kopieren des Codes etwas vergessen hast...

Uuups, habe es soeben geändert.

Daher der Hinweis: Der Code macht nichts., außer den bestehenden Boolean in ein String umzuwandeln und dann wieder zu parsen.
Ohh man, da hätte ich selbst drauf kommen können! -> Jetzt passts! (auch bei allen anderen) sowas dummes aber auch.

Vielen Dank @KonradN
Richi

PS.
Das andere Problem habe ich in einen neuen Thread gestellt. Sorry.

Das neue Problem kann ich nicht ganz nachvollziehen. Wo ist das genaue Problem? Du hast doch eine Klasse, mit der Du die Datenbank ansprichst und da kannst Du das dann doch handhaben. Also sowohl die Umsetzung von Spaltennamen als auch das Entschlüsseln von Werten.
Wie das im Detail aussehen muss, kann ich - ohne Details zu kennen - natürlich nicht sagen.

Einfach gefragt wie setzte ich Spaltennamen (werden ja bei new JTable(...) übergeben.
Aber wie überschreibe ich jetzt die Spaltenbezeichnungen? Bis jetzt hat es mir immer die Spaltennamen, auf die ich später zugreife überschrieben... ???
Vielen Dank
 

Neue Themen


Zurück
Oben