PDA

View Full Version : [FIXED] Table.recalculate() causes an exception if the table is hidden



plitvak
19 Jun 2008, 11:29 AM
The below code demonstrates the problem:



private void testDataGrid( LayoutContainer mainContainer )
{
TabPanel tabPanle = new TabPanel();

TabItem item = new TabItem( "Empty" );
tabPanle.add( item );

item = new TabItem( "Grid" );
tabPanle.add( item );

final Table table = new Table( new TableColumnModel( new TableColumn("Col1", "Col1"), new TableColumn("Col2", "Col2") ) );
item.add( table );

DeferredCommand.addCommand( new Command(){
public void execute()
{
table.removeAll();
for( int i = 0; i < 10; i++ ) {
table.add( new TableItem( new Object[]{"1_"+i, "2_"+i} ) );
}
//if( table.isVisible() ) {
table.recalculate();
//}
}
} );

mainContainer.add( tabPanle );
}
If you add check for table.isVisible() before recalculete() no exception is thrown.
I still believe that this is the bug and call to recalculate has to execute correctly in any case.

darrellmeyer
20 Jun 2008, 8:18 AM
Do you mean visible or rendered? I have no issues calling recalculate when the table is not visible, however, you will get an exception if calling before the table is rendered. I am adding a rendered check to the method. If you mean visible, please provide complete test code.

plitvak
20 Jun 2008, 8:43 AM
The code above is a complete test code you can execute it from the onModuleLoad() like this:


public void onModuleLoad()
{
Viewport mainViewPort = new Viewport();
mainViewPort.setLayout( new FitLayout() );

LayoutContainer mainContainer = new LayoutContainer();
testDataGrid( mainContainer ); mainViewPort.add(mainContainer);
RootPanel.get().add(mainViewPort);
}


I was under impression that deferred command would wait until all the UI tasks are finished so the recalculate would come after the table is rendered.

darrellmeyer
20 Jun 2008, 8:46 AM
The code cannot be executed. It does not include the code for table or the code using a deferred command.


Do you mean visible or rendered?

plitvak
20 Jun 2008, 8:58 AM
First of all the clarification.
The code included here shows the case where you construct a tab panel with two tabs.
Second tab contains the table that is recalculated in a deferred command.

By definition from GWT JavaDoc:

public class DeferredCommand extends java.lang.Object

This class allows you to execute code after all currently pending event handlers have completed, using the addCommand(Command) or addCommand(IncrementalCommand) methods. This is useful when you need to execute code outside of the context of the current stack.


The code below fills in the table and recalculate it in the deferred command that according to the GWT will execute after all pending event handlers, which means (in my understanding) that table already rendered by that time.
Adding a visibility check (in the code below commented out) prevents an exception from happening.

Code:


package gwt_15_Gxt_10_Test.client;

import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.util.Theme;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.table.Table;
import com.extjs.gxt.ui.client.widget.table.TableColumn;
import com.extjs.gxt.ui.client.widget.table.TableColumnModel;
import com.extjs.gxt.ui.client.widget.table.TableItem;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Command;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class Gwt_15_Gxt_10_Test1 implements EntryPoint
{
/**
* This is the entry point method.
*/
public void onModuleLoad()
{
Viewport mainViewPort;
LayoutContainer mainContainer;

GXT.setDefaultTheme( Theme.GRAY, true );

mainViewPort = new Viewport();
mainViewPort.setLayout( new FitLayout() );

mainContainer = new LayoutContainer();

TabPanel tabPanle = new TabPanel();

TabItem item = new TabItem( "Empty" );
tabPanle.add( item );

item = new TabItem( "Grid" );
tabPanle.add( item );

final Table table = new Table( new TableColumnModel( new TableColumn("Col1", "Col1"), new TableColumn("Col2", "Col2") ) );
item.add( table );

mainContainer.add( tabPanle );

mainViewPort.add(mainContainer);
RootPanel.get().add(mainViewPort);

DeferredCommand.addCommand( new Command(){
public void execute()
{
table.removeAll();
for( int i = 0; i < 10; i++ ) {
table.add( new TableItem( new Object[]{"1_"+i, "2_"+i} ) );
}
//if( table.isVisible() ) {
table.recalculate();
//}
}
} );
}
}
Exception:


java.lang.NullPointerException: null
at com.extjs.gxt.ui.client.widget.table.Table.onResize(Table.java:694)
at com.extjs.gxt.ui.client.widget.table.Table.recalculate(Table.java:416)
at gwt_15_Gxt_10_Test.client.Gwt_15_Gxt_10_Test1$1.execute(Gwt_15_Gxt_10_Test1.java:58)
at com.google.gwt.user.client.CommandExecutor.doExecuteCommands(CommandExecutor.java:311)
at com.google.gwt.user.client.CommandExecutor$2.run(CommandExecutor.java:206)
at com.google.gwt.user.client.Timer.fireImpl(Timer.java:164)
at com.google.gwt.user.client.Timer.fireAndCatch(Timer.java:150)
at com.google.gwt.user.client.Timer.fire(Timer.java:142)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)

darrellmeyer
20 Jun 2008, 9:06 AM
isVisible return false if the component is not rendered, so render is the issue. DeferredCommand deals with event processing which has nothing to do with component rendering. If you are trying to simulate a scenerio where the insert code happens after the table has been rendered and displayed, you can have the code execute when you click or button, or use a Timer.

plitvak
20 Jun 2008, 9:17 AM
Ok, here is the example with a button, produces the exception as well:


package gwt_15_Gxt_10_Test.client;

import com.extjs.gxt.ui.client.GXT;
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.util.Theme;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.extjs.gxt.ui.client.widget.Viewport;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.table.Table;
import com.extjs.gxt.ui.client.widget.table.TableColumn;
import com.extjs.gxt.ui.client.widget.table.TableColumnModel;
import com.extjs.gxt.ui.client.widget.table.TableItem;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.RootPanel;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class Gwt_15_Gxt_10_Test1 implements EntryPoint
{
/**
* This is the entry point method.
*/
public void onModuleLoad()
{
Viewport mainViewPort;
LayoutContainer mainContainer;

GXT.setDefaultTheme( Theme.GRAY, true );

mainViewPort = new Viewport();
mainViewPort.setLayout( new FitLayout() );

mainContainer = new LayoutContainer();

TabPanel tabPanle = new TabPanel();

TabItem item = new TabItem( "Empty" );
tabPanle.add( item );

item = new TabItem( "Grid" );
tabPanle.add( item );

final Table table = new Table( new TableColumnModel( new TableColumn("Col1", "Col1"), new TableColumn("Col2", "Col2") ) );
item.add( table );

mainContainer.add( tabPanle );

Button b = new Button("Test");
b.addSelectionListener( new SelectionListener<ComponentEvent>(){
public void componentSelected( ComponentEvent ce ) {
table.removeAll();
for( int i = 0; i < 10; i++ ) {
table.add( new TableItem( new Object[]{"1_"+i, "2_"+i} ) );
}
table.recalculate();
}
} );

mainContainer.add(b);

mainViewPort.add(mainContainer);
RootPanel.get().add(mainViewPort);
}
}




java.lang.NullPointerException: null
at com.extjs.gxt.ui.client.widget.table.Table.recalculate(Table.java:433)
at gwt_15_Gxt_10_Test.client.Gwt_15_Gxt_10_Test1$1.componentSelected(Gwt_15_Gxt_10_Test1.java:60)
at com.extjs.gxt.ui.client.event.SelectionListener.handleEvent(SelectionListener.java:20)
at com.extjs.gxt.ui.client.event.SelectionListener.handleEvent(SelectionListener.java:1)
at com.extjs.gxt.ui.client.event.BaseObservable.fireEvent(BaseObservable.java:74)
at com.extjs.gxt.ui.client.widget.Component.fireEvent(Component.java:398)
at com.extjs.gxt.ui.client.widget.button.Button.onClick(Button.java:437)
at com.extjs.gxt.ui.client.widget.button.Button.onComponentEvent(Button.java:235)
at com.extjs.gxt.ui.client.widget.Component.onBrowserEvent(Component.java:620)
at com.google.gwt.user.client.DOM.dispatchEventImpl(DOM.java:1308)

darrellmeyer
20 Jun 2008, 9:30 AM
You stack trace indicates you are not using the latest code that does the render check in recalculate. Your code works fine with the updated Table class.

FYI, the table is not rendered until you click on the grid tab, as tab panel lazy renders its tabs.

plitvak
20 Jun 2008, 9:32 AM
ok, thanks, the latest code you've mentioned, is it RC1 or current trunk?

darrellmeyer
20 Jun 2008, 9:32 AM
RC1 No, SVN Yes