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
Developer
Posts: 43
Registered: ‎12-02-2008
My Device: Curve 8330
Accepted Solution

ListField scrolling

[ Edited ]

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):

 

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:

 

    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:

 

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:

 

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

Message Edited by stevewarsa on 12-22-2008 08:34 AM
BlackBerry Development Advisor
Posts: 15,698
Registered: ‎07-09-2008
My Device: BlackBerry PRIV
My Carrier: Bell

Re: ListField scrolling

I think your code is based off of this sample:

 

How To - Create a colour ListField
Article Number: DB-00472

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

 

I ran it after adding more entries to the ListField that causes it to scroll off of the screen and it did properly display the text.  Are you able to reproduce the behaviour you are seeing with it?  If so, what BlackBerry model and handheld software version are you testing with?  You can find this under Options, About on the BlackBerry handheld.

 

If the sample doesn't trigger the problem is the issue just that the text is not showing up on the selected row or on all rows?  If it is just the selected row,are the focus colour and text colour the same?  Can you post a screen shot of the issue?

Mark Sohm
BlackBerry Development Advisor

Please refrain from posting new questions in solved threads.
Problem solved? Click the Accept As Solution button.
Found a bug? Report it using Issue Tracker
Developer
Posts: 43
Registered: ‎12-02-2008
My Device: Curve 8330

Re: ListField scrolling

[ Edited ]

Hi Mark,

 

Thank you very much for the reply and taking the time to run the code.  I really appreciate that.  Yes, I am able to reproduce the behavior consistently.  I am testing with the  Blackberry 8310 Rogers simulator (v4.2.2.163).  Compiling against the JDE 4.7.  I normally develop with NetBeans and Ant, and when I noticed the problem happening and I could not figure it out, I created a workspace and imported the files into the JDE 4.7 and started debugging it there.  Here is a screen shot where I have created 6 entries in the list and only 5 are visible.  This first screen shot has the first entry selected:

 

 

 First Entry

 

As you can see the text of the first entry is also displayed in a text area below.  Now I scroll down within the ListField until the 6th record is selected.  Here is the screen shot:

 

Sixth Entry

 

As you can see the text of the sixth entry is also displayed in a text area below (but the text is not displayed in the listfield row). Let me know if you would like more information.  Again, I sincerely thank you for your time and effort looking at this.

 

Steve

 

Message Edited by stevewarsa on 12-24-2008 07:19 AM
Message Edited by stevewarsa on 12-24-2008 08:39 AM
Developer
Posts: 43
Registered: ‎12-02-2008
My Device: Curve 8330

Re: ListField scrolling

Based on another suggestion, I moved my row painting into the  'drawListRow' method, however am receiving the exact same result.  Here is the 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);
        }
 

 

However, I just noticed something very strange... 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, 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.

Developer
Posts: 4,764
Registered: ‎07-21-2008
My Device: Not Specified

Re: ListField scrolling

You say:

 

I am testing with the  Blackberry 8310 Rogers simulator (v4.2.2.163).  Compiling against the JDE 4.7. 

 

Running code compiled on 4.7 on a lower version of OS is absolutely not recommended or supported.

 

Developer
Posts: 43
Registered: ‎12-02-2008
My Device: Curve 8330

Re: ListField scrolling

[ Edited ]

The result is the same testing on the 8310 against JDE 4.2.1.

 

Anyway, 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 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 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

Message Edited by stevewarsa on 12-28-2008 10:09 AM
Highlighted
Developer
Posts: 97
Registered: ‎07-17-2008
My Device: Not Specified

Re: ListField scrolling

Hi,

You want fixed size listfield with scrolling enabled.

Please try following solution:

Removed the following function from listfield class:

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

As you are overriding the layout of the listfield, the extent will be set as the fixed height. Hence you have noticed that vertical field manager is scrolling but listfield is not scrolling.

Please override 'sublayout' method of the 'listmgr' vertical field manager:
        VerticalFieldManager oVerticalFieldManager = new VerticalFieldManager(MainScreen.VERTICAL_SCROLL|MainScreen.VERTICAL_SCROLLBAR)
        {
            public int getPreferredHeight()
            {
                return nFixedHeight;
            }
           
            // Overriden to set the visible height for the vertical field manager.
            protected void sublayout(int width, int height)
            {
                height = nFixedHeight;
                super.sublayout(width, height);
                setExtent(width, height);
            }
        };

This code works for me very fine.

Regards,
Shubhangi
Developer
Posts: 43
Registered: ‎12-02-2008
My Device: Curve 8330

Re: ListField scrolling

Bless you my friend!  You have answered the question.  It works.  Here is the new code:

 

First the new ObjectListField subclass:

 

import net.rim.device.api.ui.Graphics; import net.rim.device.api.ui.XYRect; import net.rim.device.api.ui.component.ObjectListField; public class ColoredListField extends ObjectListField { 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 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) { hasFocus = true; super.onFocus(direction); invalidate(); } // Invoked when a field loses the focus. public void onUnfocus() { hasFocus = false; super.onUnfocus(); invalidate(); } }

Then, the place where the main screen is laid out:

 

private void createMainScreen() { mainMgr = new ColoredVerticalManager(selectedBGColor, Manager.USE_ALL_HEIGHT); listMgr = new ColoredVerticalListManager( selectedBGColor, Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR, listHeight); 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); }

Finally, the VerticalFieldManager subclass with the changes suggested by Shubhangi:

 

import net.rim.device.api.ui.Graphics; import net.rim.device.api.ui.container.VerticalFieldManager; /** * @author Steve Warsa */ public class ColoredVerticalListManager extends VerticalFieldManager { private int bgcolor; private int fixedHeight; public ColoredVerticalListManager(int bgcolor, long style, int fixedHeight) { super(style); this.bgcolor = bgcolor; this.fixedHeight = fixedHeight; } public int getPreferredHeight() { return fixedHeight; } // Overriden to set the visible height for the vertical field manager. protected void sublayout(int width, int height) { super.sublayout(width, fixedHeight); setExtent(width, fixedHeight); } public void paint(Graphics graphics) { // Sets the BackgroundColor graphics.setBackgroundColor(bgcolor); // Clears the entire graphic area to the current background graphics.clear(); super.paint(graphics); } }

 

 I hope this helps someone else avoid the frustration I endured.  Again, thanks to Shubhangi!

 

 

 


 

New Developer
Posts: 13
Registered: ‎01-08-2009
My Device: Not Specified

Re: ListField scrolling

Thank you for that post. It was very helpful to me.

I do have a question.

How do I get the vertical scroll bar to show up on the

ListField

 

Thanks in advance

Developer
Posts: 97
Registered: ‎07-17-2008
My Device: Not Specified

Re: ListField scrolling

hi,

 

Please call super() in constructor.

 

for eg:

 

class KMainScreen extends MainScreen

{

KMainScreen()

{

super();

}

}

 

 

Last time I had the same problem, but calling "super()" solved it.

Hope this helps.

 

 

 

Regards,

Shubhangi