2013-09-25 21 views
5

Devo assegnare una larghezza fissa a poche colonne di un JTable e quindi una larghezza uguale a tutte le altre colonne.Imposta la larghezza della colonna di JTable in percentuale

Supponiamo che uno JTable abbia 5 colonne. La prima colonna dovrebbe avere una larghezza di 100 e la seconda una larghezza di 150. Se la larghezza rimanente di JTable è 600 dopo aver impostato la larghezza delle due colonne, mi piacerebbe dividerla equamente tra le altre tre colonne.

Il problema è table.getParent().getSize().width è spesso 0, anche se è aggiunto allo JFrame e visibile, quindi non posso utilizzarlo come base.

Come faccio a fare questo?

+2

Se una risposta funziona per te, accettalo. – Astrobleme

risposta

3

Penso che sia necessario utilizzare table.getPreferredSize() invece. Prova questo frammento di codice:

import java.awt.Dimension; 
import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SwingUtilities; 
import javax.swing.table.DefaultTableModel; 


public class Tests { 

    private void initGUI(){   
     Object[] tableHeader = new Object[]{"Name", "Category", "Color","Ranking"}; 
     DefaultTableModel dftm = new DefaultTableModel(tableHeader, 0);   
     dftm.addRow(new Object[]{"Watermelon","Fruit","Green and red",3}); 
     dftm.addRow(new Object[]{"Tomato","Vegetable","Red",5}); 
     dftm.addRow(new Object[]{"Carrot","Vegetable","Orange",2}); 

     JTable table = new JTable(dftm); 

     JScrollPane scrollPane = new JScrollPane(); 
     scrollPane.setViewportView(table); 

     Dimension tableSize = table.getPreferredSize(); 
     table.getColumn("Name").setPreferredWidth(100); 
     table.getColumn("Category").setPreferredWidth(150); 
     table.getColumn("Color").setPreferredWidth(Math.round((tableSize.width - 250)* 0.70f)); 
     table.getColumn("Ranking").setPreferredWidth(Math.round((tableSize.width - 250)* 0.30f)); 

     JFrame frame = new JFrame("Demo"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(scrollPane); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new Tests().initGUI(); 
      } 
     });   

    } 
} 

Come vedrete, Name colonna avrà una larghezza di 100, Category avrà una larghezza di 150, Color colonna si adatta al 70% della larghezza rimanente e Ranking si adatta alle ultimo 30%.

Aggiornamento

In base a questo commento:

Grazie, ma questo non funzionerà se la dimensione del JFrame è impostata in modo esplicito più grande della JTable ...

La soluzione può essere utilizzata con i metodi setMinWidth e setMaxWidth per risolvere la larghezza delle colonne statiche oppure è possibile implementare la propria TableColumnModelListener. Nell'esempio sopra sostituire setPreferredWith linee come segue e provare dimensione preferita del frame impostato come desiderate:

final JTable table = new JTable(dftm);   
    table.getColumnModel().addColumnModelListener(new TableColumnModelListener() { 

     @Override 
     public void columnAdded(TableColumnModelEvent e) { 
      table.columnAdded(e); 
     } 

     @Override 
     public void columnRemoved(TableColumnModelEvent e) { 
      table.columnRemoved(e); 
     } 

     @Override 
     public void columnMoved(TableColumnModelEvent e) { 
      table.columnMoved(e); 
     } 

     @Override 
     public void columnMarginChanged(ChangeEvent e) { 
      Dimension tableSize = table.getSize(); 
      table.getColumn("Name").setWidth(100); 
      table.getColumn("Category").setWidth(150); 
      table.getColumn("Color").setWidth(Math.round((tableSize.width - 250)* 0.70f)); 
      table.getColumn("Ranking").setWidth(Math.round((tableSize.width - 250)* 0.30f)); 
     } 

     @Override 
     public void columnSelectionChanged(ListSelectionEvent e) { 
      table.columnSelectionChanged(e); 
     } 
    }); 
+0

Grazie, ma questo non funzionerà se la dimensione del JFrame è impostata esplicitamente più grande della JTable ... –

+1

Vedo il tuo punto. Che ne dici di giocare con i metodi 'setMinWidth' e' setMaxWidth'? Ad esempio per la tua prima colonna puoi chiamare 'setMinWidth (100)' e 'setMaxWidth (100)'. La sua larghezza sarà sempre pari a 100 indipendentemente dalle dimensioni del fotogramma e persino dal ridimensionamento del fotogramma. – dic19

+0

@TomTucker si prega di consultare la risposta aggiornata. – dic19

5

Ho bisogno di assegnare una larghezza fissa per alcune colonne di una JTable e quindi una larghezza uguale a tutti gli altre colonne.

Lascia che la modalità di ridimensionamento della tabella funzioni per te. Impostare la modalità di ridimensionamento per tutte le colonne e impostare i valori min/max delle colonne fisse:

import java.awt.*; 
import javax.swing.*; 
import javax.swing.table.*; 

public class TableLayout extends JPanel 
{ 
    public TableLayout() 
    { 
     setLayout(new BorderLayout()); 

     JTable table = new JTable(5, 7); 
     add(new JScrollPane(table)); 

     table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); 
     TableColumn columnA = table.getColumn("A"); 
     columnA.setMinWidth(100); 
     columnA.setMaxWidth(100); 
     TableColumn columnC = table.getColumn("C"); 
     columnC.setMinWidth(50); 
     columnC.setMaxWidth(50); 
    } 

    private static void createAndShowUI() 
    { 
     JFrame frame = new JFrame("TableLayout"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(new TableLayout()); 
     frame.setSize(600, 200); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      public void run() 
      { 
       createAndShowUI(); 
      } 
     }); 
    } 
} 
+0

+1: 'column.setPreferredWidth()' non funziona quando la modalità di ridimensionamento è 'AUTO_RESIZE_ALL_COLUMNS', quindi' setMin/MaxWidth() 'deve essere usato. – Matthieu

0

ho dovuto impostare dinamicamente larghezza mie colonne della tabella per un progetto che aveva per visualizzare correttamente su diverse impostazioni DPI di risoluzione dello schermo. L'idea della mia soluzione è venuta dalla risposta di dic19s.

Fondamentalmente ho ottenuto la dimensione preferita del JPanel in cui è stato inserito JSrollPane di JTable e funziona perfettamente. Si prega di vedere sotto

Dimension tableSize = tableScrollPanePanel.getPreferredSize(); 
table.getColumnModel().getColumn(0).setPreferredWidth(Math.round(tableSize.width*0.35f)); 
table.getColumnModel().getColumn(1).setPreferredWidth(Math.round(tableSize.width*0.215f)); 
table.getColumnModel().getColumn(2).setPreferredWidth(Math.round(tableSize.width*0.20f)); 
table.getColumnModel().getColumn(3).setPreferredWidth(Math.round(tableSize.width*0.10f)); 
table.getColumnModel().getColumn(4).setPreferredWidth(Math.round(tableSize.width*0.10f)); 

Spero che questo aiuti qualcuno

Grazie

9
public MyJFrame() { 
    initComponents(); 
    resizeColumns(); 
    addComponentListener(new ComponentAdapter() { 
     @Override 
     public void componentResized(ComponentEvent e) { 
      resizeColumns(); 
     } 
    }); 
} 
//SUMS 100% 
float[] columnWidthPercentage = {20.0f, 55.0f, 10.0f, 5.0f, 5.0f, 5.0f}; 

private void resizeColumns() { 
    int tW = jTable1.getWidth(); 
    TableColumn column; 
    TableColumnModel jTableColumnModel = jTable1.getColumnModel(); 
    int cantCols = jTableColumnModel.getColumnCount(); 
    for (int i = 0; i < cantCols; i++) { 
     column = jTableColumnModel.getColumn(i); 
     int pWidth = Math.round(columnWidthPercentage[i] * tW); 
     column.setPreferredWidth(pWidth); 
    } 
} 
+1

Questa è la migliore risposta che ho visto :) –

+0

Nota che puoi usare ['TableColumnModel.getTotalColumnWidth()'] (https://docs.oracle.com/javase/7/docs/api/javax/swing/table /TableColumnModel.html#getTotalColumnWidth()) nel caso in cui la tua tabella sia inclusa in un 'JScrollPane' (che di solito è il caso). – Matthieu

+0

poco tardi alla festa ma columnWidthPercentage dovrebbe aggiungere fino a 1.0, altrimenti la tua tabella crescerà molto velocemente –

0

E pensare che sarebbe più facile da usare (e riutilizzare) componente relativa ridimensionamento se incapsuliamo in una propria classe.Poiché anch'io ho dovuto affrontare lo stesso problema, vorrei pubblicare il mio codice qui.

Dal punto di vista del cliente mi piacerebbe fare qualcosa di simile

TableColumnModel columnModel = jTable.getColumnModel(); 

TableColumn firstColumn = columnModel.getColumn(0); 
TableColumn secondColumn = columnModel.getColumn(1); 

ComponentResize<TableColumn> columnResize = new TableColumnResize(); 
RelativeWidthResizer<TableColumn> relativeWidthResizer = new RelativeWidthResizer<TableColumn>(columnResize); 

relativeWidthResizer.setRelativeWidth(firstColumn, 0.8); 
relativeWidthResizer.setRelativeWidth(secondColumn, 0.2); 

jTable.addComponentListener(relativeWidthResizer); 

Così ho prima definito l'interfaccia ComponentResize e attuare un TableColumnResize

public interface ComponentResize<T> { 
    public void setWidth(T component, int width); 
} 

public class TableColumnResize implements ComponentResize<TableColumn> { 

    public void setWidth(TableColumn component, int width) { 
     component.setPreferredWidth(width); 
    } 
} 

L'interfaccia ComponentResize disaccoppia il modo in cui le dimensioni di un componente è impostato dalle API concrete. Per esempio. un TableColumn 's larghezza può essere impostata tramite setPreferredWidth(int) mentre un JComponent' dimensione s può essere impostata setPreferredWidth(Dimension)

Che ho implementato il RelativeWidthResizer che incapsula la logica di calcolo larghezza relativa.

public class RelativeWidthResizer<T> extends ComponentAdapter { 

    private Map<T, Double> relativeWidths = new HashMap<T, Double>(); 
    private ComponentResize<T> componentResize; 

    public RelativeWidthResizer(ComponentResize<T> componentResize) { 
     this.componentResize = componentResize; 
    } 

    public void setRelativeWidth(T component, double relativeWidth) { 
     if (relativeWidth < 0.0) { 
      throw new IllegalArgumentException(
        "Relative width must be greater or equal to 0.0"); 
     } 

     if (relativeWidth > 1.0) { 
      throw new IllegalArgumentException(
        "Relative width must be less or equal to 1.0"); 
     } 

     double totalRelativeWidth = 0.0; 
     for (Double relativeComponentWidth : relativeWidths.values()) { 
      totalRelativeWidth += relativeComponentWidth.doubleValue(); 
     } 

     double availableRelativeWidth = 1.0d - (totalRelativeWidth + relativeWidth); 

     boolean totalPercentageExceeded = availableRelativeWidth < 0; 
     if (totalPercentageExceeded) { 
      double remainingRelativeWidth = 1.0d - totalRelativeWidth; 
      String message = MessageFormat.format(
        "Can't set component's relative width to {0}." 
          + " {1} relative width remaining", relativeWidth, 
        remainingRelativeWidth); 
      throw new IllegalArgumentException(message); 
     } 

     relativeWidths.put(component, relativeWidth); 
    } 

    @Override 
    public void componentResized(ComponentEvent e) { 
     Component component = e.getComponent(); 
     apply(component); 
    } 

    public void apply(Component baseComponent) { 
     Dimension size = baseComponent.getSize(); 
     int maxWidth = (int) size.getWidth(); 

     int remaining = maxWidth; 

     Set<Entry<T, Double>> entrySet = relativeWidths.entrySet(); 
     Iterator<Entry<T, Double>> entrySetIter = entrySet.iterator(); 

     while (entrySetIter.hasNext()) { 
      Entry<T, Double> componentEntry = entrySetIter.next(); 
      T componentToResize = componentEntry.getKey(); 
      Double relativeWidth = componentEntry.getValue(); 

      int width = (int) (maxWidth * relativeWidth.doubleValue()); 
      remaining -= width; 

      boolean lastComponent = !entrySetIter.hasNext(); 
      if (lastComponent && remaining > 0) { 
       width += remaining; 
      } 
      componentResize.setWidth(componentToResize, width); 
     } 
    } 
}