Swing JTable Spalten ausblenden?!

ElJarno

Bekanntes Mitglied
Hi Leute,
bisher habe ich Spalten in der JTable dadurch ausgeblendet indem ich die Spaltengröße auf 0 gesetzt habe. Klappt ja so ganz gut, vorallendingen da das später Wiedereinblenden sehr einfach von statten geht und die Daten erhalten bleiben. Jetzt hat sich aber folgendes Problem eingeschlichen. Wenn man nun mit den Pfeiltasten arbeitet springt er in die ausgeblendet Spalte trotzdem rein und ermöglicht sogar die Editierung. Genau das soll nicht geschehen. Jemand ne Idee wie man alternativ Spalten ausblenden kann ohne diese Problem zu haben oder wie man das Spingen in Zelle unterbindet, außer vielleicht die entsprechenden Methoden in der JTable zu überschreiben?

Gruß Jan🙂
 
Ich weiß nicht mehr, woher ich es habe, aber dies hier ist das rundum-sorglos-Paket. Mal von einem gravierenden Rechtschreibfehler abgesehen 😉
(Musste ein paar (unwichtige) Zeilen und Kommentare entfernen)

Anwendungsbeipiel:
Java:
JTable myTable = ...;
HidableTableColumnModel htcm = new HidableTableColumnModel(
    myTable.getColumnModel());

JPopupMenu popup = new JPopupMenu();
for (Action act : htcm.createColumnActions())
{
    popup.add(new JCheckBoxMenuItem(act));
} //for
myTable.setComponentPopupMenu(popup);

Spaltenmodell:
Java:
public class HidableTableColumnModel implements TableColumnModel 
{
    // Attribute
    //----------------------------------------------------------------------------------------------

    protected ArrayList<TableColumn> m_allColumns    = null;
    protected TableColumnModel       m_delegateModel = null;    
    
    // Methoden
    //----------------------------------------------------------------------------------------------

     public HidableTableColumnModel( TableColumnModel delegateModel )
        throws NullPointerException
    {
        super();
        if (delegateModel == null)
            throw new NullPointerException("Cannot have null table column model");
        
        m_delegateModel = delegateModel;
        m_allColumns    = new ArrayList<TableColumn>( m_delegateModel.getColumnCount() );
        
        Enumeration<TableColumn> columns = m_delegateModel.getColumns();
        while (columns.hasMoreElements())
        {
            m_allColumns.add( columns.nextElement() );
        } //while
    } //Konstruktor(TableColumnModel)
    
     public void setColumnVisible( int viewIndex, boolean visible )
    {
        this.setColumnVisible(
                m_allColumns.get(viewIndex),
                visible);
    } //void setColumnVisible(int, boolean)
    
    /**
     * @brief blendet die genannte Spalte aus oder ein
     * 
     * Diese Methode setzt die genannte Spalte auf sichtbar (einblenden) oder
     * unsichtbar (ausblenden), je nach Angabe.<br>
     * Wenn die Spalte nicht in einem der Modelle (dieses und das Basismodell)
     * enthalten ist, geschieht nichts.
     * 
     * @note Listener werden Ereignisse für Spalten-Entfernen und -Hinzufügen
     *       erhalten.
     *       
     * @param column    Spaltenobjekt, das ein-/ausgeblendet werden soll
     * @param visible   Angabe ob die Spalte ein- oder ausgeblendet wird
     */
    public void setColumnVisible( TableColumn column, boolean visible )
    {
        if ( ! visible)
        {
            m_delegateModel.removeColumn(column);
        } //if verbergen
        else
        {
            final int visibleColumns   = m_delegateModel.getColumnCount();
            final int invisibleColumns = m_allColumns.size();
                  int idxVisible       = 0;
            
            for (int idxInvisible = 0; idxInvisible < invisibleColumns; idxInvisible++)
            {
                final TableColumn visibleColumn = ( idxVisible < visibleColumns
                                                  ? m_delegateModel.getColumn(idxVisible)
                                                  : null);
                final TableColumn testColumn    = m_allColumns.get(idxInvisible);
                
                if (testColumn.equals(column))
                {
                    if ( ! column.equals(visibleColumn))
                    {
                        m_delegateModel.addColumn(column);
                        m_delegateModel.moveColumn(
                                m_delegateModel.getColumnCount() -1, 
                                idxVisible);
                    } //if ! sichtbare Spalte
                    return;
                } //if 
                
                if (testColumn.equals(visibleColumn))
                    idxVisible++;
            } //for
        } //if zeigen
    } //void setColumnVisible(TableColumn, boolean)
    
    /**
     * @brief zeigt alle Spalten im Modell an
     * 
     * Diese Methode blendet alle Spalte ein.
     */
    public void setAllColumnsVisible() 
    {
        final int totalSize = m_allColumns.size();
        
        for (int idxColumn = 0; idxColumn < totalSize; idxColumn++)
        {
            final TableColumn visibleColumn = ( idxColumn < m_delegateModel.getColumnCount()
                                              ? m_delegateModel.getColumn(idxColumn)
                                              : null);
            final TableColumn invisibleColumn = m_allColumns.get(idxColumn);
            
            if ( ! invisibleColumn.equals(visibleColumn))
            {
                m_delegateModel.addColumn(invisibleColumn);
                m_delegateModel.moveColumn(
                        m_delegateModel.getColumnCount() -1, 
                        idxColumn);
            } //if ungleich
        } //for
    } //void setAllColumnsVisible() 
    
    /**
     * @brief Getter für Spalte anhand des Modell-Indizes
     * 
     * Ermittelt das Spaltenobjekt aus der Gesamtmenge der Spalten (auch jene, die nicht
     * sichtbar sind), das dem gegebenen Modellindex (vom Tabellenmodell) entspricht.
     * 
     * @param modelIndex    Index des Tabellenmodells der Spalte, die erfragt ist
     * @return              (erste) gefundene Spalte oder <code>null</code>
     */
    public TableColumn getColumnByModelIndex( int modelIndex )
    {
        for (int idxColumn = 0; idxColumn < m_allColumns.size(); idxColumn++)
        {
            final TableColumn column = m_allColumns.get(idxColumn);
            if (column.getModelIndex() == modelIndex)
                return column;
        } //for
        
        return null;
    } //TableColumn getColumnByModelIndex(int)
    
    /**
     * @brief gibt an, ob Spalte sichtbar ist, oder nicht
     * 
     * Diese Methode gibt an, ob die gegebene Spalte sichtbar ist, oder nicht. Sprich
     * ob sie ausgeblendet wurde (in diesem Fall lautet die Rückgabe <code>false</code>).
     * 
     * @param column    Spaltenobjekt
     * @return          <code>true</code> wenn diese Spalte eingeblendet ist
     */
    public boolean isColumnVisible( TableColumn column ) 
    {
        for (int i = 0; i < m_delegateModel.getColumnCount(); i++)
        {
            if (m_delegateModel.getColumn(i).equals(column))
                return true;
        } //for
        
        return false;
    } //boolean isColumnVisible(TableColumn)
    
    /**
     * @brief Getter für Anzahl der Spalten
     * 
     * Gibt an, wie viele Spalten dieses Modell hat. Über den Parameter lässt sich
     * steuern, ob nur die sichtbaren, oder auch die ausgeblendeten Spalten
     * gezählt werden.
     * 
     * @param visibleOnly   wenn <code>true</code>, werden nur die sichtbaren
     *                      Spalten gezählt
     * @return              Anzahl der Spalten, je nach Parameter alle oder nur die
     *                      sichtbaren     
     *
     * @see getColumnCount()                                       
     */
    public int getColumnCount( boolean visibleOnly )
    {
        if (visibleOnly)
            return m_delegateModel.getColumnCount();
        else
            return m_allColumns.size();
    } //int getColumnCount(boolean)
    
    /**
     * @brief gibt eine Aufzählung der Spalten zurück
     * 
     * Diese Methode gibt eine Aufzählung der Spalten des Modells zurück. Über den
     * Parameter lässt sich steuern, ob alle Spalten (<code>= false</code>) oder nur
     * die sichtbaren (<code>= true</code>) angegeben werden sollen.<br>
     * Bei <code>true</code> wird das delegierte Modell befragt.
     * 
     * @param visibleOnly   wenn <code>true</code>, werden nur die sichtbaren
     *                      Spalten zurückgegeben
     * @return              Aufzählung über die Spalten, je nach Parameter alle oder nur die
     *                      sichtbaren     
     *
     * @see getColumns()                                       
     */
    public Enumeration<TableColumn> getColumns( boolean visibleOnly )
    {
        if (visibleOnly)
        {
            return m_delegateModel.getColumns();
        } //if sichtbare
        else
        {
            return new Enumeration<TableColumn>()
            {
                private int m_index = 0;
                
                @Override
                public TableColumn nextElement()
                {
                    return m_allColumns.get(m_index++);
                } //TableColumn nextElement()
            
                @Override
                public boolean hasMoreElements()
                {
                    return (m_index < m_allColumns.size());
                } //boolean hasMoreElements()
            };
        } //if alle
    } //Enumeration<TableColumn> getColumns(boolean)
    
    /**
     * @brief Getter für Index der ersten Spalte mit gegebenen
     *        Identifikator
     *        
     * Diese Methode ermittelt den (Anzeige-)Index der ersten Spalte mit dem
     * gegebenen Identifikator. Es wird über die <code>equals()</code>-Methode
     * verglichen.<br>
     * Über den zweiten Parameter kann man steuern, ob nur alle sichtbaren oder auch
     * die ausgeblendeten Spalten geprüft werden.
     * 
     * @param identifier    Identifikations-Objekt der gesuchten Spalte  
     * @param visibleOnly   Angabe ob nur die sichtbaren Spalten durchsucht werden
     * @return              Index der gefundenen Spalte oder eine Ausnahme
     * 
     * @throws IllegalArgumentException
     *  Wenn der Identifikator <code>null</code> ist, oder keine Spalte mit
     *  dem gegebenen Identifikator gefunden wurde.
     *  
     * @see getColumnIndex(Object) 
     */
    public int getColumnIndex( Object identifier, boolean visibleOnly )
        throws IllegalArgumentException
    {
        if (identifier == null)
            throw new IllegalArgumentException("Identifiert cannot be null");
        
        Enumeration<TableColumn> columns = this.getColumns(visibleOnly);
        int                      index   = 0;
        
        while (columns.hasMoreElements())
        {
            final Object id = columns.nextElement().getIdentifier();
            if (identifier.equals(id))
                return index;
            
            index++;
        } //while
        
        throw new IllegalArgumentException("Identifier "+identifier+" not found");
    } //int getColumnIndex(Object, boolean)

    /**
     * @brief Getter für Spalte am Index
     * 
     * Diese Methode ermittelt die Spalte am gegebenen (Anzeige-)Index. Über den
     * zweiten Parameter lässt sich steuern, ob alle sichtbaren oder auch die
     * ausgeblendeten Spalten betrachtet werden.
     * 
     * @param columnIndex   Index der gesuchten Spalte. Der Index entspricht dem
     *                      Anzeigeindex in der Tabelle
     * @param visibleOnly   Angabe ob nur sichtbare Spalten geprüft werden
     * @return              gefundene Spalte
     * 
     * @exception IndexOutOfBoundsException
     *  Wenn der gegeben Index außerhalb des gültigen Bereichs liegt.
     *  
     * @see getColumn(int)
     */
    public TableColumn getColumn( int columnIndex, boolean visibleOnly ) 
    {
        if (visibleOnly)
            return m_delegateModel.getColumn(columnIndex);
        else
            return m_allColumns.get(columnIndex);
    } //TableColumn getColumn(int, boolean)

    /**
     * @brief Methode für bequeme Aktionen
     * 
     * Diese Methode erstellt (bei jedem Aufruf neu) eine Menge von Aktionen, die für jede
     * der gesetzen Spalten (auch unsichtbare) eine selektierte Aktion darstellt, um
     * sie ein- und auszublenden:
     * @code
     *  HidableTableColumnModel cModel  = ...;
     *  JPopupMenu              popup   = new JPopupMenu("Hide Menu");
     *  Action[]                actions = cModel.createColumnActions();
     *  for (Action act : actions)
     *  {
     *      popup.add(new JCheckBoxMenuItem(act));
     *  } //for
     *  myTable.setComponentPopupMenu(popup);
     * @endcode
     * 
     * @note Die Aktionen sind <i>nicht</i> serialisierbar!
     * 
     * @return  Feld mit Aktionen, pro Spalte eine eigene
     */
    @SuppressWarnings("serial")
    public Action[] createColumnActions()
    {
        final Action[] actions = new Action[ m_allColumns.size() ];
        
        for (int i = 0; i < m_allColumns.size(); i++)
        {
            final TableColumn col = m_allColumns.get(i);
            final Action      act = new AbstractAction()
            {
                final private TableColumn internalColumn = col;
                
                {
                    this.putValue(
                            SELECTED_KEY, 
                            HidableTableColumnModel.this.isColumnVisible(col));
                    this.putValue(NAME, 
                            col.getHeaderValue());
                }
                
                @Override
                public void actionPerformed( ActionEvent event )
                {
                    HidableTableColumnModel.this.setColumnVisible(
                            internalColumn,
                            ((Boolean) this.getValue(SELECTED_KEY)).booleanValue());
                } //void actionPerformed(ActionEvent)
            };
            
            actions[i] = act;
        } //for
        
        return actions;
    } //Action[] createColumnActions()
    

    // Table Column Model Methoden
    //----------------------------------------------------------------------------------------------

    /**
     * @brief fügt neue Spalte hinzu
     * 
     * Diese Methode fügt die gegebene Spalte dem Modell an letzter Stelle hinzu.
     * 
     * @param column    neues Spaltenobjekt
     */
    @Override
    public void addColumn( TableColumn column ) 
    {
        m_allColumns.add(column);
        m_delegateModel.addColumn(column);
    } //void addColumn(TableColumn)

    /**
     * @brief entfernt die Spalte aus dem Modell
     * 
     * Diese Methode entfernt die gegebene Spalte aus dem Modell.
     * 
     * @param column    zu entfernende Spalte
     */
    @Override
    public void removeColumn( TableColumn column ) 
    {
        m_allColumns.remove(column);
        m_delegateModel.removeColumn(column);
    } //void removeColumn(TableColumn)
    
    /**
     * @brief verschiebt Spalte innerhalb der Tabelle
     * 
     * Diese Methode verschiebt die Spalte an Stelle <code>oldIndex</code> nach
     * <code>newIndex</code>. Verwendet werden hier die Anzeigeindizes.
     * 
     * @param oldIndex  Anzeigeindex der Spalte, die verschoben werden soll
     * @param newIndex  Anzeigeindex des Ortes, an den die Spalte verschoben
     *                  wird
     *                  
     * @throws IllegalArgumentException
     *  Wenn einer der Indizes nicht im gültigen bereich liegt.                  
     */
    @Override
    public void moveColumn( int oldIndex, int newIndex )
        throws IndexOutOfBoundsException
    {
        final int size = m_delegateModel.getColumnCount();
        if (   oldIndex < 0 || oldIndex >= size
            || newIndex < 0 || newIndex >= size)
        {
            throw new IndexOutOfBoundsException(
                    "At least one index is invalid: '"
                   +oldIndex
                   +"' or '"
                   +newIndex
                   +"' (valid range is [0, "
                   +size
                   +"])");
        } //if Fehler
        
        final TableColumn oldColumn = m_delegateModel.getColumn(oldIndex);
        final TableColumn newColumn = m_delegateModel.getColumn(newIndex);
        final int         idxOld    = m_allColumns.indexOf(oldColumn);
        final int         idxNew    = m_allColumns.indexOf(newColumn);
        
        if (oldIndex != newIndex)
        {
            m_allColumns.remove(idxOld);
            m_allColumns.add(idxNew, oldColumn);
        } //if
        
        m_delegateModel.moveColumn(oldIndex, newIndex);
    } //void moveColumn(int, int)

    /**
     * @brief fügt Listener hinzu
     * 
     * Der Listener wird an das delegierte Modell hinzugefügt.
     * 
     * @param listener  neuer Listener
     */
    @Override
    public void addColumnModelListener( TableColumnModelListener listener )
    {
        m_delegateModel.addColumnModelListener(listener);
    } //void addColumnModelListener(TableColumnModelListener)

    /**
     * @brief entfernt Listener
     * 
     * Der Listener wird vom delegierten Modell entfernt.
     * 
     * @param listener  Listener der entfernt wird
     */
    @Override
    public void removeColumnModelListener( TableColumnModelListener listener )
    {
        m_delegateModel.removeColumnModelListener(listener);
    } //void removeColumnModelListener(TableColumnModelListener)

    /**
     * @brief Getter für Spalte am gegebenen Index
     * 
     * Diese Methode ermittelt die Spalte am gegeben Index. Verwendet werden
     * nur sichtbare Spalten.
     * 
     * @param columnIndex   Index der gesuchten Spalte. Verwendet wird hier
     *                      der Anzeigeindex der Tabelle.
     * @return              gefundene Spalte
     * 
     * @exception IndexOutOfBoundsException
     *  Wenn der gegeben Index außerhalb des gültigen Bereichs liegt.
     *  
     * @see getColumn(int, boolean)
     */
    @Override
    public TableColumn getColumn( int columnIndex )
    {
        return this.getColumn(columnIndex, true);
    } //TableColumn getColumn(int)

    /**
     * @brief Getter für Spaltenzahl
     * 
     * Gibt die Anzahl der sichtbaren (!) Spalten zurück.
     * @return  Anzahl der sichtbaren Spalten
     * 
     * @see getColumnCount(boolean)
     */
    @Override
    public int getColumnCount()
    {
        return this.getColumnCount(true);
    } //int getColumnCount()

    /**
     * @brief ermittelt Index der Spalte durch Identifikator
     * 
     * Diese Methode ermittelt den Index der Spalte über alle sichtbaren
     * Spalten. Dazu wird intern #getColumnIndex(Object, boolean) verwendet.
     * 
     * @param identifier    Identifikations-Objekt der gesuchten Spalte  
     * @return              Index der gefundenen Spalte oder eine Ausnahme
     * 
     * @throws IllegalArgumentException
     *  Wenn der Identifikator <code>null</code> ist, oder keine Spalte mit
     *  dem gegebenen Identifikator gefunden wurde.
     *  
     * @see getColumnIndex(Object, boolean) 
     */
    @Override
    public int getColumnIndex( Object identifier ) throws IllegalArgumentException
    {
        return this.getColumnIndex(identifier, true);
    } //int getColumnIndexObject)

    /**
     * @brief Getter für Spalte an X-Position
     * 
     * Diese Methode ermittelt über das delegierte Modell den Spaltenindex
     * an der gegebenen X-Position.
     * 
     * @param position  erfragte X-Position, meist Pixelwerte
     * @return          Index der Spalte an der Position
     */
    @Override
    public int getColumnIndexAtX( int position )
    {
        return m_delegateModel.getColumnIndexAtX(position);
    } //int getColumnIndexAtX(int)

    /**
     * @brief Getter für Spaltenabstand
     * 
     * Gibt den Abstand der Spalten zurück. Dies wird vom delegierten
     * Modell verwaltet.
     * 
     * @return  Abstand der Spalten in Pixeln
     * 
     * @see setColumnMargin(int)
     */
    @Override
    public int getColumnMargin()
    {
        return m_delegateModel.getColumnMargin();
    } //int getColumnMargin()

    /**
     * @brief gibt an, ob Spaltenselektion erlaubt ist
     * 
     * Diese Methode gibt zurück, ob die Selektion ganzer
     * Spalten erlaubt ist, oder nicht.
     * 
     * @return  <code>true</code> wenn Spaltenselektion erlaubt ist
     * 
     * @see setColumnSelectionAllowed(boolean)
     */
    @Override
    public boolean getColumnSelectionAllowed()
    {
        return m_delegateModel.getColumnSelectionAllowed();
    } //boolean getColumnSelectionAllowed()

    /**
     * @brief Getter für alle Spalten
     * 
     * Diese Methode gibt eine Aufzählung über alle sichtbaren
     * Spalten zurück.
     * 
     * @return  Aufzählung mit allen sichtbaren Spalten
     * 
     * @see getColumns(boolean)
     */
    @Override
    public Enumeration<TableColumn> getColumns()
    {
        return this.getColumns(true);
    } //Enumeration<TableColumn> getColumns()

    /**
     * @brief ermittelt die Anzahl der selektierten Spalten
     * 
     * Ermittelt die Anzahl der selektierten Spalten über das 
     * delegierte Modell.
     * 
     * @return Anzahl selektierter Spalten
     */
    @Override
    public int getSelectedColumnCount()
    {
        return m_delegateModel.getSelectedColumnCount();
    } //int getSelectedColumnCount()

    /**
     * @brief ermittelt Indizes der selektierten Spalten
     * 
     * Diese Methode ermittelt die Indizes der selektierten
     * Spalten über das delegierte Modell.
     * 
     * @return  Feld mit den Indizes der selektierten Spalten, oder
     *          leeres Array 
     */
    @Override
    public int[] getSelectedColumns()
    {
        return m_delegateModel.getSelectedColumns();
    } //int[] getSelectedColumns()

    /**
     * @brief Getter für Selektionsmodell
     * 
     * Gibt das Selektionsmodell der delegierten Modells zurück.
     * 
     * @return  Selektionsmodell
     */
    @Override
    public ListSelectionModel getSelectionModel()
    {
        return m_delegateModel.getSelectionModel();
    } //ListSelectionModel getSelectionModel()

    /**
     * @brief ermittelt vollständige Breite der Spalten
     * 
     * Diese Methode ermittelt (über das delegierte Modell) die vollständige
     * Breite der Spalten in Pixeln.
     * 
     * @return  Breite aller (sichtbaren) Spalten in Pixeln
     */
    @Override
    public int getTotalColumnWidth()
    {
        return m_delegateModel.getTotalColumnWidth();
    } //int getTotalColumnWidth()

    /**
     * @brief Setter für Spaltenabstand
     * 
     * Übernimmt den neuen Spaltenabstand in Pixeln, welcher an das 
     * delegierte Modell weitergetragen wird.
     * 
     * @param newMargin neuer Spaltenabstand
     * 
     * @see getColumnMargin()
     */
    @Override
    public void setColumnMargin( int newMargin )
    {
        m_delegateModel.setColumnMargin(newMargin);
    } //void setColumnMargin(int)

    /**
     * @brief erlaubt/verbietet Spaltenselektion
     * 
     * Über diese Methode kann man die Selektion ganzer Spalten
     * erlauben, bzw. verbieten.
     * 
     * @param flag  Angabe ob Selektion erlaubt ist, oder nicht
     * 
     * @see getColumnSelectionAllowed()
     */
    @Override
    public void setColumnSelectionAllowed( boolean flag )
    {
        m_delegateModel.setColumnSelectionAllowed(flag);
    } //void setColumnSelectionAllowed(boolean)

    /**
     * @brief Setter für Selektionsmodell
     * 
     * Übernimmt das neue Selektionsmodell für das delegierte Spaltenmodell.
     * 
     * @param model neues Selektionsmodell
     * 
     * @see getSelectionModel()
     */
    @Override
    public void setSelectionModel( ListSelectionModel model )
    {
        m_delegateModel.setSelectionModel(model);
    } //void setSelectionModel(ListSelectionModel)
    
} //class HidableTableColumnModel
 
So habs mal grad nedlich getestet.
Wahnsinss dingen genau so hab ich mir das vorgestellt. Wollte sowas jetzt erst selbers schreiben. Is halt wie beim Windows Explorer. Ganz dicker Gruß und Danke. Werd mir jetzt erst mal den Code reinziehen.

Gruß Jan🙂
 

Neue Themen


Zurück
Oben