Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

Reply
New Developer
keslabs
Posts: 10
Registered: ‎05-25-2009
My Device: Not Specified
Accepted Solution

ListField: RENDERER updates only top row

[ Edited ]

Hey all,

 

First time caller, long time listener. I'm cutting my teeth on BB dev and have hit a snag. I've created a ListField that takes in an array of custom RowObjects that includes not only the array that makes up the row, but styling (Background Color, Text Color) properties as well.

 

My 2 issues are that the only the first row is getting it's background color and the rest are default. None are getting the Text Color. It seems like the Renderer is only being called once, which absolutely boggles me.

 

The second issue is that I can't seem to get it scroll horizontally to show the additional columns that are out of screen.

 

The main TableField components code:

 

package com.keslabs.kui; import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.container.*; public class TableField extends ListField { private TableRowManager[] _rows; private int[] _columnWidths; private int[] _horizontalPaddings; public TableField(TableRowObject[] contents, int[] columnWidths, int[] horizontalPaddings) { int numRows = contents.length; _rows = new TableRowManager[numRows]; for (int curRow = 0; curRow < numRows; curRow++) { _rows[curRow] = new TableRowManager(contents[curRow]); } // Store the layout data. _columnWidths = columnWidths; _horizontalPaddings = horizontalPaddings; // Configure this ListField to operate with TableListField semantics. setSize(numRows); setCallback(RENDERER); } // Calculates the horizontal position at which the indicated // column should begin, based on the column widths and paddings. private int getColumnStart(int col) { int columnStart = 0; for (int i = 0; i < col; i++) { columnStart += _columnWidths[i]; columnStart += _horizontalPaddings[i]; } return columnStart; } public int moveFocus(int amount, int status, int time) { invalidate(getSelectedIndex()); return super.moveFocus(amount, status, time); } // Invoked when this field receives the focus. public void onFocus(int direction) { super.onFocus(direction); invalidate(); } // Invoked when a field loses the focus. public void onUnfocus() { super.onUnfocus(); invalidate(); } // Manager that lays out the fields of a table row horizontally, // within the columns of its enclosing TableListField. private class TableRowManager extends Manager { private TableRowObject _row; // styles public int bgcolor = Color.BEIGE; public int fgcolor = Color.BLUE; // Constructor. The elements of rowContents are added to this manager // so that when it is layed out, these fields become cells within a row. public TableRowManager(TableRowObject rowContents) { super(0); if (rowContents.bgcolor != -1) { bgcolor = rowContents.bgcolor; } if (rowContents.fgcolor != -1) { fgcolor = rowContents.fgcolor; } _row = rowContents; for (int col = 0; col < rowContents.data.length; col++) { add(rowContents.data[col]); } } // Causes the fields within this row manager to be layed out then // painted. public void drawRow(ListField listField, int index, Graphics g, int x, int y, int width, int height) { // Arrange the cell fields within this row manager. layout(width, height); // Place this row manager within its enclosing list. setPosition(x, y); // Apply a translating/clipping transformation to the graphics // context so that this row paints in the right area. g.pushRegion(getExtent()); // Paint this manager's controlled fields. subpaint(g); g.setColor(bgcolor); g.fillRect(0, y, width, height); g.setColor(fgcolor); //g.drawText("i-"+index, 0, y); listField.invalidate(index); // Restore the graphics context. g.popContext(); } protected void sublayout(int width, int height) { for (int col = 0; col < getFieldCount(); col++) { Field curCellField = getField(col); layoutChild(curCellField, _columnWidths[col], getPreferredHeight()); setPositionChild(curCellField, getColumnStart(col), 0); } setExtent(getPreferredWidth(), getPreferredHeight()); } public int getPreferredWidth() { return RENDERER.getPreferredWidth(TableField.this); } public int getPreferredHeight() { return getRowHeight(); } } private static final ListFieldCallback RENDERER = new ListFieldCallback() { public void drawListRow(ListField listField, Graphics graphics, int index, int y, int width) { TableField tableField = (TableField) listField; TableRowManager rowManager = tableField._rows[index]; rowManager.drawRow(listField, index, graphics, 0, y, width, tableField.getRowHeight()); } public int getPreferredWidth(ListField listField) { TableField tableField = (TableField) listField; int numColumns = tableField._columnWidths.length; return tableField.getColumnStart(numColumns); } public Object get(ListField listField, int index) { TableField tableField = (TableField) listField; return tableField._rows[index]; } // prefix searching is not supported public int indexOfList(ListField listField, String prefix, int start) { return -1; } }; }

 

The TableRowObject class (which works fine, but I posted for ease of understanding):

 

 

package com.keslabs.kui; import net.rim.device.api.ui.*; import net.rim.device.api.ui.component.*; import net.rim.device.api.ui.container.*; import net.rim.device.api.system.*; public class TableRowObject { public Field[] data; public int bgcolor = -1; public int fgcolor = -1; public TableRowObject(Field[] rowContent) { data = rowContent; } }

 


Any help that could be provided would be great as I've been stuck with this for 3 days banging my head against a wall.

Message Edited by keslabs on 05-26-2009 01:42 PM
Please use plain text.
Developer
Developer
mb1
Posts: 318
Registered: ‎05-26-2009
My Device: Not Specified

Re: ListField: RENDERER updates only top row

It looks like you are trying to implement a custom ListField. In that case your 'custom Field class' needs to implement the ListFieldCallback interface.

 

Something like:

 

class MyListField extends ListField implements ListFieldCallback {

};

 

I would recommend going through the following KB article:

 

http://www.blackberry.com/knowledgecenterpublic/livelink.exe/fetch/2000/348583/800332/800505/800345/...

 

 

Also  search for 'custom ListField blackberry'  at Yahoo/Google to understand how a custom ListField should be implemented.

 

--MB

Please use plain text.
New Developer
keslabs
Posts: 10
Registered: ‎05-25-2009
My Device: Not Specified

Re: ListField: RENDERER updates only top row

Perhaps I'm mistaken, but isn't an interface only implemented on strict OO inheritance?

 

This is based off of a RIM example and is delegating the redraw of each row to the inherited ListField method of drawRow.

 

I'll take another look at the implementation you suggested and what you mentioned. Cheers.

Please use plain text.
Developer
Developer
mb1
Posts: 318
Registered: ‎05-26-2009
My Device: Not Specified

Re: ListField: RENDERER updates only top row

My guess is that the ListField class calls the drawListRaw of the callback listener, with the appropriate arguments when you invalidate it or when the row gets invalidated for some other reason.

 

In your MyListField class you would have to call setCallback(this);

 

--MB.

Please use plain text.
New Developer
keslabs
Posts: 10
Registered: ‎05-25-2009
My Device: Not Specified

Re: ListField: RENDERER updates only top row

If I understand you correctly, you're saying to localize the Callback to inside the class itself?
Please use plain text.
Developer
Developer
mb1
Posts: 318
Registered: ‎05-26-2009
My Device: Not Specified

Re: ListField: RENDERER updates only top row

yes, but it doesn't necessarily have to be 'this'. It can be any other object as you have done  in  your implementation.
Please use plain text.
New Developer
keslabs
Posts: 10
Registered: ‎05-25-2009
My Device: Not Specified

Re: ListField: RENDERER updates only top row

For some reason it began working properly after converting from an instance of ListFieldCallback to a class implementing it as you suggested.

 

Specifically:

 

From private static final ListFieldCallback RENDERER = new ListFieldCallback()

To public class TableRowRenderer implements ListFieldCallback

 

and adding it to my class.

 

Many thanks for your help... I sincerely appreciate it.

 

Cheers.

Please use plain text.