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
Posts: 36
Registered: ‎01-07-2010
My Device: Torch 9800
My Carrier: Rogers

List (or TableView) with headers

Hello,

 

I'm using BB SDK 6.0 and trying to achieve this look from http://docs.blackberry.com/en/developers/deliverables/17971/Lists_and_tables_1111481_11.jsp :

 

ListWithHeaders.jpg

 

I have list of objects that contain several properties each, which need to be grouped by the date.

How can i achieve this - using lists or TableView? I couldn't understand from the article.

Does anyone have some piece of code to share? Any ideas will be appreciated.

Thank you.

 

 

 

Developer
Posts: 2,268
Registered: ‎07-08-2009
My Device: various
My Carrier: various

Re: List (or TableView) with headers

The article is useless, as is the corresponding PDF document (the link to the PDF is at the top of the article). The PDF is a necessary introduction to BlackBerry UI in general, so read it through anyway. Also, read the API documentation on ListField, ListFieldCallback and, potentially, ObjectListField.

 

Incredibly, there aren't any terribly useful examples in the knowledge base as well. Do check them, though - type "ListField" in the search box, choose 'Knowledge Base' in the drop-down list next to it and hit search. Colored ListField and ListField with checkboxes are the two most useful ones. Download the code and study it.

 

If you are stuck, post here again. Good luck!

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
New Developer
Posts: 36
Registered: ‎01-07-2010
My Device: Torch 9800
My Carrier: Rogers

Re: List (or TableView) with headers

Thank you for the suggestions. I found those examples and also some other ones too and I managed to do something, but still have problems.

 

When I open the screen for the first time, it looks OK, almost exactly as I want it to look, with some minor details that I need to change.

 

But when I go through the items of the list, i see overlapped controls. Date headers are put on top of the actual first item of that date (see the image). First image is how the list looks like first time after openning, second one is when I highlight second item in the list, then the first item under header appear and third one is how the list looks like when i go through the each item, this is the full list.

 

Agenda.jpg

 

So either Paint method is not good, or what I think is the problem - ListFieldCallback implementation is not good.

 

In drawListRow I add two rows when date is changed - and here overlapping appears. I guess I cannot do this. I'm adding both rows in one place.

 

But how can I add those date headers if dates are not part of list collection I want to display?

Any idea? Here is my code:

 

import java.util.Calendar;
import java.util.Date;
import java.util.Vector;

import net.rim.device.api.i18n.SimpleDateFormat;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.Ui;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.ListField;
import net.rim.device.api.ui.component.ListFieldCallback;
import net.rim.device.api.ui.component.NullField;

public class AgendaListField extends ListField implements ListFieldCallback{
    
    private String strDate = "";
    private boolean isNewDate = false;
    private int rowLabelAdded = 0;
    private boolean hasFocus = false;
    
    public AgendaListField(int size){        
        super(0, ListField.MULTI_SELECT | ListField.USE_ALL_WIDTH);
        setRowHeight(50);
        setCallback(this);
        setEmptyString("No tasks!", DrawStyle.HCENTER);
        setSearchable(true);

        Vector rows = new Vector();      
        TableRowManager row;
        
        for (int i = 0; i < size; i++) {
            row = new TableRowManager();
            rows.addElement(row);
        }            
        setSize(rows.size());        
    }

    // ListFieldCallback Implementation
     public void drawListRow(ListField listField, Graphics g, int index, int y, int width) {
        
         AgendaListField list = (AgendaListField) listField;
         Task task = ActivitiesManager.getTask(index);
        
         if (task != null ){
             Calendar taskDate = task.getActivity().getStartTimeCal();
             SimpleDateFormat formatter = new SimpleDateFormat(SimpleDateFormat.DATE_LONG);
             String strFormattedDate = formatter.format(new Date(taskDate.getTime().getTime()));
            
             if ( !strFormattedDate.equals(strDate)){
                
                 isNewDate = true;
                 strDate = strFormattedDate;        
                
                 TableRowManager rowHeaderManager=new TableRowManager();
                 rowHeaderManager.drawRow(g, 0, y, Display.getWidth(), list.getRowHeight());
                
                 TableRowManager rowManager=new TableRowManager(task);
                 rowManager.drawRow(g, 0, y+50, Display.getWidth(), list.getRowHeight());
             }
             else{
                 isNewDate = false;
                 TableRowManager rowManager=new TableRowManager(task);
                 rowManager.drawRow(g, 0, y, Display.getWidth(), list.getRowHeight());                
             }    
         }        
     }

     public Object get(ListField listField, int index) {
        
         return null;
     }

     public int getPreferredWidth(ListField listField) {
        
         return Display.getWidth();
     }

     public int indexOfList(ListField listField, String prefix, int start) {
        
         return -1;
     }

     protected void setFont(Field field, int style, int size){
        field.setFont(Font.getDefault().derive(style,size,Ui.UNITS_px));
     }
        
     //Handles moving the focus within this field.
     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);
     }

     //Invoked when a field loses the focus.
     public void onUnfocus()
     {
        super.onUnfocus();
        invalidate();
     }
    
     private class TableRowManager extends Manager {
        
         Bitmap    bmpType = Bitmap.getBitmapResource("type.png");
         Bitmap    bmpRecurring = Bitmap.getBitmapResource("recurring.png");
        
         public TableRowManager(Task task) {
            super(0);
                         
            String strRegarding = "";
            boolean isRecurring = false;
            String strStartTime = "";
           
            if ( task != null ){
                strRegarding = Util.returnIfExists(task.getRegarding());
                isRecurring = task.isRecurring();
                               
                Calendar taskDate = task.getActivity().getStartTimeCal();
                SimpleDateFormat formatter = new SimpleDateFormat(SimpleDateFormat.TIME_SHORT);
                String strFormattedDate = formatter.format(new Date(taskDate.getTime().getTime()));
                
                strStartTime = strFormattedDate;             
            }
            else{
                System.out.println("Task is null");                
            }
            
            // SET THE TYPE BITMAP FIELD
            add( new BitmapField(bmpType));
            
            // SET THE REGARDING LABELFIELD
            LabelField lblRegarding = new LabelField(strRegarding, DrawStyle.ELLIPSIS);
            //setFont(lblRegarding, Font.BOLD, 18);
            add(lblRegarding);
            
            // SET THE START TIME LABELFIELD
            LabelField lblStartTime = new LabelField(strStartTime, DrawStyle.ELLIPSIS);
            setFont(lblStartTime, Font.PLAIN, 16);
            add(lblStartTime);
            
            // SET THE RECURRING BITMAP FIELD
            if (!isRecurring)
                add( new NullField());
            else
                add( new BitmapField(bmpRecurring));            
            
         }
        
         public TableRowManager() {
            super(0);                         
            if (isNewDate){
                    
                LabelField lblHeader = new LabelField(strDate, DrawStyle.HCENTER | Field.FIELD_VCENTER | USE_ALL_WIDTH | AgendaListField.USE_ALL_HEIGHT | NON_FOCUSABLE){
//                    protected void paintBackground(Graphics graphics)
//                    {
//                        graphics.setColor(Color.DARKGRAY);
//                        graphics.fillRect(0, 0, getWidth(), getHeight());
//                        graphics.setColor(Color.BLACK);
//                        super.paint(graphics);                    
//                    }                    
                };                
                add(lblHeader);
                rowLabelAdded++;
            }            
         }
        
         protected void setFont(Field field, int style, int size){
             field.setFont(Font.getDefault().derive(style,size,Ui.UNITS_px));
         }
        
         // Causes the fields within this row manager to be layed out then
         // painted.
         public void drawRow(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(Color.DARKGRAY);
                g.drawLine(0, 0, getPreferredWidth(), 0);
                
                // Restore the graphics context.
                g.popContext();                
                
         }

         // Arranges this manager's controlled fields from left to right within
         // the enclosing table's columns.
         protected void sublayout(int width, int height) {

             // set the size and position of each field.
             int fontHeight = Font.getDefault().getHeight();
             int preferredWidth = getPreferredWidth();
                
             if (isNewDate){
                 Field field = getField(0);
                 layoutChild(field, preferredWidth, fontHeight+1);
                 setPositionChild(field, 0, 0);
             }
             else{    
                 // start with the bitmap Field of the Type icon
                 Field field = getField(0);
                 layoutChild(field, 40, 40);
                 setPositionChild(field, 5, 15);
                
                 // set the Regarding label field
                 field = getField(1);
                 layoutChild(field, 250, fontHeight+1);
                 setPositionChild(field, 45, 5);
                            
                 // set the StartTime label field
                 field = getField(2);
                 layoutChild(field, 250, fontHeight+1);
                 setPositionChild(field, 45, 22);
                
                 // set the bitmap field of Recurring icon  
                 field = getField(3);
                 layoutChild(field, 150, 39);
                 setPositionChild(field, preferredWidth - 42, 15);
             }
             setExtent(preferredWidth, getPreferredHeight());
         }

         // The preferred width of a row is defined by the list renderer.
         public int getPreferredWidth() {
             return Display.getWidth();
         }

         // The preferred height of a row is the "row height" as defined in the
         // enclosing list.
         public int getPreferredHeight() {
             return getRowHeight();
         }        
     }
}

 

 

 

Developer
Posts: 2,268
Registered: ‎07-08-2009
My Device: various
My Carrier: various

Re: List (or TableView) with headers

I must admit - I haven't read your code fully, but drawListRow is indeed too overloaded.

 

drawListRow is not for list manipulation. It is just for visualizing the data which is already there. All you want to have there is extracting the necessary data, picking the drawing "style" (you paint Date row differently than task / appointment) and calling Graphics primitives which deal with painting (setBackgroundColor/clear; setColor; drawText; drawImage; drawBitmap; drawRect; fillRect etc.)

 

Usually, to implement ListField, you create the initial list in the constructor and manipulate it according to the user's input, fully (re)calculating your rows (including headers) and inserting them in the proper places in the list. You might have a list of tasks already in the memory, but it's not a good source for your ListField - it needs a separate array/Vector, corresponding to what you see on the screen.

 

Scratch the code and redesign it - seriously. Better find the right way now and use it over and over again in the future.

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
New Contributor
Posts: 3
Registered: ‎02-26-2013
My Device: TEST
My Carrier: TEST

Re: List (or TableView) with headers

Hi, Thanks for this article !!! When I am using the above given code I found the missing class "ActivitiesManager". Can you please provide the ActivitiesManager class. Thanks, Arun.
Developer
Posts: 17,019
Registered: ‎07-29-2008
My Device: Z10 LE, Z30, Passport
My Carrier: O2 Germany

Re: List (or TableView) with headers

welcome to the support forums.
this thread is two years old, and the class in question is most likely a component of the posters software, it is not a public api class.
you can replace it with whatever your application needs.
----------------------------------------------------------
feel free to press the like button on the right side to thank the user that helped you.
please mark posts as solved if you found a solution.
@SimonHain on twitter
Regular Contributor
Posts: 52
Registered: ‎02-26-2013
My Device: Curve 9650,Bold 9900
My Carrier: Airtel

Re: List (or TableView) with headers

[ Edited ]

Hello Sir

  I have read your code, its good and i exactly wants somrething like this.Will you please provide me the complete source code of this ui..

 

Thanks in advance

New Contributor
Posts: 3
Registered: ‎02-26-2013
My Device: TEST
My Carrier: TEST

Re: List (or TableView) with headers

Hi,

can we have the source code for above first screenshot pasted into this article of List (or TableView) with headers.

Thanks,
Arun.

Developer
Posts: 19,636
Registered: ‎07-14-2008
My Device: Not Specified

Re: List (or TableView) with headers

That screen shot is just the standard email viewer.  I am fairly confident that the source for that is not available to us. 

New Contributor
Posts: 3
Registered: ‎02-26-2013
My Device: TEST
My Carrier: TEST

Re: List (or TableView) with headers

Okay. Thanks for the update.

 

Actually we have to develop same like above, I am trying to use TableViewManager but i did't get any update regarding this on web.

 

Thanks for your help & support

 

Regards,

Arun.