JScrollPane breaking right to left orientation

1.4k views Asked by At

My application is divided up into into two main components:

  • a header consisting of a JLabel and JTableHeader
  • a JScrollPane containing a JTable

The reason the JTableHeader is in a separate panel is because it should not scroll. The columns in the table all have preferred/max width set (except for column in the middle) so when the frame is resized only column should be changing its width.

EDIT: I believe I can use JScrollPane.setColumnHeaderView( JTable.getTableHeader() ); to get get the table header to remain static - the code I got had it like that and changing it doesn't impact the issue at hand as far as I can tell.

I have a problem with JScrollPane breaking the right-to-left (RTL) orientation of the JTableHeader. The JTableHeader will be aligned on the left whereas the JTable will be aligned on the right.

The question is similar to what was posted here which points to this unresolved bug. I'm not entirely sure it's the issue I'm seeing since the JTableHeader shouldn't be in the scroll pane. Additionally, the proposed solution doesn't work since I do need the scroll bar to be on the left as it would be expected in RTL orientation.

How can I fix the orientation for the JTableHeader while still maintaining the ability to auto-resize the columns?

EDIT: Added a JButton to the tablePanel because it's suppose to be there.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.ComponentOrientation;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;

public class SwingTest {

  public static void main( String[] args ) {
    final JFrame frame = new JFrame( "RTL Test" );

    //ComponentOrientation orientation = ComponentOrientation.LEFT_TO_RIGHT;
    ComponentOrientation orientation = ComponentOrientation.RIGHT_TO_LEFT;

    frame.setComponentOrientation( orientation );

    /* Build and populate table */
    String data[][] = {
      { "1", "foo", "bar", "5000" },
      { "2", "wtf", "RTL", "20000" },
      { "3", "hello", "world", "30000" },
      { "4", "why", "align", "25000" },
      { "5", "foo", "bar", "5000" },
      { "6", "wtf", "RTL", "20000" },
      { "7", "hello", "world", "30000" },
      { "8", "why", "align", "25000" },
      { "9", "hello", "world", "30000" },
      { "10", "hello", "world", "30000" },
      { "11", "hello", "world", "30000" }
    };
    String col[] = { "First", "Second", "Third", "Fourth" };
    DefaultTableModel model = new DefaultTableModel( data, col );
    /* Simply overrides isCellEditable to always * return false */
    JTable table = new NonEditableTable( model );
    /* By using AUTO_RESIZE_OFF, the header becomes correctly aligned but columns no longer auto-resize */
    //table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
    table.setAutoResizeMode( JTable.AUTO_RESIZE_ALL_COLUMNS );
    table.applyComponentOrientation( orientation );

    /* Set all but 3rd column to have a preferred/max size */
    TableColumn tableColumn = null;
    for ( int i = 0; i < table.getColumnCount(); i++ ) {
      if ( i != 2 ) {
        tableColumn = table.getColumnModel().getColumn( i );
        tableColumn.setMaxWidth( 100 );
        tableColumn.setPreferredWidth( 100 );
      }
    }

    /* Pretty */
    JTableHeader header = table.getTableHeader();
    header.setForeground( Color.RED );

    /* ScrollPane = JScrollPane + JTable */
    JPanel tablePanel = new JPanel( new BorderLayout() );
    tablePanel.add( BorderLayout.CENTER, table );
    tablePanel.add( BorderLayout.CENTER, new JButton( "Doh!" ) );
    JScrollPane scrollPane = new JScrollPane( tablePanel );
    scrollPane.setBorder( BorderFactory.createEmptyBorder() );
    /* NOTE: This is what breaks the header when using AUTO_RESIZE_ALL_COLUMNS, comment out to see */
    scrollPane.setComponentOrientation( orientation );

    /* Header */
    JPanel headerPanel = new JPanel( new BorderLayout() );
    headerPanel.add( BorderLayout.NORTH, new JLabel( "SWING TEST" ) );
    headerPanel.add( BorderLayout.CENTER, Box.createVerticalStrut( 5 ) );
    headerPanel.add( BorderLayout.SOUTH, table.getTableHeader() );
    headerPanel.applyComponentOrientation( orientation );

    /* Main = Header + ScrollPane */
    JPanel mainPanel = new JPanel( new BorderLayout() );
    mainPanel.add( BorderLayout.NORTH, headerPanel );
    mainPanel.add( BorderLayout.CENTER, scrollPane );

    /* Add to main frame */
    frame.add( mainPanel );
    frame.setUndecorated( true );
    frame.getRootPane().setWindowDecorationStyle( JRootPane.PLAIN_DIALOG );
    frame.setSize( 500, 200 );
    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

    SwingUtilities.invokeLater( new Runnable() {

      @Override
      public void run() {
        frame.setVisible( true );
      }
    } );

  }

  @SuppressWarnings( "serial" )
  public static class NonEditableTable extends JTable {

    public NonEditableTable( DefaultTableModel model ) {
      super( model );
    }

    @Override
    public boolean isCellEditable( int row, int column ) {
      return false;
    }

  }
}
1

There are 1 answers

1
David Gidony On

How about doing something like this ? and than you will have some better control of orientation.

JPanel headerPanel = new JPanel( new BorderLayout() );

JPanel headerPan = new JPanel();
JLabel xxx = new JLabel( "SWING TEST" );
xxx.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);

headerPan.add(xxx);

Hope that's helpful.