1

The goal to write the values of columns into JTable vertically. I read about DefaultTableCellRenderer, VerticalTableHeaderCellRenderer() but cannot implement it. Here is my code:

//=========================================================
    private JScrollPane getTablePane() {
        if (tablePane == null) {
            tablePane = new JScrollPane();
            tablePane.setRowHeaderView(getTableDictionary());
            tablePane.setViewportView(getTableDictionary());
        }
        return tablePane;
    }

//=============================================================

private JTable getTableDictionary(){
    if (table == null) {

            rowVector = new String[colCount];
                for(int i=0; i<colCount;i++) {rowVector[i]="";}
            data = new DefaultTableModel(rowVector, 0);
                for (int i = 0; i < rowCount; i++) { data.addRow(rowVector); }

            table = new JTable(data);
            table.getTableHeader().setDefaultRenderer(new VerticalTableHeaderCellRenderer());
                for(int i=1; i<colCount; i++)  { table.getColumnModel().getColumn(i).setPreferredWidth(withCol);}

                table.setSelectionForeground(Color.BLACK);
                table.setSelectionBackground(Color.YELLOW);
            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
            table.setAutoscrolls(true);
            table.setColumnSelectionAllowed(false);
            table.setRowSelectionAllowed(true);

        /*    DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer();
            int bg = table.getTableHeader().getBackground().getRGB();
            defaultTableCellRenderer.setBackground(Color.getHSBColor(125, 125, 125)); //задаем цвет столбца
            table.getColumnModel().getColumn(0).setCellRenderer(defaultTableCellRenderer);
        */    


        return table;
    }

Where is my mistake? Thank you

Vasyl Lyashkevych
  • 1,920
  • 2
  • 23
  • 38
  • 3
    There are some examples of how to do something like this [here](http://stackoverflow.com/q/92781/2891664), although I haven't tested them so I'm not sure how robust they are. Using HTML label text might be very easy if you don't want the letters rotated. The default table cell renderer decorates a JLabel so anything that renders a JLabel vertically should also work for a table cell renderer. – Radiodef May 20 '17 at 15:32
  • Thank you! I am going to see it – Vasyl Lyashkevych May 20 '17 at 17:02

1 Answers1

1

I read more resources and I found a decision, it works. I need to implement a render for that and call it when I am locating the table on the JScrollPane. It means that column header is processing apart from a JTable using datamodel. Also, I can define the height of the columns.

private JScrollPane getTablePane() {
    if (tablePane == null) {
        tablePane = new JScrollPane();
        tablePane.setRowHeaderView(getTableDictionary());
        tablePane.setViewportView(getTableDictionary());
        tablePane.setColumnHeader(new JViewport() {
        @Override public Dimension getPreferredSize() {
            Dimension d = super.getPreferredSize();
            d.height = rowColumnHeigth;  // Col header Height
            return d;
            }
        });
    }
    return tablePane;
}

Also, I need for that additional classes:

/**
 * @(#)DefaultTableHeaderCellRenderer.java  1.0 02/24/09
 */

import java.awt.Component;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JTable;
import javax.swing.RowSorter;
import javax.swing.RowSorter.SortKey;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;

/**
 * A default cell renderer for a JTableHeader.
 * <P>
 * DefaultTableHeaderCellRenderer attempts to provide identical behavior to the
 * renderer which the Swing subsystem uses by default, the Sun proprietary
 * class sun.swing.table.DefaultTableCellHeaderRenderer.
 * <P>
 * To apply any desired customization, DefaultTableHeaderCellRenderer may be
 * suitably extended.
 * 
 * @author Darryl
 */
public class DefaultTableHeaderCellRenderer extends DefaultTableCellRenderer {

  /**
   * Constructs a <code>DefaultTableHeaderCellRenderer</code>.
   * <P>
   * The horizontal alignment and text position are set as appropriate to a
   * table header cell, and the opaque property is set to false.
   */
  public DefaultTableHeaderCellRenderer() {
    setHorizontalAlignment(CENTER);
    setHorizontalTextPosition(LEFT);
    setVerticalAlignment(BOTTOM);
    setOpaque(false);
  }

  /**
   * Returns the default table header cell renderer.
   * <P>
   * If the column is sorted, the approapriate icon is retrieved from the
   * current Look and Feel, and a border appropriate to a table header cell
   * is applied.
   * <P>
   * Subclasses may overide this method to provide custom content or
   * formatting.
   *
   * @param table the <code>JTable</code>.
   * @param value the value to assign to the header cell
   * @param isSelected This parameter is ignored.
   * @param hasFocus This parameter is ignored.
   * @param row This parameter is ignored.
   * @param column the column of the header cell to render
   * @return the default table header cell renderer
   */
  @Override
  public Component getTableCellRendererComponent(JTable table, Object value,
          boolean isSelected, boolean hasFocus, int row, int column) {
    super.getTableCellRendererComponent(table, value,
            isSelected, hasFocus, row, column);
    JTableHeader tableHeader = table.getTableHeader();
    if (tableHeader != null) {
      setForeground(tableHeader.getForeground());
    }
    setIcon(getIcon(table, column));
    setBorder(UIManager.getBorder("TableHeader.cellBorder"));
    return this;
  }

  /**
   * Overloaded to return an icon suitable to the primary sorted column, or null if
   * the column is not the primary sort key.
   *
   * @param table the <code>JTable</code>.
   * @param column the column index.
   * @return the sort icon, or null if the column is unsorted.
   */
  protected Icon getIcon(JTable table, int column) {
    SortKey sortKey = getSortKey(table, column);
    if (sortKey != null && table.convertColumnIndexToView(sortKey.getColumn()) == column) {
      switch (sortKey.getSortOrder()) {
        case ASCENDING:
          return UIManager.getIcon("Table.ascendingSortIcon");
        case DESCENDING:
          return UIManager.getIcon("Table.descendingSortIcon");
      }
    }
    return null;
  }

  /**
   * Returns the current sort key, or null if the column is unsorted.
   *
   * @param table the table
   * @param column the column index
   * @return the SortKey, or null if the column is unsorted
   */
  protected SortKey getSortKey(JTable table, int column) {
    RowSorter rowSorter = table.getRowSorter();
    if (rowSorter == null) {
      return null;
    }

    List sortedColumns = rowSorter.getSortKeys();
    if (sortedColumns.size() > 0) {
      return (SortKey) sortedColumns.get(0);
    }
    return null;
  }
}

Also:

/**
 * @(#)VerticalLabelUI.java 1.0 02/18/09
 */
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicLabelUI;

/**
 * A UI delegate for JLabel that rotates the label 90є
 * <P>
 * Extends {@link BasicLabelUI}.
 * <P>
 * The only difference between the appearance of labels in the Basic and Metal
 * L&Fs is the manner in which diabled text is painted.  As VerticalLabelUI
 * does not override the method paintDisabledText, this class can be adapted
 * for Metal L&F by extending MetalLabelUI instead of BasicLabelUI.
 * <P>
 * No other changes are required.
 * 
 * @author Darryl
 */
public class VerticalLabelUI extends BasicLabelUI {

   private boolean clockwise = false;
   // see comment in BasicLabelUI
   Rectangle verticalViewR = new Rectangle();
   Rectangle verticalIconR = new Rectangle();
   Rectangle verticalTextR = new Rectangle();
   protected static VerticalLabelUI verticalLabelUI =
         new VerticalLabelUI();
   private final static VerticalLabelUI SAFE_VERTICAL_LABEL_UI =
         new VerticalLabelUI();

   /**
    * Constructs a <code>VerticalLabelUI</code> with the default anticlockwise
    * rotation
    */
   public VerticalLabelUI() {
   }

   /**
    * Constructs a <code>VerticalLabelUI</code> with the desired rotation.
    * <P>
    * @param clockwise true to rotate clockwise, false for anticlockwise
    */
   public VerticalLabelUI(boolean clockwise) {
      this.clockwise = clockwise;
   }

   /**
    * @see ComponentUI#createUI(javax.swing.JComponent) 
    */
   public static ComponentUI createUI(JComponent c) {
      if (System.getSecurityManager() != null) {
         return SAFE_VERTICAL_LABEL_UI;
      } else {
         return verticalLabelUI;
      }
   }

   /**
    * Overridden to always return -1, since a vertical label does not have a
    * meaningful baseline.
    * 
    * @see ComponentUI#getBaseline(JComponent, int, int)
    */
   @Override
   public int getBaseline(JComponent c, int width, int height) {
      super.getBaseline(c, width, height);
      return -1;
   }

   /**
    * Overridden to always return Component.BaselineResizeBehavior.OTHER,
    * since a vertical label does not have a meaningful baseline 
    * 
    * @see ComponentUI#getBaselineResizeBehavior(javax.swing.JComponent)
    */
   @Override
   public Component.BaselineResizeBehavior getBaselineResizeBehavior(
         JComponent c) {
      super.getBaselineResizeBehavior(c);
      return Component.BaselineResizeBehavior.OTHER;
   }

   /**
    * Transposes the view rectangles as appropriate for a vertical view
    * before invoking the super method and copies them after they have been
    * altered by {@link SwingUtilities#layoutCompoundLabel(FontMetrics, String,
    * Icon, int, int, int, int, Rectangle, Rectangle, Rectangle, int)}
    */
   @Override
   protected String layoutCL(JLabel label, FontMetrics fontMetrics,
         String text, Icon icon, Rectangle viewR, Rectangle iconR,
         Rectangle textR) {

      verticalViewR = transposeRectangle(viewR, verticalViewR);
      verticalIconR = transposeRectangle(iconR, verticalIconR);
      verticalTextR = transposeRectangle(textR, verticalTextR);

      text = super.layoutCL(label, fontMetrics, text, icon,
            verticalViewR, verticalIconR, verticalTextR);

      viewR = copyRectangle(verticalViewR, viewR);
      iconR = copyRectangle(verticalIconR, iconR);
      textR = copyRectangle(verticalTextR, textR);
      return text;
   }

   /**
    * Transforms the Graphics for vertical rendering and invokes the
    * super method.
    */
   @Override
   public void paint(Graphics g, JComponent c) {
      Graphics2D g2 = (Graphics2D) g.create();
      if (clockwise) {
         g2.rotate(Math.PI / 2, c.getSize().width / 2, c.getSize().width / 2);
      } else {
         g2.rotate(-Math.PI / 2, c.getSize().height / 2, c.getSize().height / 2);
      }
      super.paint(g2, c);
   }

   /**
    * Returns a Dimension appropriate for vertical rendering
    * 
    * @see ComponentUI#getPreferredSize(javax.swing.JComponent)
    */
   @Override
   public Dimension getPreferredSize(JComponent c) {
      return transposeDimension(super.getPreferredSize(c));
   }

   /**
    * Returns a Dimension appropriate for vertical rendering
    * 
    * @see ComponentUI#getMaximumSize(javax.swing.JComponent)
    */
   @Override
   public Dimension getMaximumSize(JComponent c) {
      return transposeDimension(super.getMaximumSize(c));
   }

   /**
    * Returns a Dimension appropriate for vertical rendering
    * 
    * @see ComponentUI#getMinimumSize(javax.swing.JComponent)
    */
   @Override
   public Dimension getMinimumSize(JComponent c) {
      return transposeDimension(super.getMinimumSize(c));
   }

   private Dimension transposeDimension(Dimension from) {
      return new Dimension(from.height, from.width + 2);
   }

   private Rectangle transposeRectangle(Rectangle from, Rectangle to) {
      if (to == null) {
         to = new Rectangle();
      }
      to.x = from.y;
      to.y = from.x;
      to.width = from.height;
      to.height = from.width;
      return to;
   }

   private Rectangle copyRectangle(Rectangle from, Rectangle to) {
      if (to == null) {
         to = new Rectangle();
      }
      to.x = from.x;
      to.y = from.y;
      to.width = from.width;
      to.height = from.height;
      return to;
   }
}

Also:

import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.Icon;
import javax.swing.JTable;
import javax.swing.RowSorter.SortKey;
import javax.swing.SortOrder;
import javax.swing.UIManager;

/**
 * A renderer for a JTableHeader with text rotated 90В° counterclockwise.
 * <P>
 * Extends {@link DefaultTableHeaderCellRenderer}.
 * 
 * @see VerticalLabelUI
 * @author Darryl
 */
public class VerticalTableHeaderCellRenderer
        extends DefaultTableHeaderCellRenderer {

  /**
   * Constructs a <code>VerticalTableHeaderCellRenderer</code>.
   * <P>
   * The horizontal and vertical alignments and text positions are set as
   * appropriate to a vertical table header cell.
   */
  public VerticalTableHeaderCellRenderer() {
    setHorizontalAlignment(LEFT);
    setHorizontalTextPosition(CENTER);
    setVerticalAlignment(CENTER);
    setVerticalTextPosition(TOP);
    setUI(new VerticalLabelUI());
  }

  /**
   * Overridden to return a rotated version of the sort icon.
   *
   * @param table the <code>JTable</code>.
   * @param column the colummn index.
   * @return the sort icon, or null if the column is unsorted.
   */
  @Override
  protected Icon getIcon(JTable table, int column) {
    SortKey sortKey = getSortKey(table, column);
    if (sortKey != null && table.convertColumnIndexToView(sortKey.getColumn()) == column) {
      SortOrder sortOrder = sortKey.getSortOrder();
      switch (sortOrder) {
        case ASCENDING:
          return VerticalSortIcon.ASCENDING;
        case DESCENDING:
          return VerticalSortIcon.DESCENDING;
      }
    }
    return null;
  }

  /**
   * An icon implementation to paint the contained icon rotated 90В° clockwise.
   * <P>
   * This implementation assumes that the L&F provides ascending and
   * descending sort icons of identical size.
   */
  private enum VerticalSortIcon implements Icon {

    ASCENDING(UIManager.getIcon("Table.ascendingSortIcon")),
    DESCENDING(UIManager.getIcon("Table.descendingSortIcon"));
    private final Icon icon;// = ;

    private VerticalSortIcon(Icon icon) {
      this.icon = icon;
    }

    /**
     * Paints an icon suitable for the header of a sorted table column,
     * rotated by 90В° clockwise.  This rotation is applied to compensate
     * the rotation already applied to the passed in Graphics reference
     * by the VerticalLabelUI.
     * <P>
     * The icon is retrieved from the UIManager to obtain an icon
     * appropriate to the L&F.
     *
     * @param c the component to which the icon is to be rendered
     * @param g the graphics context
     * @param x the X coordinate of the icon's top-left corner
     * @param y the Y coordinate of the icon's top-left corner
     */
    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
      int maxSide = Math.max(getIconWidth(), getIconHeight()+(Integer)getIconHeight()/4);
      Graphics2D g2 = (Graphics2D) g.create(x, y, maxSide, maxSide);
      g2.rotate((Math.PI / 2));
      g2.translate(0, -maxSide);
      icon.paintIcon(c, g2, 0, 0);
      g2.dispose();
    }

    /**
     * Returns the width of the rotated icon.
     *
     * @return the <B>height</B> of the contained icon
     */
    @Override
    public int getIconWidth() {
      return icon.getIconHeight();
    }

    /**
     * Returns the height of the rotated icon.
     *
     * @return the <B>width</B> of the contained icon
     */
    @Override
    public int getIconHeight() {
      return icon.getIconWidth();
    }
  }
}

It works fine for me. Thank you! Also, it looks like:

enter image description here

Vasyl Lyashkevych
  • 1,920
  • 2
  • 23
  • 38