BlackBerry Forums Support Community               

Closed Thread
 
LinkBack Thread Tools
Old 12-23-2008, 06:35 AM   #1 (permalink)
New Member
 
Join Date: May 2008
Model: 8330
Carrier: Sprint
Posts: 14
Post Thanks: 0
Thanked 0 Times in 0 Posts
Default ListField scrolling

Please Login to Remove!

I have read many other posts on ListField scrolling and they have helped me to get this far, but now I am stuck. I have my list field in a VerticalManager with scrolling working. I have it set up so that there are 5 visible rows in the ListField. However, when I scroll past the last visible row (currently there are a total of 9 rows in the list), the rows no longer paint the text of the row. I have developed a Custom ListField implementation that has a foreground and background color. The idea is that as each row is focused, the foreground and background color switch - the selected row has navy background with white text and unselected rows have white background with navy text. Works great for the visible rows, but when I scroll past row 5 to reveal the invisible rows, they are just painting with the navy background and no white text. Here is my custom list field class (which was based off of something I found either on a forum or in the knowledge base):


Code:
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.ListField;

public class ColoredListField extends ListField
{
    private boolean hasFocus = false;
    private final int fixedWidth;
    private int fgcolor;
    private int bgcolor;
    private final int fixedHeight;

    public ColoredListField(int width, int height, int fgcolor, int bgcolor)
    {
        this.fixedWidth = width;
        this.fixedHeight = height;
        this.fgcolor = fgcolor;
        this.bgcolor = bgcolor;
    }

    public int getPreferredWidth()
    {
        return fixedWidth;
    }

    public void layout(int width, int height)
    {
        setExtent(fixedWidth, fixedHeight);
    }

    public int moveFocus(int amount, int status, int time)
    {
        invalidate(getSelectedIndex());
        return super.moveFocus(amount, status, time);
    }

    public void onFocus(int direction)
    {
        hasFocus = true;
        super.onFocus(direction);
        invalidate();
    }

    public void onUnfocus()
    {
        hasFocus = false;
        super.onUnfocus();
        invalidate();
    }

    public void paint(Graphics graphics)
    {
        // Get the current clipping region as it will be the only part that
        // requires repainting
        XYRect redrawRect = graphics.getClippingRect();
        if (redrawRect.y < 0)
            throw new IllegalStateException(
                "The 'y' variable of the clipping " +
                "rectangle is < 0: " + redrawRect.y);

        // If the ListField has focus determine the selected row.
        int rowHeight = getRowHeight();
        int currEntry = redrawRect.y / rowHeight;
        int lastVisibleEntry = (redrawRect.y + redrawRect.height - 1) / rowHeight;
        lastVisibleEntry = Math.min(lastVisibleEntry, getSize() - 1);
        int y = currEntry * rowHeight;

        int curSelected = hasFocus ? getSelectedIndex() : -1;
        // Draw each row
        for (; currEntry <= lastVisibleEntry; ++currEntry)
        {
            graphics.setColor(currEntry == curSelected ? bgcolor : fgcolor);
            graphics.fillRect(0, y, redrawRect.width, rowHeight);
            graphics.setColor(currEntry == curSelected ? fgcolor : bgcolor);
            graphics.drawText(getCallback().get(this, currEntry).toString(), 0,
                y);
            // Assign new values to the y axis moving one row down.
            y += rowHeight;
        }
    }
}
Here is how I instantiate the class:


Code:
    private int screenW = Graphics.getScreenWidth(); 
    private int screenH = Graphics.getScreenHeight();
    private int listWidth = (int) (screenW * 0.95);
    private int listHeight = (int) (screenH * 0.4);
    private ColoredListField myListField = new ColoredListField(
        listWidth, listHeight, selectedFGColor, selectedBGColor);

Also, here is my callback:


Code:
private static class DiaryEntryListCallback implements ListFieldCallback
    {
        private DiaryEntry[] diaryEntryList;

        public DiaryEntryListCallback() throws Exception
        {
            diaryEntryList = new DiaryEntry[0];
            init();
        }

        public void init() throws Exception
        {
            DiaryEntry[] tmpDiaryEntryList =
                DiaryDAO.instance().getDiaryEntriesAsArray(true);
            if (tmpDiaryEntryList != null && tmpDiaryEntryList.length > 0)
                diaryEntryList = tmpDiaryEntryList;
            else
            {
                diaryEntryList = new DiaryEntry[1];
                diaryEntryList[0] = new DiaryEntry("No data",
                    Calendar.getInstance());
            }
        }

        public void init(DiaryEntry[] diaryEntries) throws Exception
        {
            diaryEntryList = diaryEntries;
        }

        public int getNumberOfRows()
        {
            return diaryEntryList.length;
        }

        public void drawListRow(ListField l, Graphics g, int index, int y, int w)
        {
            // drawing text is handled by the custom list field implementation
        }

        public Object get(ListField listField, int index)
        {
            return diaryEntryList[index];
        }

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

        public int indexOfList(ListField listField, String prefix, int start)
        {
            int size = diaryEntryList.length;
            for (int i = 0; i < size; i++)
            {
                DiaryEntry currEntry = (DiaryEntry) diaryEntryList[i];
                if (currEntry.getEntryText().toLowerCase().startsWith(
                    prefix.toLowerCase()))
                    return i;
            }
            return listField.getSelectedIndex();
        }
    }
And here is where I build the main screen, adding the list field and other fields to it:


Code:
private void createMainScreen()
    {
        mainMgr = new ColoredVerticalManager(selectedBGColor,
            Manager.USE_ALL_HEIGHT);
        listMgr = new ColoredVerticalManager(
            selectedBGColor,
            Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR);
        mainMgr.add(diaryEntriesLabel = new FixedWidthLabelField(
            "Diary Entries:", listWidth, -1, selectedFGColor, selectedBGColor));
        try
        {
            listCallback = new DiaryEntryListCallback();
            diaryEntriesListField.setSize(listCallback.getNumberOfRows());
            diaryEntriesListField.setCallback(listCallback);
            diaryEntriesListField.setFocusListener(new DiaryFocusListener());
            listMgr.add(diaryEntriesListField);
            mainMgr.add(listMgr);
        }
        catch (Exception e)
        {
            Dialog.alert("Error loading diary entry list: " + e.getMessage());
        }
        mainMgr.add(selectedEntryLabel = new FixedWidthLabelField(
            "Selected Entry:", -1, -1, selectedFGColor, selectedBGColor));
        mainMgr.add(diaryEntry);
        add(mainMgr);
    }

Any clues as to why when scrolling past the visible rows, it stops painting?



Thanks,

Steve
Offline  
Old 12-23-2008, 11:58 AM   #2 (permalink)
Thumbs Must Hurt
 
Join Date: Dec 2005
Model: 8310
Carrier: Rogers
Posts: 138
Post Thanks: 0
Thanked 0 Times in 0 Posts
Default

drawListRow is called by the ListField with the correct clipping context already set up for you. I suggest drawing your items there.
Offline  
Old 12-24-2008, 12:48 PM   #3 (permalink)
New Member
 
Join Date: May 2008
Model: 8330
Carrier: Sprint
Posts: 14
Post Thanks: 0
Thanked 0 Times in 0 Posts
Default ListField Scrolling

Thanks for the suggestion. I did that, and it didn't change the result. The result is exactly the same. Here is the code:

Code:
        public void drawListRow(ListField l, Graphics g, int index, int y, int w)
        {
            ColoredListField clf = (ColoredListField) l;
            g.setColor(index == l.getSelectedIndex() ? clf.getBGColor() : clf.getFGColor());
            g.fillRect(0, y, w, l.getRowHeight());
            g.setColor(index == l.getSelectedIndex() ? clf.getFGColor() : clf.getBGColor());
            g.drawText(get(l, index).toString(), 0, y);
        }
Offline  
Old 12-25-2008, 06:57 AM   #4 (permalink)
New Member
 
Join Date: May 2008
Model: 8330
Carrier: Sprint
Posts: 14
Post Thanks: 0
Thanked 0 Times in 0 Posts
Default ListField Scrolling - another clue

I just noticed that going through the debugger, the 'drawListRow' method is initially getting called with index 0, 1, 2, 3, 4 (i.e. it is displaying the 1st 5 visible rows). Then, when I scroll to the 6th row (index 5), and the 1st row (index 0) scrolls out of view, 'drawListRow' is only getting called 4 times - with index 1, 2, 3, 4. However, I would expect that it would be called 5 times with index 1, 2, 3, 4, 5, since row 1 (index 0) has now scrolled out of view and row 6 (index 5) has now scrolled into view. I think this is definitely a clue as to what is going on. Maybe it is scrolling within the Manager, but the ListField itself is not scrolling the elements?
Offline  
Old 12-28-2008, 08:20 AM   #5 (permalink)
New Member
 
Join Date: May 2008
Model: 8330
Carrier: Sprint
Posts: 14
Post Thanks: 0
Thanked 0 Times in 0 Posts
Default ListField Scrolling

I just found out that it is only scrolling the vertical manager - it is not actually scrolling the list field. I found this out by giving the vertical manager a different background color and I could see that the even though in the debugger the selected index of the list field was correct, the list field was not scrolling down to show the selected index (e.g. 5). So, now, I took out the vertical manager that contained the list field and just added the list field to the 'mainMgr' and the list field is not scrolling at all, so I'm back to my original issue - the list field with a fixed height simply does not scroll. Has anyone gotten this to work?

In my opinion, it seems like the framework is not working as I would expect for a fixed height list (taking up 40% of the height of the screen) with vertical scrolling. So, I'm thinking about going back to the approach of just completely implementing the painting myself. I would get the total height of the repaint rect and divide that by the row height to tell me how many rows to paint. I would always have to track the range of visible rows (start index to end index). This could be based on the current selected index and the previous selected index to indicate a scroll direction. I'm sure it will be complicated, but that seems like my only option now...


Thanks,

Steve

Last edited by swarsa : 12-28-2008 at 09:09 AM.
Offline  
Old 12-30-2008, 06:53 AM   #6 (permalink)
New Member
 
Join Date: May 2008
Model: 8330
Carrier: Sprint
Posts: 14
Post Thanks: 0
Thanked 0 Times in 0 Posts
Default Issue resolved - finally!

Hello all, the issue has been resolved thanks to a guy with a screen name 'Shubhangi' on the RIM forum. Basically, he told me to remove the overridden layout method from my listfield subclass. He also told me to add the following 2 methods to the VerticalManager containing the list:

public int getPreferredHeight()
{
return fixedHeight;
}

protected void sublayout(int width, int height)
{
super.sublayout(width, fixedHeight);
setExtent(width, fixedHeight);
}

As well as making sure to use the styles Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR, which I was already doing. I have posted the full solution over on the RIM forum.

Thanks for all your time on this one,
Steve
Offline  
Closed Thread


Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On





Copyright 2004-2014 BlackBerryForums.com.
The names RIM and BlackBerry are registered Trademarks of BlackBerry Inc.