Search code examples
blackberrylistfielddraw-list

Displaying extra rows in a ListField


I'm trying to display an extra row at the top of a ListField - called "Add Item" and it almost works, but the very last row "Item 4" of my data is not displayed.

Screenshot, 1 row is missing

How would you fix this issue?

Please see my very simple test code MyList.java below:

package mypackage;

import java.util.*;
import net.rim.device.api.collection.*;
import net.rim.device.api.collection.util.*; 
import net.rim.device.api.system.*;
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.ui.decor.*;
import net.rim.device.api.util.*;

public class MyList extends UiApplication {
    public static void main(String args[]) {
        MyList app = new MyList();
        app.enterEventDispatcher();
    }

    public MyList() {
        pushScreen(new MyScreen());
    }
} 

class MyScreen extends MainScreen {

    ObjectListField myList = new ObjectListField() {
        public void drawListRow(ListField list,
                        Graphics g,
                        int index,
                        int y,
                        int width) {
            if (index == 0) {
                Font i = getFont().derive(Font.ITALIC);
                g.setFont(i);
                g.drawText("Add Item", 0, y);
            } else {
                String str = (String) get(this, index - 1);
                g.drawText(str, 0, y);
            }                
        }

        protected boolean navigationClick(int status, int time) {
            int index = myList.getSelectedIndex();
            String str = (index > 0 ? (String) get(this, index - 1) : 
                "Add item");
            Status.show("You have clicked: " + str);
            return true;
        }
    };

    public MyScreen() {
        setTitle("How to display an extra row?");
        myList.set(new String[]{"Item 1","Item 2","Item 3","Item 4",});
        // myList.setSize(5);
        add(myList);
    }
}

I've tried adding myList.setSize(5); but get an ArrayIndexOutOfBoundsException thrown by Vector.elementAt(4)

UPDATE:

On Michael's suggestion I've switched from ObjectListField to KeywordFilterField (which is what I actually use in my real program) and now I can call myList.setSize(5) without any exception being thrown.

But the last row is still not displayed:

screenshot

package mypackage;

import java.util.*;
import net.rim.device.api.collection.*;
import net.rim.device.api.collection.util.*; 
import net.rim.device.api.system.*;
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.ui.decor.*;
import net.rim.device.api.util.*;

public class MyList extends UiApplication {
    public static void main(String args[]) {
        MyList app = new MyList();
        app.enterEventDispatcher();
    }

    public MyList() {
        pushScreen(new MyScreen());
    }
} 

class MyScreen extends MainScreen {
    static final int EXTRA_ROWS = 1;

    MyItemList myItems = new MyItemList();
    KeywordFilterField myList = new KeywordFilterField() {
        protected boolean navigationClick(int status, int time) {
            int index = getSelectedIndex();
            String str = (index < EXTRA_ROWS ? "Add item" :
                ((MyItem) getElementAt(index - EXTRA_ROWS)).toString());
            Status.show("You have clicked - " + str);
            return true;
        }
    };

    public MyScreen() {
        setTitle(myList.getKeywordField());
        myList.setSourceList(myItems, new MyItem.MyProvider());
        myItems.doAdd(new MyItem(1, "Eins"));
        myItems.doAdd(new MyItem(2, "Zwei"));
        myItems.doAdd(new MyItem(3, "Drei"));
        myItems.doAdd(new MyItem(4, "Vier"));

        myList.setSourceList(myItems, new MyItem.MyProvider());
        myList.setCallback(new MyListFieldCallback());
        myList.setSize(myItems.size() + EXTRA_ROWS);
        myList.updateList();
        add(myList);
    }

    private class MyListFieldCallback implements ListFieldCallback {

        public void drawListRow(ListField list, Graphics g, int index, int y, int width) {
            if (index < EXTRA_ROWS) {
                Font i = getFont().derive(Font.ITALIC);
                g.setFont(i);
                g.drawText("Add Item", 0, y);
                return;
            } 

            if (index >= EXTRA_ROWS) {
                MyItem item = (MyItem) ((KeywordFilterField) list).getElementAt(index - EXTRA_ROWS);
                g.drawText(item.toString(), 0, y);
                return;
            }

            g.drawText(list.getEmptyString(), 0, y);
        }

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

        public int getPreferredWidth(ListField listField) { 
            return 0; 
        }

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

class MyItemList extends SortedReadableList {
    public MyItemList() {
        super(new MyItem.MyComparator());        
    } 

    protected void doAdd(Object obj) {
        super.doAdd(obj);   
    }

    protected boolean doRemove(Object obj) {
        return super.doRemove(obj);        
    }
}

class MyItem {
    int _num;
    String _name;

    public MyItem(int num, String name) {
        _num = num;
        _name = name;
    }

    public String toString() {
        return _num + ": " + _name;
    }

    static class MyComparator implements Comparator {
        public int compare(Object obj1, Object obj2) {
            MyItem item1 = (MyItem) obj1;
            MyItem item2 = (MyItem) obj2;

            return item1.toString().compareTo(item2.toString());
        }
    }

    static class MyProvider implements KeywordProvider {
        public String[] getKeywords(Object obj) {
            MyItem item = (MyItem) obj;
            return new String[]{ Integer.toString(item._num), item._name };
        }
    }
}

I have a feeling, that setSize(4) (instead of 5) is called inbetween - because I see the last row for a moment and then it disappears again.

Thank you! Alex


Solution

  • Here is my own solution - override the setSize() of the ListField:

    enter image description here

    (the screenshot above has EXTRA_ROWS = 3, which still works ok).

    package mypackage;
    
    import java.util.*;
    import net.rim.device.api.collection.*;
    import net.rim.device.api.collection.util.*; 
    import net.rim.device.api.system.*;
    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.ui.decor.*;
    import net.rim.device.api.util.*;
    
    public class MyList extends UiApplication {
        public static void main(String args[]) {
            MyList app = new MyList();
            app.enterEventDispatcher();
        }
    
        public MyList() {
            pushScreen(new MyScreen());
        }
    } 
    
    class MyScreen extends MainScreen {
        static final int EXTRA_ROWS = 3;
    
        MyItemList myItems = new MyItemList();
        KeywordFilterField myList = new KeywordFilterField() {
            protected boolean navigationClick(int status, int time) {
                int index = getSelectedIndex();
                String str = (index < EXTRA_ROWS ? "Add item" :
                    ((MyItem) getElementAt(index - EXTRA_ROWS)).toString());
                Status.show("You have clicked - " + str);
                return true;
            }
    
            public void setSize(int count) {
                super.setSize(count + EXTRA_ROWS);
            }
        };
    
        public MyScreen() {
            setTitle(myList.getKeywordField());
            myList.setSourceList(myItems, new MyItem.MyProvider());
            myItems.doAdd(new MyItem(1, "Eins"));
            myItems.doAdd(new MyItem(2, "Zwei"));
            myItems.doAdd(new MyItem(3, "Drei"));
            myItems.doAdd(new MyItem(4, "Vier"));
    
            myList.setSourceList(myItems, new MyItem.MyProvider());
            myList.setCallback(new MyListFieldCallback());
            add(myList);
        }
    
        private class MyListFieldCallback implements ListFieldCallback {
    
            public void drawListRow(ListField list, Graphics g, int index, int y, int width) {
                if (index < EXTRA_ROWS) {
                    Font i = getFont().derive(Font.ITALIC);
                    g.setFont(i);
                    g.drawText("Add Item", 0, y);
                    return;
                } 
    
                if (index >= EXTRA_ROWS) {
                    MyItem item = (MyItem) ((KeywordFilterField) list).getElementAt(index - EXTRA_ROWS);
                    g.drawText(item.toString(), 0, y);
                    return;
                }
    
                g.drawText(list.getEmptyString(), 0, y);
            }
    
            public Object get(ListField listField, int index) { 
                return null; 
            }
    
            public int getPreferredWidth(ListField listField) { 
                return 0; 
            }
    
            public int indexOfList(ListField listField, String prefix, int start) { 
                return 0; 
            }
        }
    }
    
    class MyItemList extends SortedReadableList {
        public MyItemList() {
            super(new MyItem.MyComparator());        
        } 
    
        protected void doAdd(Object obj) {
            super.doAdd(obj);   
        }
    
        protected boolean doRemove(Object obj) {
            return super.doRemove(obj);        
        }
    }
    
    class MyItem {
        int _num;
        String _name;
    
        public MyItem(int num, String name) {
            _num = num;
            _name = name;
        }
    
        public String toString() {
            return _num + ": " + _name;
        }
    
        static class MyComparator implements Comparator {
            public int compare(Object obj1, Object obj2) {
                MyItem item1 = (MyItem) obj1;
                MyItem item2 = (MyItem) obj2;
    
                return item1.toString().compareTo(item2.toString());
            }
        }
    
        static class MyProvider implements KeywordProvider {
            public String[] getKeywords(Object obj) {
                MyItem item = (MyItem) obj;
                return new String[]{ Integer.toString(item._num), item._name };
            }
        }
    }