Using Grids

This section guides you through two example applications: SimpleGrid and MarkableGrid. SimpleGrid covers the basics of using grids. Specifically, it shows you how to define a grid using resources, create a concrete grid class, and then draw the grid. MarkableGrid looks at markable grids, which are used much as markable lists are. It covers creating a markable grid, setting the icons for a markable grid, and drawing the grid.

As in the Using Vertical Lists section, each of the grid examples employs a very simple user interface, with each example incrementally building on the previous example. This section will only discuss features in the code that are new to each example. Similarly, many aspects of the code are the same as those in the vertical list examples discussed in the Using Vertical Lists section of this chapter ” duplicated code is not discussed here.

GMS Grid

The example SimpleGrid displays a number of card games that a player can choose from, as shown in Figure 7-22. Each item represents one game and consists of an icon and a caption. Selecting an item starts the selected game. As this is not a full application, no code is included to actually play the game ”instead an empty method is called ( PlaySelectedGame() ).

Figure 7-22. SimpleGrid screen.


Defining a Grid Using Resources

You define the grid in a GRID resource, as shown in SimpleGrid.rss for the SimpleGrid example:

 RESOURCE GRID R_SIMPLEGRID_GAMES_GRID    {    array_id = r_simplegrid_games_grid_items;    flags = EAknListBoxSelectionGrid;    style = r_simplegrid_games_grid_style;    } 

The flags field determines the type of grid, in this case a selection grid. (Refer back to Table 7-4 for other options.) The array_id field refers to an array of LBUF strings, which defines the items contained in the grid. As usual, you should localize the text for the items in an appropriate resource file. Each grid item comprises of a number of fields separated by a tab character ( \t ) ”for example:

 #define GAMES_GRID_ITEM1_TEXT "0\tSnap" 

As with lists, the number indicates an icon in the icon array. However, the tab character only separates the fields rather than indicating their position in the grid cell . You will see how the position is determined shortly when subcells are discussed. See Adding Icons to a List and the SimpleList example in the Using Vertical Lists section for details on setting the icon array.

Series 60 ignores the height and width flags in the GRID resource, but these values can be specified in the GRID_STYLE resource. The emptytext field can be overridden to supply a string which displays when the grid is empty. You should not change the version field.

The style value refers to a GRID_STYLE resource:

 RESOURCE GRID_STYLE r_simplegrid_games_grid_style    {    layoutflags = EAknGridHorizontalOrientation EAknGridLeftToRight  EAknGridTopToBottom;    // horizontal scroll    primaryscroll = EAknGridFollowsItemsAndLoops;    // vertical scroll    secondaryscroll = EAknGridFollowsItemsAndLoops;    // number of items horizontally per screen    itemsinprimaryorient = 3;    // number of items vertically per screen    itemsinsecondaryorient = 2;    gapwidth = 5;    gapheight = 5;    height = 68;    width = 50;    } 

The GRID_STYLE resource determines the layout of the grid, but not the layout of individual cells .

The layout_flags field indicates how the grid appends items. You need to specify an orientation flag. In this case, EAknGridHorizontalOrientation is used to indicate that the grid will append items to rows and will append additional rows as necessary. If you choose a vertical orientation, using EAknVerticalOrientation , the grid will append items to columns and append additional columns as necessary.

You also specify flags to indicate how the grid should add rows, and how it should add items to rows. In SimpleGrid , EAknGridTopToBottom indicates that the grid should add new rows from top to bottom and EAknGridLeftToRight that it should add items to rows from left to right.

In a horizontal orientation, primaryscroll indicates how horizontal scrolling will behave, and secondaryscroll relates to vertical scrolling. In a vertical orientation, these are reversed : primaryscroll indicates vertical scrolling and secondaryscroll indicates horizontal scrolling.

In this case, primaryscroll and secondaryscroll are set to EAknGridFollowsItemsAndLoops . This flag means that as you scroll in one direction, the focus moves from one item to the next until you reach the end of the row or column. At this point, if you scroll in the same direction again, it will either: loop round to the other end of the same row or column, or snake to the other end of the next row or column. Whether it loops or snakes depends on the orientation of the grid. When scrolling in the same plane as the orientation ”for example, scrolling to the right in a horizontally oriented grid ”it will snake. When scrolling in the other plane ”for example, scrolling down in a horizontally oriented grid ”it will loop.

So, when scrolling to the right in a horizontally oriented grid, the focus moves along the items in a row from left to right. If, when the focus reaches the last item in the row, you scroll right again, it then moves to the first item on the next row. When you reach the last item of the last row, scrolling will continue at the first item of the first row. Figure 7-23 depicts this scenario.

Figure 7-23. Horizontal scrolling to right with loop in a horizontally oriented grid.


If you are scrolling down in a horizontally oriented grid and the focus reaches the last item in the column, then, if you scroll down again, the focus will move to the first item in the same column. Table 7-8 provides the details of possible types of scrolling.

The values for itemsinprimaryorient and itemsinsecondaryorient determine the horizontal and vertical dimensions of the grid. In the SimpleGrid example there are three items in each row and two in each column. (In a vertical orientation, itemsinprimaryorient indicates the number of items in each column and itemsinsecondaryorient the number in each row.)

When working out the values for itemsinprimaryorient and itemsinsecondaryorient , you should select values that will fit comfortably on one screen. If you select more items in an orientation than will fit on the screen, the scrolling might not work as you would expect. Items will only scroll once you pass the final item in the orient , regardless of whether it is visible on screen.


The gapwidth and gapheight fields determine the amount of space between each cell in pixels.

Table 7-8. Grid Primary and Secondary Scrolling

Type

Scrolling Behavior at Edge in Vertically Oriented Grids

Scrolling Behavior at Edge in Horizontally Oriented Grids

EAknGridFollowsItemsAndStops

Horizontal : Stops .

Vertical : Snakes . Except when moving up from the first cell in last the grid or down from the last cell in the grid where it stops .

Horizontal : Snakes . Except when moving left from the first cell in the grid or right from the cell in the grid where it stops .

Vertical : Stops.

EAknGridFollowsItemsAndLoops

Horizontal : Loops.

Vertical : Snakes . Additionally, moves to the first cell when moving down from the last cell in the grid, and to the last cell when moving up from the first cell in the grid.

Horizontal : Snakes . Additionally, moves to the first cell when moving right from the last cell, and to the last cell when moving left from the first cell.

Vertical : Loops .

EAknGridFollowsGrid

Horizontal : Loops.

Vertical : Loops.

Horizontal : Loops.

Vertical : Loops.

EAknGridStops

Horizontal : Stops.

Vertical : Stops.

Horizontal : Stops.

Vertical : Stops.

EAknGridIncrementLineAndLoops

Horizontal : Loops.

Vertical : Snakes . Additionally, moves to the first cell when moving down from the last cell in the grid, and to the last cell when moving up from the first cell in the grid.

Horizontal : Snakes . Additionally, moves to the first cell when moving right from the last cell, and to the last cell when moving left from the first cell.

Vertical : Loops.

EAknGridIncrementLineAndStops

Horizontal : Snakes . Except when moving left from the first cell in the grid or right from the last cell in the grid, where it stops .

Horizontal : Snakes. Except when moving left from the first cell in the grid or right from the last cell in the grid, where it stops.

Vertical : Snakes . Except when moving up from the first cell in the grid or down from the last cell in the grid, where it stops.

Vertical : Snakes . Except when moving up from the first cell in the grid or down from the last cell in the grid, where it stops .


The height and width fields determine the size of each cell in pixels. You set the size according to the exact layout you require. For SimpleGrid , a 50 by 50-pixel bitmap was created for the icons; the graphics should appear above the text and take up approximately 18 pixels. A width of 50 and a height of 68 were therefore set.

Possible values of flags , primaryscroll and secondaryscroll are provided in Table 7-8 .

Creating a Concrete Grid Class

You will need to implement your grid as a class derived from CAknGrid . In the SimpleGrid example, the grid class is CSimpleGridGrid . This is contained within a standard Symbian OS container CSimpleGridContainer . The code for the AppUi and Container will not be analyzed in depth here, as there is little difference between it and the code in the vertical list examples. There are, however, a few points worthy of note:

  • In the AppUi, the container is constructed using new(Eleave) , and the MOP parent is set before calling ConstructL() , rather than calling NewL() and then setting the MOP parent. This is because the scroll bars will appear only if the MOP parent is set before the call to ConstructL() .

  • In the container's SizeChanged() method, the extent of the grid is set using Rect().Size() , rather than the grid's minimum size. This is because using the minimum size affects the redrawing of the grid when scrolling.

The grid needs to construct itself from resource, set up its icons and then display itself. This is performed in CSimpleGridGamesGrid::ConstructL() , which is called from the container. The container passes the resources for the icon file name (R_ICON_FILE_NAME) and the grid (R_SIMPLEGRID_GAMES_GRID) , which was defined previously in Defining a Grid Using Resources .

 void CSimpleGridGamesGrid::ConstructL(TInt aGridResource, TInt aIconFileResource) { TResourceReader reader; CEikonEnv::Static()->CreateResourceReaderLC(reader, aGridResource); ConstructFromResourceL(reader); CleanupStack::PopAndDestroy(); SetupGridIconsL(aIconFileResource); SizeChanged(); } 

The base class has a ConstructFromResourceL() method, which you should call with a resource reader created using the GRID resource. Once constructed, you can set up the icons for the grid. This is performed by calling the SetupGridIconsL() method. Apart from the difference in the actual icons, the code for adding icons is the same as for lists. See the SimpleList example in the Using Vertical Lists section for details of how to add icons.

You do not need to set up the scroll bars for the grid as you did with lists. CAknGrid takes care of them for you.


The last thing you need to do is draw the grid. You do this by overriding its SizeChanged() method.

 void CSimpleGridGamesGrid::SizeChanged()    {    CAknGrid::SizeChanged();    SetupGrid();    } void CSimpleGridGamesGrid::SetupGrid()    {    // Setup text foreground and background colours to default    AknListBoxLayouts::SetupStandardGrid(*this);    // Get local copies of data we will need    CFormattedCellListBoxItemDrawer* itemDrawer =       this->ItemDrawer();    TInt cellWidth = ColumnWidth();    TInt cellHeight = ItemHeight();    // Set up graphics subcells    AknListBoxLayouts::SetupFormGfxCell(       *this,        //the grid       itemDrawer,   // the grid's drawer       0,            // index of the graphic within item strings       0,            // left position       0,            // top position       0,            // right - unused       0,            // bottom - unused       cellWidth,    // width of graphic       KGraphicsHeight,             // height of graphic       TPoint(0, 0), // start position       TPoint(cellWidth , KGraphicsHeight)); // end position    // Set up text subcells    const CFont* KFont = LatinBold12();    TInt baseline = cellHeight - KFont->DescentInPixels() - 1;    // N.B. although color is commented out    // in the header file, it is still used!    AknListBoxLayouts::SetupFormTextCell(       *this,        // the grid       itemDrawer    // the grid's drawer       1,            // index of text within item strings       KFont,        // the font for the text       KTextColor,   // the color of the text       0,            // left margin       0,            // right margin - unused       baseline,     // Baseline       cellWidth,    // text width (take margin into account if set)       CGraphicsContext::ECenter     // Alignment       TPoint(0, KGraphicsHeight)    // start position       TPoint(cellWidth, cellHeight) // end position    } 

You should call the base class SizeChanged() method, so that you retain important functionality in your overridden method. Then you set up the cell layout using a number of static methods defined in AknListBoxLayouts .

The default foreground and background colors are set using the SetupStandardGrid() method. You can determine how the graphics and text will appear in each cell by setting up the subcells using SetupFormGfxCell() for the graphics subcell and SetupFormTextCell() for the text subcell. Each method has an index parameter, which refers to the position in the item strings of the graphic or text. All item strings used here are of the form " n\tText ", where n is an icon number and Text is the text that will appear beneath that icon. Therefore, the index provided for the graphics subcell is 0 (the first position in the string), and the index for the text subcell is 1 (second position). When setting up the graphics subcell you must provide the following parameters:

  • A reference to the grid itself.

  • The grid's drawer.

  • The index, as already discussed.

  • Left position ”the position in pixels relative to the left-hand side of the cell.

  • Top position ”the position in pixels relative to the top side of the cell.

  • The width of the graphic.

  • The height of the graphic.

  • Start position ”the coordinates of the start of the graphic.

  • End position ”the coordinates of the end of the graphic.

When setting up the text subcell you must provide the following parameters:

  • The grid itself.

  • The grid's drawer.

  • The index, as already discussed.

  • The font.

  • The color of the text as a TInt ”this is an index into the color palette, the values of which can be found in the Appendix of the Series 60 UI guide, part of the SDK documentation.

  • Left margin position ”position in pixels relative to the left-hand side of the cell.

  • Baseline position ”the position between the ascent and descent of the font. See Chapter 11 or the SDK documentation ( Character ascent, descent, height and baseline ) for further information.

  • The width of the text.

  • The alignment of the text.

  • Start Position ”the coordinates of the start of the text area.

  • End Position ”the coordinates of the start of the text area.

The header file comments out the color parameter of AknListBoxLayouts::SetupFormTextCell() , but it is actually used.


Markable Grids

The MarkableGrid example displays a list of saved games. Each list item has an icon representing the game, and a single line of text representing the name, as shown in Figure 7-24. When you select an item from the list, a tick appears beneath it. You can delete marked items by selecting Delete from the Options menu.

Figure 7-24. MarkableGrid screen.


Creating a Markable Grid

You need to define a grid resource and set the flags to EAknListBoxMarkableGrid to indicate a markable grid. The item strings will need to include the unmarked icon. For example:

 #define GAMES_GRID_ITEM1_TEXT "2\tGame 1\t1" 

The first field defines the index of the icon representing the game, the second defines the name, and the third is the index of the unmarked item icon.

Setting Markable Grid Icons

You will need two additional icons, to denote the marked and unmarked states, which you should add to the icon array.

In code, the markable grid is more akin to a multiselection list than to a markable list. That is, you provide two marking icons: one to represent a marked item and one to represent an unmarked one. In the MarkableGrid example, a blank icon is provided to represent an unmarked item, meaning that the markable grid will have the same behavioral characteristics as a markable list.

In the MarkableList example, it was necessary for the marking icon to be the first element in the icon array. With markable grids, it is up to you to decide which element the icon appears in. In order to remain consistent with markable list behavior, the MarkableGrid example uses the first element in the array.

Drawing a Markable Grid

As in the SimpleGrid example, you set the layout of the grid in the SizeChanged() method. This time, you need to change the layout of the cells to accommodate the marking item. You will need to adjust height, width, start and end positions accordingly , and you can add another graphics subcell, by calling SetupFormGfxCell() . Then you need to call methods on the item drawer to allow marking to occur. In MarkableList these steps are performed in CMarkableGridGamesGrid::SetupGrid() :

 ... itemDrawer->SetItemMarkPosition(2); if (!iMarkOnValue)    {    iMarkOnValue = StringLoader::LoadL(R_MARKABLEGRID_MARK_ON_VALUE);    } // the index of the mark on icon itemDrawer->SetItemMarkReplacement(*iMarkOnValue); // Don't display all items as marked initially itemDrawer->SetItemMarkReverse(ETrue); ... 

The SetItemMarkPosition() method sets the position in the item string of the unmarked item.

When an item is marked, the framework alters the item string such that the marking icon number replaces the nonmarking icon number. In the MarkableGrid example, "2\tGame 1\t1" would become "2\tGame 1\t0" when marked. You use the SetItemMarkReplacement() method to specify what replaces the unmarked icon in the string. This is a descriptor, which you should define in a resource file and set to the position of the marking icon in the icon array (in this case "0" ).

Finally, you should call SetItemMarkReverse() . This determines whether the icon replacement occurs when an item is marked or unmarked. Setting it to Etrue ensures that the marking icon will appear when the item is marked.



Developing Series 60 Applications. A Guide for Symbian OS C++ Developers
Developing Series 60 Applications: A Guide for Symbian OS C++ Developers: A Guide for Symbian OS C++ Developers
ISBN: 0321227220
EAN: 2147483647
Year: 2003
Pages: 139

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net