2

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

  }
}
Community
  • 1
  • 1
nevets1219
  • 7,692
  • 4
  • 32
  • 47
  • 1
    I'd suggest to post [your question to Coderanch](http://www.coderanch.com/forums/f-2/GUI), here is @Darryl Burke author of most of workaround for LTR & Swing, then please to notify about crossposting on both forums – mKorbel Aug 29 '13 at 07:08
  • actually, I don't understand what you want to achieve: sounds weird to have the header not-scrolling when the table itself does .. Technically, the problem is unrelated to the scrollPane (can't be related, as the header isn't added anywhere to the scrollPane ;), even its CO is correct, only the alignment is weird. Removing its association to the table fixes that, didn't dig as to why that happens. In your shoes, I would start over: describe your requirements and lets see how they can be achieved without doing anything unusual – kleopatra Aug 29 '13 at 10:22
  • It's actually quite common to freeze a row (in this case the header) so that as the table scrolls, you can easily see the header without having to scroll back up. My requirements haven't changed regardless of the source of the problem. The table header should be right aligned as according to the orientation and the column's should auto-resize. – nevets1219 Aug 29 '13 at 17:01
  • 2
    `It's actually quite common to freeze a row (in this case the header) so that as the table scrolls, you can easily see the header without having to scroll back up` - this is the default behaviour of a JScrollPane. When you scroll vertically the header stays displayed at the top. If you scroll horizontally the header scroll horizontally to match the columns being scrolled. – camickr Aug 29 '13 at 22:39
  • This program behaves extremely strangely even when you remove the RIGHT_TO_LEFT flipping. – Hakanai Aug 12 '14 at 05:53

1 Answers1

1

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.

David Gidony
  • 1,243
  • 3
  • 16
  • 31
  • I was able to get an answer from CodeRanch at http://www.coderanch.com/t/618982/GUI/java/JScrollPane-header-lose-component-orientation – nevets1219 Feb 27 '14 at 00:50