2010-03-30 11 views
9

Quelle est la meilleure façon de configurer une table dans un JScrollPane de telle sorte que la première colonne soit toujours à l'écran dans la même position indépendamment des colonnes de défilement horizontal et de chevauchement qui passent dessous? Lorsque la barre de défilement est à l'extrême gauche, les colonnes semblent normales, mais lorsque l'utilisateur fait défiler vers la droite, les colonnes secondaires (2 et suivantes) se déplacent sous la première jusqu'à ce que la dernière colonne apparaisse à l'extrême droite de l'écran. viewport?Comment créer une JTable où la première colonne est toujours dans la fenêtre JScrollPane?

J'ai trouvé un échantillon tiré du livre "Java Swing" d'Eckstein qui fait cela, mais il ne permet pas le redimensionnement de la première colonne. Je pensais à un schéma où un JPanel tenait une structure horizontale et une table contenant les colonnes secondaires et un autre JPanel qui flottait sur eux (fixe indépendamment du défilement). La structure consisterait à maintenir la plage de la fenêtre pendant que la première colonne flottait. Idéalement, je pourrais le faire avec deux tables utilisant le même modèle, mais je ne suis pas sûr si l'idée est une solution naïve. Je voudrais idéalement une configuration où plusieurs tables sont verticalement sur le même scrollpane, où toutes leurs premières colonnes sont alignées et se déplacent ensemble et il y a juste peu d'espaces horizontaux entre les tables individuelles.

Répondre

12

Fixed Column Table fait la plupart de ce dont vous avez besoin.

Il ne vous supporte pas le redimensionnement de la colonne fixe donc besoin d'ajouter du code comme:

MouseAdapter ma = new MouseAdapter() 
{ 
    TableColumn column; 
    int columnWidth; 
    int pressedX; 

    public void mousePressed(MouseEvent e) 
    { 
     JTableHeader header = (JTableHeader)e.getComponent(); 
     TableColumnModel tcm = header.getColumnModel(); 
     int columnIndex = tcm.getColumnIndexAtX(e.getX()); 
     Cursor cursor = header.getCursor(); 

     if (columnIndex == tcm.getColumnCount() - 1 
     && cursor == Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR)) 
     { 
      column = tcm.getColumn(columnIndex); 
      columnWidth = column.getWidth(); 
      pressedX = e.getX(); 
      header.addMouseMotionListener(this); 
     } 
    } 

    public void mouseReleased(MouseEvent e) 
    { 
     JTableHeader header = (JTableHeader)e.getComponent(); 
     header.removeMouseMotionListener(this); 
    } 

    public void mouseDragged(MouseEvent e) 
    { 
     int width = columnWidth - pressedX + e.getX(); 
     column.setPreferredWidth(width); 
     JTableHeader header = (JTableHeader)e.getComponent(); 
     JTable table = header.getTable(); 
     table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
     JScrollPane scrollPane = (JScrollPane)table.getParent().getParent(); 
     scrollPane.revalidate(); 
    } 
}; 

JTable fixed = fixedColumnTable.getFixedTable(); 
fixed.getTableHeader().addMouseListener(ma); 
+0

MGRH, je pensais à ma question d'être plus obscure pour obtenir une réponse rapidement. Cela devrait fonctionner extrêmement bien. Je vais essayer avec le code de colonnes redimensionnable que vous avez fourni. Merci. – voodoogiant

1

Je pense que vous êtes sur la bonne voie. Ce que vous avez conceptuellement est une table avec une «colonne d'en-tête» pour chaque rangée. J'utiliserais deux tables - l'une a la colonne 'leftmost' et l'autre a toutes les autres. Ensuite, je les présenterais dans un JSplitPane avec la table 'leftmost column' sur la gauche et le reste sur la droite. Il y aurait une seule barre de défilement verticale contrôlant le décalage y des deux tables et une seule barre de défilement horizontale contrôlant le volet droit (uniquement).

Vous pouvez également utiliser les fonctions avancées de JScrollPane pour définir un composant 'en-tête' à gauche de la zone de défilement principale. Je ne l'ai jamais fait, mais vous pourrez peut-être l'utiliser comme «en-tête» de vos lignes.

4

JScrollPane a une superficie spécifiquement pour cela, l'en-tête de ligne (voir le diagramme dans le API :)

Tout ce que vous devez faire est: - créer un JTable supplémentaire pour cette zone fixe - le raccorder à la première colonne de votre modèle de données - définir comme l'en-tête de la ligne - et dans le tableau principal omettent ou supprimer la première colonne de données.

Lorsque le panneau de défilement défile vers le haut et vers le bas, les deux tables défilent en synchronisation sans ajout de code. Lorsque le scrollpane défile horizontalement, l'en-tête de ligne reste toujours visible et seule la table principale défile.

Pour la plupart des cas, le seul code ajouté dont vous aurez besoin est le redimensionnement de la colonne, comme l'exemple de camickr.

2

Vérifiez cette classe, extraite de http://fahdshariff.blogspot.sg/2010/02/freezing-columns-in-jtable.html

import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.JViewport; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.JTableHeader; 
import javax.swing.table.TableModel; 
public class FrozenTablePane extends JScrollPane{  
    public FrozenTablePane(JTable table, int colsToFreeze){  
     super(table);  
     TableModel model = table.getModel();  
     //create a frozen model  
     TableModel frozenModel = new DefaultTableModel(         
       model.getRowCount(),         
       colsToFreeze);  
     //populate the frozen model  
     for (int i = 0; i < model.getRowCount(); i++) {  
      for (int j = 0; j < colsToFreeze; j++) {   
       String value = (String) model.getValueAt(i, j);   
       frozenModel.setValueAt(value, i, j);  
      }  
     } 
    //create frozen table 
    JTable frozenTable = new JTable(frozenModel); 
    //remove the frozen columns from the original table 
    for (int j = 0; j < colsToFreeze; j++) { 
    table.removeColumn(table.getColumnModel().getColumn(0)); 
    }  table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 
    //format the frozen table  
    JTableHeader header = table.getTableHeader();  
    frozenTable.setBackground(header.getBackground());  
    frozenTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);  
    frozenTable.setEnabled(false);  
    //set frozen table as row header view 
    JViewport viewport = new JViewport();  
    viewport.setView(frozenTable); 
    viewport.setPreferredSize(frozenTable.getPreferredSize()); 
    setRowHeaderView(viewport); 
    setCorner(JScrollPane.UPPER_LEFT_CORNER, 
      frozenTable.getTableHeader()); 
    } 
} 

Par la suite, il suffit d'appeler la méthode constructeur:

JTable table = new JTable(<yourData>, <yourColumns>); 
FrozenTablePane frozenPane = new FrozenTablePane(table,1);//where 1 is the number of freezed column(s)