2013-02-22 2 views
3

Я столкнулся с проблемой, которая обсуждалась здесь раньше: получение JScrollPane, содержащего JTable, для отображения горизонтальной полосы прокрутки по своему желанию. HERE - это сообщение, которое я пробовал, но по какой-то причине он не работает с моей ситуацией (я думаю, это потому, что я установил одну из моих столбцов на фиксированную ширину.JTable горизонтальная полоса прокрутки, основанная на ширине одного столбца

Вот SSCCE:

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 

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

     DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"},0); 
     model.addRow(new Object[]{"short", "blah"}); 
     model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"}); 

     JTable table = new JTable(model) { 
      public boolean getScrollableTracksViewportWidth() { 
       return getPreferredSize().width < getParent().getWidth(); 
      } 
     };   
     table.getColumn("key").setPreferredWidth(60); 
     table.getColumn("key").setMinWidth(60); 
     table.getColumn("key").setMaxWidth(60); 
     table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 

     JScrollPane scrollPane = new JScrollPane(table); 
     getContentPane().add(scrollPane); 
    } 

    public static void main(String[] args) { 
     TableScrollTest frame = new TableScrollTest(); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setSize(200, 200); 
     frame.setResizable(false); 
     frame.setVisible(true); 
    } 
} 

Короче говоря, у меня есть таблица из двух столбцов для отображения пары ключ/значение. контейнер, содержащий таблицу имеет фиксированную ширину, и первый столбец таблицы также имеет фиксированную ширину (так как я знаю, как длинный все имена ключей будут). Второй столбец будет содержать значения переменной длины строки. Горизонтальная полоса прокрутки должна появляться только тогда, когда есть значения, которые слишком велики для того, чтобы соответствовать ширине, выделенной для столбца.

enter image description here

Поскольку второе значение выше, имеет такую ​​большую длину, то полоса прокрутки должна быть видна. Тем не менее, это не так, и все, что я пробовал, преуспело только в том, чтобы всегда видеть его всегда, чего я не хочу ... Я только хочу, чтобы он был видимым, если присутствуют «длинные» значения. Кажется, что метод getScrollableTracksViewportWidth(), переопределяемый в конструкторе таблицы, проверяет, какая ширина предпочтительной ширины таблицы ... так что мне нужно направить таблицу на предпочтительную большую ширину, основываясь только на содержимом этого второго столбца ... но Я в тупике.

Любые идеи?

+1

Вы неотложный вопрос, потому что вы имеете переопределяется 'getScrollableTracksViewportWidth', что означает этот стол никогда не может быть шире, чем панель прокрутки ... – MadProgrammer

+0

@MadProgrammer Уверены ли вы? В примере, который я связывал, этот метод переопределен, и в этом примере таблица становится шире, чем панель прокрутки. – The111

+1

Но предпочтительная ширина таблицы основана на ширине «TableColumn», которая не учитывает ширину содержимого, а это означает, что, если вы не измените ширину второго столбца так же, как вы изменили первый, это всегда будет возвращать 'true'. Я удалил метод getScrollableTracksViewportWidth и вручную изменил размер столбца и смог отобразить горизонтальную полосу прокрутки. – MadProgrammer

ответ

6

это hackey Solution

В принципе, что она делает это вычисляет «предпочтительный» ширину всех столбцов на основе значений из всех строк.

Он принимает во внимание изменения в модели, а также изменения в родительском контейнере.

Как только это будет сделано, он проверяет, превышает ли «предпочтительную» ширину доступное пространство и соответственно устанавливает переменную trackViewportWidth.

Вы можете добавить проверки для фиксированных столбцов (я не беспокоил), что сделало бы процесс «немного» быстрее, но это будет страдать, когда вы добавите больше столбцов и строк в таблицу, так как каждое обновление требуя прогулок всей модели.

Вы могли бы поставить какой-то кэш в, но прямо о тогда, я бы рассматривать столбцы с фиксированной шириной;)

import java.awt.Container; 
import java.awt.EventQueue; 
import java.awt.event.ComponentAdapter; 
import java.awt.event.ComponentEvent; 
import javax.swing.JFrame; 
import static javax.swing.JFrame.EXIT_ON_CLOSE; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.JViewport; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ListSelectionEvent; 
import javax.swing.event.TableColumnModelEvent; 
import javax.swing.event.TableColumnModelListener; 
import javax.swing.event.TableModelEvent; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableColumn; 
import javax.swing.table.TableColumnModel; 

public class TableScrollTest extends JFrame { 

    public TableScrollTest() { 

     DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"}, 0); 
     model.addRow(new Object[]{"short", "blah"}); 
     model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"}); 

     JTable table = new JTable(model) { 
      private boolean trackViewportWidth = false; 
      private boolean inited = false; 
      private boolean ignoreUpdates = false; 

      @Override 
      protected void initializeLocalVars() { 
       super.initializeLocalVars(); 
       inited = true; 
       updateColumnWidth(); 
      } 

      @Override 
      public void addNotify() { 
       super.addNotify(); 
       updateColumnWidth(); 
       getParent().addComponentListener(new ComponentAdapter() { 
        @Override 
        public void componentResized(ComponentEvent e) { 
         invalidate(); 
        } 
       }); 
      } 

      @Override 
      public void doLayout() { 
       super.doLayout(); 
       if (!ignoreUpdates) { 
        updateColumnWidth(); 
       } 
       ignoreUpdates = false; 
      } 

      protected void updateColumnWidth() { 
       if (getParent() != null) { 
        int width = 0; 
        for (int col = 0; col < getColumnCount(); col++) { 
         int colWidth = 0; 
         for (int row = 0; row < getRowCount(); row++) { 
          int prefWidth = getCellRenderer(row, col). 
            getTableCellRendererComponent(this, getValueAt(row, col), false, false, row, col). 
            getPreferredSize().width; 
          colWidth = Math.max(colWidth, prefWidth + getIntercellSpacing().width); 
         } 

         TableColumn tc = getColumnModel().getColumn(convertColumnIndexToModel(col)); 
         tc.setPreferredWidth(colWidth); 
         width += colWidth; 
        } 

        Container parent = getParent(); 
        if (parent instanceof JViewport) { 
         parent = parent.getParent(); 
        } 

        trackViewportWidth = width < parent.getWidth(); 
       } 
      } 

      @Override 
      public void tableChanged(TableModelEvent e) { 
       super.tableChanged(e); 
       if (inited) { 
        updateColumnWidth(); 
       } 
      } 

      public boolean getScrollableTracksViewportWidth() { 
       return trackViewportWidth; 
      } 

      @Override 
      protected TableColumnModel createDefaultColumnModel() { 
       TableColumnModel model = super.createDefaultColumnModel(); 
       model.addColumnModelListener(new TableColumnModelListener() { 
        @Override 
        public void columnAdded(TableColumnModelEvent e) { 
        } 

        @Override 
        public void columnRemoved(TableColumnModelEvent e) { 
        } 

        @Override 
        public void columnMoved(TableColumnModelEvent e) { 
         if (!ignoreUpdates) { 
          ignoreUpdates = true; 
          updateColumnWidth(); 
         } 
        } 

        @Override 
        public void columnMarginChanged(ChangeEvent e) { 
         if (!ignoreUpdates) { 
          ignoreUpdates = true; 
          updateColumnWidth(); 
         } 
        } 

        @Override 
        public void columnSelectionChanged(ListSelectionEvent e) { 
        } 
       }); 
       return model; 
      } 
     }; 
     table.getColumn("key").setPreferredWidth(60); 
//  table.getColumn("key").setMinWidth(60); 
//  table.getColumn("key").setMaxWidth(60); 
//  table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); 

     JScrollPane scrollPane = new JScrollPane(table); 
     getContentPane().add(scrollPane); 
    } 

    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       TableScrollTest frame = new TableScrollTest(); 
       frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
       frame.pack(); 
       frame.setSize(200, 200); 
       frame.setResizable(true); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
+0

Спасибо! Это очень похоже на то, что я придумал выше, но я только придумал мой из-за ваших комментариев и сообщения @ kleopatra, с которым я связан. Однако в вашем решении есть небольшая ошибка ... ваша ширина накапливает значение ширины каждой строки ... так что чем больше строк вы добавляете, тем больше «мертвого» пространства вы получаете в конце каждой строки. Я думаю, вы хотите использовать функцию max, как я. Но тогда мне еще нужно добавить 1-5 пиксельный фактор выдумки, о котором я прокомментировал в своем ответе. Окунитесь за свою помощь. :-) – The111

+0

Также принимаем этот ответ, потому что переопределения 'addNotify',' tableChanged' и т. Д. Умны и делают все автоматическим. Я планировал вручную вызывать метод 'update' каждый раз, когда моя таблица менялась, но включение его в определение таблицы, как вы сделали, намного лучше. – The111

+1

@ The111 Исправлена ​​ошибка, также добавленная в межсетевой фактор. Хорошее место! – MadProgrammer

4

кажется то, что моя цель состоит в том, чтобы заставить рендер ячейки автоматически делает клетки подходят длинные строки

Это не работа визуализатора. Вы должны вручную установить ширину столбцов.

См. Table Column Adjuster для этого способа.

1

Я не обязательно соглашусь с этим ответом, если что-то умнее отправлено, но вот решение, которое я выяснил самостоятельно, основываясь на комментариях, опубликованных до сих пор, и THIS. Единственный улов в том, что ширина, которую я придумывал, всегда была слишком 1 пиксель (в некоторых выглядело и чувствую, что все в порядке), поэтому я добавил строку ближе к концу width += 5, которая, кажется, заставляет ее работать нормально, но он чувствует себя взломанным. Будут приветствовать любые комментарии по этому подходу.

import java.awt.Component; 

import javax.swing.JFrame; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellRenderer; 

@SuppressWarnings("serial") 
public class TableScrollTest extends JFrame { 
    public TableScrollTest() { 
     DefaultTableModel model = new DefaultTableModel(new Object[]{"key", "value"},0); 
     model.addRow(new Object[]{"short", "blah"}); 
     model.addRow(new Object[]{"long", "blah blah blah blah blah blah blah"}); 

     JTable table = new JTable(model);   
     table.getColumn("key").setPreferredWidth(60); 
     table.getColumn("key").setMinWidth(60); 
     table.getColumn("key").setMaxWidth(60); 
     table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 

     int width = 0; 
     for (int row = 0; row < table.getRowCount(); row++) { 
      TableCellRenderer renderer = table.getCellRenderer(row, 1); 
      Component comp = table.prepareRenderer(renderer, row, 1); 
      width = Math.max (comp.getPreferredSize().width, width); 
     } 
     width += 5; 
     table.getColumn("value").setPreferredWidth(width); 
     table.getColumn("value").setMinWidth(width); 
     table.getColumn("value").setMaxWidth(width); 

     JScrollPane scrollPane = new JScrollPane(table); 
     getContentPane().add(scrollPane); 
    } 

    public static void main(String[] args) { 
     TableScrollTest frame = new TableScrollTest(); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setSize(200, 200); 
     frame.setResizable(false); 
     frame.setVisible(true); 
    } 
} 
+1

Используйте ['JTable.getIntercellSpacing() .width'] (http://docs.oracle.com/javase/7/docs/api/javax/swing/JTable.html#getIntercellSpacing%28%29) вместо" fudging «padding padding – MadProgrammer

+0

@MadProgrammer Прохладный, спасибо за этот совет и за обновление вашего решения. – The111