2016-12-14 18 views
2

Как получить многострочный заголовок JTable, где колонка заголовка правильно увеличивается, чтобы соответствовать некоторому тексту, а затем обертывается в новую строку?Оболочка заголовка JTable для многострочного заголовка (пользовательский TableCellRenderer)

Что-то, как показано ниже:

wrapping column header

В настоящее время в поисках вышеуказанных требований возвращает много решений, которые никто на самом деле не решает проблему:

http://www.javarichclient.com/multiline-column-header/

Creating multi-line header for JTable

Java JTable header word wrap

Вышеуказанные решения все предлагают использовать HTML код, например:

String[] columnNames = { 
    "<html><center>Closing<br>Date</html>", 
    "<html><center>Open<br>Price</html>", 
    "<html>Third<br>column</html>" 
}; 

Это решение не является элегантным в течение нескольких причин, в основном потому, что в случае имен переменных столбцов Мне нужно передать строку функция, которая разделяет пробелы и подтачивает их символами <br>, однако, если текст столбца содержит очень короткий текст, который появляется в отдельной строке.

Мне нужно будет решить минимальную и максимальную длину столбца, а затем иметь возможность сделать центрирование текста возможным, вышеупомянутое решение быстро становится перегруженным и неуправляемым.

http://www.java2s.com/Code/Java/Swing-Components/MultiLineHeaderTable.htm

http://www.java2s.com/Code/Java/Swing-Components/MultiLineHeaderExample.htm

multilineheader2

выше решения требуют ручного создания массива заголовка со словами уже правильно распались как в:

public static Object[][] tableHeaders = new Object[][] { 
     new String[] { "Currency" }, 
     new String[] { "Yesterday's", "Rate" }, 
     new String[] { "Today's", "Rate" }, 
     new String[] { "Rate", "Change" } }; 

-или-

DefaultTableModel dm = new DefaultTableModel(); 
    dm.setDataVector(
     new Object[][] { { "a", "b", "c" }, { "A", "B", "C" } }, 
     new Object[] { "1st\nalpha", "2nd\nbeta", "3rd\ngamma" }); 

Все еще не изящно, потому что переменный текст в именах столбцов был бы невозможен.

How to change JTable header height?

Ручная настройка высоты заголовка, как в приведенных выше решений составляет лишь половину того, что я хочу сделать, потому что тогда текст будет по-прежнему не правильно завернуть и решить высоту до сих пор не представляется возможным.

В настоящее время все, что я был в состоянии было создать пользовательский TableCellRenderer, но еще не решения:

import java.awt.Component; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.TableCellRenderer; 
import javax.swing.table.TableColumn; 

import java.util.*; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.StringReader; 
import javax.swing.*; 
import javax.swing.table.*; 

/** 
* @version 1.0 11/09/98 
*/ 
public class MultiLineHeaderExample extends JFrame 
{ 

    MultiLineHeaderExample() 
    { 
     super("Multi-Line Header Example"); 

     DefaultTableModel dm = new DefaultTableModel(); 
     dm.setDataVector(new Object[][] 
     { 
      { 
       "a", "b", "c" 
      }, 
      { 
       "A", "B", "C" 
      } 
     }, 
     new Object[] 
       { 
        "My First Column, Very Long But Space Separated", "short col", "VeryLongNoSpaceSoShouldSomeHowWrap" 
     }); 

     JTable table = new JTable(dm); 
     MultiLineHeaderRenderer renderer = new MultiLineHeaderRenderer(); 
     Enumeration enumK = table.getColumnModel().getColumns(); 
     while (enumK.hasMoreElements()) 
     { 
      ((TableColumn) enumK.nextElement()).setHeaderRenderer(renderer); 
     } 
     JScrollPane scroll = new JScrollPane(table); 
     getContentPane().add(scroll); 
     setSize(400, 110); 
     setVisible(true); 
    } 

    public static void main(String[] args) 
    { 
     MultiLineHeaderExample frame = new MultiLineHeaderExample(); 
     frame.addWindowListener(new WindowAdapter() 
     { 
      public void windowClosing(WindowEvent e) 
      { 
       System.exit(0); 
      } 
     }); 
    } 
} 

class MultiLineHeaderRenderer extends JList implements TableCellRenderer 
{ 

    public MultiLineHeaderRenderer() 
    { 
     ListCellRenderer renderer = getCellRenderer(); 
     ((JLabel) renderer).setHorizontalAlignment(JLabel.CENTER); 
     setCellRenderer(renderer); 
    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, 
      boolean isSelected, boolean hasFocus, int row, int column) 
    { 
     setFont(table.getFont()); 
     String str = (value == null) ? "" : value.toString(); 
     BufferedReader br = new BufferedReader(new StringReader(str)); 
     String line; 
     Vector v = new Vector(); 
     try 
     { 
      while ((line = br.readLine()) != null) 
      { 
       v.addElement(line); 
      } 
     } 
     catch (IOException ex) 
     { 
      ex.printStackTrace(); 
     } 
     setListData(v); 
     return this; 
    } 
} 

ответ

4

Это здесь также использует JTextArea, а также изменяет высоту заголовка, когда таблица изменяется.Ключ к правильному расчету высоты заголовка таблицы setSize(width, getPreferredSize().height);

class MultiLineTableHeaderRenderer extends JTextArea implements TableCellRenderer 
{ 
    public MultiLineTableHeaderRenderer() { 
    setEditable(false); 
    setLineWrap(true); 
    setOpaque(false); 
    setFocusable(false); 
    setWrapStyleWord(true); 
    LookAndFeel.installBorder(this, "TableHeader.cellBorder"); 
    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { 
    int width = table.getColumnModel().getColumn(column).getWidth(); 
    setText((String)value); 
    setSize(width, getPreferredSize().height); 
    return this; 
    } 
} 
+0

прекрасно работает, только проблема в том, что она использует JTextArea для отображения текста в заголовке, так что столбцы заголовка укладки будут потеряны например, используется белый фон. –

+0

Я отредактировал answear, чтобы заголовок выглядел как заголовок по умолчанию 'JTable'. – Stefan

+0

@ sarah.ferguson Попробуйте установить фон JTextArea на 'JTable.getBackground()'. –

2

вам нужен Conponent, который способен перенос слов его содержания, как JTextArea. Я изменил визуализатор ячеек из вашего SSCCE, так что это изначально работает, но он имеет неприятное изменение размера.

class MultiLineHeaderRenderer extends JTextArea implements TableCellRenderer { 
    public MultiLineHeaderRenderer() 
    { 
     setAlignmentY(JLabel.CENTER); 
     setLineWrap(true); 
     setWrapStyleWord(true); 
     setBorder(BorderFactory.createCompoundBorder(
       BorderFactory.createLineBorder(Color.BLACK), 
       BorderFactory.createEmptyBorder(3,3,3,3) 
       )); 

    } 

    @Override 
    public Component getTableCellRendererComponent(JTable table, 
      Object value, 
      boolean isSelected, 
      boolean hasFocus, 
      int row, 
      int column) { 
     setFont(table.getFont()); 
     String str = (value == null) ? "" : value.toString(); 
     setText(str); 
     int columnWidth= getColumnWidth(); 
     setRows(str.length()/columnWidth); 
     return this; 
    } 
} 
0

Вот другой подход. Это решение имеет следующие преимущества:

  1. Вам не нужно вручную разбивать имена столбцов.
  2. Столбцы динамически переносятся по словам при изменении размеров столбцов и/или окна.
  3. Внешний вид заголовка будет автоматически соответствовать установленному внешнему виду.
  4. В отличие от других решений, которые я видел, это работает, даже если первый столбец не обертывается (как в примере ниже).

Однако он имеет следующий недостаток: он создает неиспользуемый объект JTableHeader для каждого столбца, поэтому он немного неэлегантен и, вероятно, не подходит, если у вас много столбцов.

Основная идея заключается в том, что вы обертываете имена столбцов в тегах <html>, и, самое главное, каждый TableColumn получает свой собственный объект TableCellRenderer.

Я пришел к этому решению после отладки вглубь глубины раскладушки таблиц заголовка Swing. Не вдаваясь слишком много в сорняки, проблема заключается в том, что если у TableColumn s не указан определитель headerRenderer, для каждой ячейки заголовка столбца используется тот же рендеринг по умолчанию. Код компоновки, используемый для JTableHeader, беспокоит только запрос рендеринга заголовка столбца для его предпочтительного размера (см. Функцию 4. выше), и поскольку средство визуализации повторно используется, вызов его метода setText() запускает создание новый View для ярлыка, который по причинам, которые я слишком устал, чтобы даже подумать об объяснении, заставляет визуализатор заголовков всегда сообщать о своем предпочтительном развернутом размере.

Вот быстрый и грязный проверка концепции:

package scratch; 

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

@SuppressWarnings("serial") 
public class WordWrappingTableHeaderDemo extends JFrame { 

    class DemoTableModel extends AbstractTableModel { 

     private ArrayList<String> wrappedColumnNames = new ArrayList<String>(); 
     private int numRows; 

     DemoTableModel(List<String> columnNames, int numRows) { 
      for (String name: columnNames) 
       wrappedColumnNames.add("<html>" + name + "</html>"); 
      this.numRows = numRows; 
     } 

     public int getRowCount() { 
      return numRows; 
     } 

     public int getColumnCount() { 
      return wrappedColumnNames.size(); 
     } 

     public Object getValueAt(int rowIndex, int columnIndex) { 
      return Integer.valueOf(10000 + (rowIndex + 1)*(columnIndex + 1)); 
     } 

     public String getColumnName(int column) { 
      return wrappedColumnNames.get(column); 
     } 

     public Class<?> getColumnClass(int columnIndex) { 
      return Integer.class; 
     } 
    } 

    public WordWrappingTableHeaderDemo() { 

     DefaultTableColumnModel tableColumnModel = new DefaultTableColumnModel() { 
      public void addColumn(TableColumn column) { 
       // This works, but is a bit kludgey as it creates an unused JTableHeader object for each column: 
       column.setHeaderRenderer(new JTableHeader().getDefaultRenderer()); 
       super.addColumn(column); 
      } 
     }; 

     JTable table = new JTable(); 
     table.setFillsViewportHeight(true);; 
     table.setColumnModel(tableColumnModel); 
     table.setModel(
       new DemoTableModel(Arrays.asList("Name", "The Second Column Name is Very Long", "Column Three"), 20)); 
     getContentPane().add(new JScrollPane(table)); 
    } 

    public static void createAndShowGUI() { 
     WordWrappingTableHeaderDemo app = new WordWrappingTableHeaderDemo(); 
     app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     app.setLocationByPlatform(true); 
     app.pack(); 
     app.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(() -> {createAndShowGUI();}); 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^