MultiColumnList

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Revision as of 19:27, 29 September 2005 by Jamhap (Talk | contribs)

Jump to: navigation, search

Since I have been harping about documentation in the forums, I thought it best that I put my money where my mouth is. I am not an expert but I would like to share what I have learned and gleaned about the MultiColumnList widget.

If you are familiar with the Listbox widget then the MultiColumnList will be a natural progression for you. The one thing you need to remember is that every column entry in the MultiColumnList will have its own instance of a ListboxItem or ListboxTextItem. The MultiColumnList has some very nice features built directly into the widget. By default your users can: a) re-arrange the column display order; b) sort (Ascending and Descending) rows by a column; c) change the width of a column. These features can be disabled.

API References: MultiColumnList ListboxItem ListboxTextItem WindowManager

Please note that the following example source code was gleaned and edited from project specific code so there may be some syntax errors.

Creating the MultiColumnList in code

Take a look at this code on how we create the MultiColumnList window:

// Get the CEGUI Window Manager
CEGUI::WindowManager *mWinMgr = CEGUI::WindowManager::getSingletonPtr();

// Create the CEGUI MultiColumnList window
CEGUI::MultiColumnList *mListBox = (CEGUI::MultiColumnList *)mWinMgr->createWindow(
(CEGUI::utf8*)CEGUILOOK"/MultiColumnList", (CEGUI::utf8*)"MyListBox");
// Don't forget to add this window to another window and set its other properties
// like position, size, etc. Use the methods you prefer.
mListBox->setPosition( CEGUI::Point(0.05f, 0.1f) );
mListBox->setSize( CEGUI::Size(0.90f, 0.80f) );
// mSomeWindow->addChild(mListBox);

// Set the users selection ability
mListBox->setSelectionMode(CEGUI::MultiColumnList::SelectionMode::RowMultiple);

// Add some column headers
mListBox->addColumn("Column1", 0, 0.10f);
mListBox->addColumn("Column2", 1, 0.25f);
mListBox->addColumn("Column3", 2, 0.25f);
mListBox->addColumn("Column4", 3, 0.45f);

// I don't know why, but you have set the column header widths via this function.
// The Column Header widths are not assumed from the "addColumn" function. Bug?
mListBox->setColumnHeaderWidth(0, 0.10f);
mListBox->setColumnHeaderWidth(1, 0.25f);
mListBox->setColumnHeaderWidth(2, 0.25f);
mListBox->setColumnHeaderWidth(3, 0.45f);


Note these lines in the code:

// I don't know why, but you have set the column header widths via this function.
// The Column Header widths are not assumed from the "addColumn" function. Bug?
mListBox->setColumnHeaderWidth(0, 0.10f);
mListBox->setColumnHeaderWidth(1, 0.25f);
mListBox->setColumnHeaderWidth(2, 0.25f);
mListBox->setColumnHeaderWidth(3, 0.45f);

If you don't set the column header widths with the setColumnHeaderWidth() method then the columns will appear to be stacked on top of one another. This may be a bug in the library. The numbers I used for the widths are arbitrary. You can make them anything you like.

!! WARNING !! Take note that you should not follow each addColumn() with a setColumnHeaderWidth(). Create all the columns first and then set the column widths. Not following this will yield unreliable column size results.

In other words DO NOT DO THIS

// Add some column headers
mListBox->addColumn("Column1", 0, 0.10f);
mListBox->setColumnHeaderWidth(0, 0.10f);
mListBox->addColumn("Column2", 1, 0.25f);
mListBox->setColumnHeaderWidth(1, 0.25f);
mListBox->addColumn("Column3", 2, 0.25f);
mListBox->setColumnHeaderWidth(2, 0.25f);
mListBox->addColumn("Column4", 3, 0.45f);
mListBox->setColumnHeaderWidth(3, 0.45f);

Adding Data

Now, lets create a method to add data to our MultiColumnList. Review this code:

void addListboxItem(char *c1, char *c2, char *c3, char *c4, bool isSelected)
{
  // First, we need to add a new row to the Listbox
  // mListBox is from the above code, its a class global pointer in my code.
  // If you want, you can singleton() the Listbox or pass the pointer to this function.
  unsigned int mRow = mListBox->addRow();

  // Remember, each column is a 'ListboxTextitem' so we need to
  // create a new instance for each column.

  // Column1
  // Create our ListboxTextItem instance...
  CEGUI::ListboxTextItem* item = new CEGUI::ListboxTextItem((CEGUI::utf8*)c1, 0);
  // Note that in 'setItem' we specify '0' for the index/column we want this
  // ListboxTextItem to be attached too.
  mListBox->setItem(item, 0, mRow);
  // Should it be selected? I know this appears weird but yes you can have columns be
  // selected or not selected. In other words, its not ROW based, its COLUMN based 
  // selection. Why? more options and flexibilty!
  item->setSelected(isSelected);
  // Don't forget to set the selection brush or your item won't get highlighted.
  item->setSelectionBrushImage( (CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MultiListSelectionBrush");
  // You could attach some data to this column that is important to you by
  // using the 'setUserData' function. Each column could point to a different
  // user data source or the same user data source, or nothing at all.
  // item->setUserData(MyPointerToSomeData);

  // Column2
  item = new CEGUI::ListboxTextItem((CEGUI::utf8*)c2, 0);
  mListBox->setItem(item, 1, mRow);
  item->setSelected(isSelected);
  item->setSelectionBrushImage( (CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MultiListSelectionBrush");

  // Column3
  item = new CEGUI::ListboxTextItem((CEGUI::utf8*)c3, 0);
  mListBox->setItem(item, 2, mRow);
  item->setSelected(isSelected);
  item->setSelectionBrushImage( (CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MultiListSelectionBrush");

  //Column4
  item = new CEGUI::ListboxTextItem((CEGUI::utf8*)c4, 0);
  mListBox->setItem(item, 3, mRow);
  item->setSelected(isSelected);
  item->setSelectionBrushImage( (CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MultiListSelectionBrush");

} // addListboxItem


Now, somewhere in your code, call the addListboxItem function like this:

  ...
  addListboxItem("Item1 Col1", "Item1 Col2", "Item1 Col3", "Item1 Col4", true);
  addListboxItem("Item2 Col1", "Item2 Col2", "Item2 Col3", "Item2 Col4", false);
  addListboxItem("Item3 Col1", "Item3 Col2", "Item3 Col3", "Item3 Col4", false);
  addListboxItem("Item4 Col1", "Item4 Col2", "Item4 Col3", "Item4 Col4", true);
  ...

You will note that in the above source code I have specified two rows to be highlighted. This is possible because of the

mListBox->setSelectionMode(CEGUI::MultiColumnList::SelectionMode::RowMultiple);

statement from above. Review the API documentation about the setSelectionMode. You can make it single row based or column based.

Program this and give it a try. When you run your program don't forget to re-arrange the column order (drag and drop the column header), resize columns and double click a column header to sort the rows via the clicked column.

Other Notable Items

At least one column is required. You must have defined at least one column using the addColumn() method or you will get an error when you attempt to insert a row using the addRow() funtion.

Odd Column Sizes. After the window is created the columns may appear funny - that is, the columns and the data won't appear aligned. There appears to be an initial 'redraw' bug in the library. If you manually resize a column (yes, with the mouse like in windows) it will correct the column layout, spacing and alignment. Also remember that you should not follow each addColumn() with a setColumnHeaderWidth(). Create all the columns first and then set the column widths. Not following this will yield unreliable column size results. See the example above.

Drag and Drop. As of version 0.4.0 you can not use the CEGUI Drag and Drop feature with ListboxTextItem. Drag and Drop only works with Window based widgets right now.