2013-09-25 18 views
5

Muszę przypisać stałą szerokość do kilku kolumn JTable, a następnie równą szerokość do wszystkich pozostałych kolumn.Ustaw szerokość kolumny JTable według wartości procentowej

Załóżmy, że JTable ma 5 kolumn. Pierwsza kolumna powinna mieć szerokość 100, a druga szerokość 150. Jeśli pozostała szerokość JTable wynosi 600 po ustawieniu szerokości dwóch kolumn, chciałbym równomiernie podzielić ją między pozostałe trzy kolumny.

Problem to table.getParent().getSize().width jest często 0, nawet jeśli jest dodany do JFrame i widoczny, więc nie mogę go użyć jako podstawy.

Jak mam to zrobić?

+2

Jeśli odpowiedź dotyczy u, zaakceptuj to. – Astrobleme

Odpowiedz

3

Myślę, że trzeba użyć zamiast tego table.getPreferredSize(). Spróbuj ten fragment kodu:

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(); 
      } 
     });   

    } 
} 

Jak zobaczysz, Name kolumna będzie mieć szerokość 100, Category będzie mieć szerokość 150, Color kolumna zmieści się w 70% szerokości remanentnej i Ranking zmieści się ostatnie 30%.

Aktualizacja

Na podstawie tego komentarza:

Dzięki, ale to nie będzie działać, jeśli rozmiar JFrame ustawiony jest wyraźnie większy niż JTable ...

Rozwiązanie może być odtwarzane za pomocą metod ustalania szerokości kolumn statycznych za pomocą metod setMinWidth i setMaxWidth. Można także zaimplementować własne TableColumnModelListener. W powyższym przykładzie zastąpić setPreferredWith linie w następujący sposób i spróbować frame set preferowany rozmiar, jak chcesz:

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

Dzięki, ale to nie zadziała, jeśli rozmiar JFrame jest ustawiony wyraźnie większy niż JTable ... –

+1

Widzę twój punkt widzenia. A co z odtwarzaniem metod 'setMinWidth' i' setMaxWidth'? Na przykład dla twojej pierwszej kolumny możesz nazwać 'setMinWidth (100)' i 'setMaxWidth (100)'. Jego szerokość zawsze wynosi 100 niezależnie od rozmiaru ramki, a nawet rozmiaru ramki. – dic19

+0

@TomTucker zobacz zaktualizowaną odpowiedź. – dic19

5

muszę przypisać stałej szerokości do kilku kolumnach JTable a potem równej szerokości do wszystkich inne kolumny.

Pozwól, aby tryb zmiany rozmiaru stołu wykonał pracę za Ciebie. Ustaw tryb zmiany rozmiaru do wszystkich kolumn i ustawić min/max wartości stałych kolumn:

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()' nie działa, gdy tryb zmiany rozmiaru ma wartość 'AUTO_RESIZE_ALL_COLUMNS', więc' setMin/MaxWidth() 'muszą być użyte. – Matthieu

0

musiałem dynamicznie ustawić moje kolumny tabeli szerokość dla projektu, który musiał poprawnie wyświetlane na różnych rozdzielczości ekranu ustawień DPI. Pomysł na moje rozwiązanie pochodzi od odpowiedzi dic19s.

Zasadniczo otrzymałem preferowany rozmiar JPanel, w którym umieszczony został JSrollPane JTable i działa świetnie. Poniżej znajdują

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)); 

nadzieję, że to pomoże komuś

Dzięki

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

To jest najlepsza odpowiedź, jaką widziałem :) –

+0

Zauważ, że możesz użyć ['TableColumnModel.getTotalColumnWidth()'] (https://docs.oracle.com/javase/7/docs/api/javax/swing/table /TableColumnModel.html#getTotalColumnWidth()) w przypadku, gdy twoja tabela jest zawarta w 'JScrollPane' (co zwykle ma miejsce). – Matthieu

+0

trochę spóźniony na imprezę, ale columnWidthPercentage powinien dodać do 1,0, w przeciwnym razie stolik będzie rósł bardzo szybko –

0

To, że byłoby łatwiejsze w użyciu (i re-use) względną komponent zmiany rozmiaru jeśli ująć go w rękę klasa.Ponieważ również spotkałem się z tym samym problemem, chciałbym opublikować tutaj mój kod.

Z punktu widzenia klienta, chciałbym zrobić coś takiego

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); 

Więc pierwszy zdefiniowany interfejs ComponentResize i realizuje 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); 
    } 
} 

Interfejs ComponentResize oddziela drogę Rozmiar A komponentu ustawia się z konkretnych interfejsów API. Na przykład. TableColumn „szerokość S może być ustawiany za pomocą setPreferredWidth(int) podczas JComponent” rozmiar S może być ustalone przez setPreferredWidth(Dimension)

niż I wdrożone RelativeWidthResizer która zamyka względnej logikę obliczeniową szerokości.

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); 
     } 
    } 
} 
Powiązane problemy