Tuesday, October 20, 2009

Arrange It Like A Table, Introducing The Table Layout

In a recent post I discussed LWUIT 1.3's upcoming table component. This new component is based on a new underlying layout manager also introduced in LWUIT 1.3: the table layout.

The table layout is largely inspired by the HTML table tag and slightly by AWT's GridBagLayout.
The table layout is a constraint based layout (similar to the border layout) this means that unlike other layout managers that expect components to be added on their own:
container.addComponent(component);

The table layout container expects something like this:
container.addComponent(tableConstraint, component);

Notice that this syntax is optional if omitting the constraint a default behavior will ensue of placing the component in the next available cell.

The table layout will automatically size components to the largest preferred size in the row/column until running out of space, if the table is not horizontally scrollable this will happen when the edge of the parent container is reached (close to the edge of the screen) and further components will be "crammed together". Notice that all cells in the table layout are sized to fit the entire cell always. To align, or margin cell's a developer can use the methods of the component/Style appropriately.

A developer can provide hints to the table layout to enable spanning and more detailed column/row sizes using the constraint argument to the addComponent method. The constraint argument is an instance of TableLayout.Constraint that must not be reused for more than one cell, this will cause an exception.

A constraint can specify the absolute row/column where the entry should fit as well as spanning between cell boundaries. Notice that in the picture the "First" cell is spanned vertically while the "Spanning" cell is spanned horizontally. This is immensely useful in creating elaborate UI's,

Constraints can also specify a height/width for a column/row that will override the default, this size is indicated in percentage of the total table layout size. In the picture you can see that the "First" label is sized to 50% width while the "Forth" label is sized to 20% height.

Form mainForm = new Form("Table Layout");
TableLayout layout = new TableLayout(4, 3);
mainForm.setLayout(layout);
TableLayout.Constraint constraint = layout.createConstraint();
constraint.setVerticalSpan(2);
constraint.setWidthPercentage(50);
mainForm.addComponent(constraint, new Label("First"));
mainForm.addComponent(new Label("Second"));
mainForm.addComponent(new Label("Third"));

constraint = layout.createConstraint();
constraint.setHeightPercentage(20);
mainForm.addComponent(constraint, new Label("Forth"));
mainForm.addComponent(new Label("Fifth"));
constraint = layout.createConstraint();
constraint.setHorizontalSpan(3);
Label span = new Label("Spanning");
span.getStyle().setBorder(Border.createLineBorder(2));
span.setAlignment(Component.CENTER);
mainForm.addComponent(constraint, span);
mainForm.show();

18 comments:

  1. hi Shai,
    Is it possible to extend Table Component to draw a grid that have 10 columns and show only 6 of it and when moving to right, shows the other columns and hide the first columns?

    ReplyDelete
  2. @Bertan You don't need to extend the table. Just call setScrollableX(true).

    ReplyDelete
  3. Hi Shai, I test the code below. On the Emulator, components getting smaller. What I want is, it should show the enough columns that fit the screen width. and when moving to the right, the columns that outside the screen width is displayed while the first columns is getting hide.

    Display.init(this);
    Resources r1 = null;
    try {
    r1 = Resources.open("/LWUITtheme.res");
    } catch (IOException ex) {
    ex.printStackTrace();
    }
    UIManager.getInstance().setThemeProps(r1.getTheme(r1.getThemeResourceNames()[0]));

    final Form f = new Form("Table Test");
    f.setScrollableX(true);

    f.setLayout(new TableLayout(4, 12));

    for (int j = 0; j < 4 ; j++)
    for (int i = 0; i < 12; i++) {
    f.addComponent(new Label("row "+j+i ));
    }

    f.show();

    ReplyDelete
  4. @Bertan I fixed this issue in my latest commit to LWUIT.

    ReplyDelete
  5. Hi Shai, I update the source to revision 723. I test the both code before I sent and the code below. but nothing seems to me changed.
    As you'll see, int the deafult emulator, the columns that after the 6th column, is getting narrowed and when moving to the last columns, they ar not visible.

    if you could help me I'll be pleased.

    Display.init(this);
    Resources r1 = null;
    try {
    r1 = Resources.open("/LWUITtheme.res");
    } catch (IOException ex) {
    ex.printStackTrace();
    }
    UIManager.getInstance().setThemeProps(r1.getTheme(r1.getThemeResourceNames()[0]));

    final Form f = new Form("Table Test");
    TableModel model = new DefaultTableModel(new String[] {"Col 1", "Col 2", "Col 3","Col 4", "Col 5", "Col 6","Col 7", "Col 8", "Col 9"},
    new Object[][]{
    {"Row 1", "Row A", "Row X","Row 1", "Row A", "Row X","Row 1", "Row A", "Row X"},
    {"Row 2", "Row B", "Row Y","Row 2", "Row B", "Row Y","Row 2", "Row B", "Row Y"},
    {"Row 3", "Row C", "Row Z","Row 3", "Row C", "Row Z","Row 3", "Row C", "Row Z"},
    {"Row 4", "Row D", "Row K","Row 4", "Row D", "Row K","Row 4", "Row D", "Row K"}
    }
    )
    {

    public boolean isCellEditable(int row, int col) {
    return false;
    }
    };
    Table table = new Table(model);
    table.setScrollableX(true);
    f.setLayout(new BorderLayout());
    f.addComponent(BorderLayout.CENTER, table);
    f.show();
    }

    ReplyDelete
  6. @Bertan: try f.setScrollable(false) so the forms scrollability doesn't break the tables scrolling.

    ReplyDelete
  7. you re great. thank you.

    ReplyDelete
  8. Hello Shai, Addition of Table Component is Great.
    I have one doubt, I have created
    Buttons in a form, Layout is TableLayout. It's running fine.
    But, if I try deleting One or two buttons, then Run ( after Clean ) the application, it is still showing the Deleted Buttons on Emulator. I don't know what the problem is. Please Help!!

    ---Priyanka

    ReplyDelete
  9. Hi Shai,

    I'm using the new Table component in my project. I have 3 columns and I need to make them occupy full-width (something like: first column 40% and second and third columns 30% each, of the total width) in the form. I'm putting table component in CENTER of the form which is set with BorderLayout. Right now, the columns are sized based on the contents but, I want to make them independent of the content.

    [ And, I don't want the horizontal scrollbars to appear in the table i.e. table.setScrollableX(false); ]

    Please help!!

    ReplyDelete
  10. @Priyanka: You have a build problem.

    @siddharudh: You need to manipulate the column constraint to determine the width. In 1.3 you can do this by getting the table layout and extracting the constraint variable. In the trunk you can override the Table.createCellConstraint method.

    ReplyDelete
  11. Really helpful for screen designing. I was fed up with other Layouts.
    Is there any option for a href="" in lwuit??

    ReplyDelete
  12. Shai, is there some trick to making tables scroll faster? I have tried to set smooth scrolling, but it is still choppy.

    By the way, this framework is awesome. We are using it here at Miami-Dade Police on our BlackBerry devices, and also plan to use it on our ruggedized Motorola devices.

    ReplyDelete
  13. Hello Shai, the reason why the tables were scrolling choppy was due to the fact that we were using a bitmap font, we are now using the default system font, and it works great.

    ReplyDelete
  14. Issues like that would be addressed better in the forum ideally with an image/code to clarify the issue.

    ReplyDelete
  15. Hey Shai Almog!
    I am working with LWUIT framework and created a midlet that reads data from a server, parses it and fills table items, but when I run my application on Java Sun Emulator my table scrolls well but when ideployed my application on nokia N80 scrolling isn't working!!! I did this but didn'nt help

    fMain.setScrollable(false);
    table.setScrollable(true);

    what could be the problem?

    ReplyDelete
  16. With so little information I can only guess. 90% of device problems stem from race conditions, I'm guessing you changed the table from a separate thread and layout broke down.

    ReplyDelete
  17. hi Shai..
    Am trying to work on a dynamic lwuit table that fetches data from an rss link. how do i go about it..

    ReplyDelete