Ecere SDK/eC Forums • View topic - [Solved]How to iterate through ListBox




Ecere SDK/eC Forums

Ecere Developers Community

[Solved]How to iterate through ListBox

General help with the Ecere Cross Platform GUI toolkit: Window, common controls, events, etc.
Help with the 2D Graphics library: Surface, Display, Bitmap, Font and others.

[Solved]How to iterate through ListBox

Postby samsam598 » Tue Sep 13, 2011 2:55 am

Hi,

I want to pick every row of a given listBox but are not able to find the right method.Could you please figure me out?
Code: Select all
 
 
double Calculate()
{ 
     uint i;
     uint counts=listBox1.rowCount;
     double result=0.0f;
 
     for(i=0;i<counts;i++)
    {
        result+=atof(listBox1.row[i].string);//===>how to iterate each row?
    }
    if(counts)
         result/=counts;
   return result;
 
}
 
Last edited by samsam598 on Wed Sep 14, 2011 4:38 am, edited 1 time in total.
samsam598
 
Posts: 208
Joined: Thu Apr 14, 2011 9:44 pm

Re: How to iterate through ListBox

Postby jerome » Tue Sep 13, 2011 10:38 am

Sam,

Just like with child windows, you can use ListBox::firstRow and DataRow::next to iterate through the rows:
Code: Select all
   double Calculate()
   { 
      uint counts=listBox1.rowCount;
      double result=0.0f;
      DataRow row;
 
      for(row = listBox1.firstRow; row; row = row.next)
         result+=atof(row.string);
      if(counts)
         result/=counts;
      return result;   
   }


It might be interesting to point out that a ListBox in Ecere is a flexible data control that can work with any datatypes(s). You could store the number as doubles within the list box this way:
Code: Select all
import "ecere"
 
class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   size = { 640, 480 };
 
   ListBox listBox1 { this, text = "listBox1", size = { 156, 132 }, position = { 128, 96 } };
   DataField df { class(double) };
   Form1()
   {
      listBox1.AddField(df);
      listBox1.AddRow().SetData(df, 4.5);
      listBox1.AddRow().SetData(df, 2.4);
      listBox1.AddRow().SetData(df, 5.9);
 
      PrintLn(Calculate());
   }
 
   double Calculate()
   { 
      uint counts=listBox1.rowCount;
      double result = 0;
      DataRow row;
      for(row = listBox1.firstRow; row; row = row.next)
         result += row.GetData(df);
      if(counts)
         result/=counts;
      return result;   
   }
}
 
Form1 form1 {};
jerome
Site Admin
 
Posts: 623
Joined: Sat Jan 16, 2010 11:16 pm

Re: [Solved]How to iterate through ListBox

Postby samsam598 » Wed Sep 14, 2011 4:43 am

Cool.

How to make use of ListBox and DataField to create a database grid?Or any other solution should be fine also.Please note I need the headers as well.Thanks.
-----------------------------------------------------------------
ID |姓名 |出生日期 |喜好 |
-----------------------------------------------------------------
0001 | 王小早 |1987/06/26|打球、下棋、听音乐 |
-----------------------------------------------------------------
samsam598
 
Posts: 208
Joined: Thu Apr 14, 2011 9:44 pm

Re: [Solved]How to iterate through ListBox

Postby jerome » Wed Sep 14, 2011 10:35 am

Sam,

Here's sample code for a grid view ListBox. It uses 'ShortDate.ec' in sdk/extras, you need to add the file to the project.
Code: Select all
import "ecere"
import "ShortDate"
 
class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   nativeDecorations = true;
   hasClose = true;
   size = { 640, 480 };
 
   ListBox listBox1 { this, hasHeader = true, moveFields = true, moveRows = true, resizable = true, sortable = true, size = { 500, 132 }, position = { 20, 96 } };
 
   DataField dfId { class(uint), width = 40, header = "ID" };
   DataField dfName { class(String), width = 100, header = "姓名", editable = true };
   DataField dfBirthday { class(ShortDate), width = 80, header = "出生日期", editable = true };
   DataField dfHobbies { class(String), width = 200, header = "喜好", editable = true };
 
   Form1()
   {
      DataRow row;
 
      listBox1.AddField(dfId);
      listBox1.AddField(dfName);
      listBox1.AddField(dfBirthday);
      listBox1.AddField(dfHobbies);
 
      row = listBox1.AddRow();
      row.tag = 1;
      row.SetData(dfId, 1);
      row.SetData(dfName, "王小早");
      row.SetData(dfBirthday, Date { 1987, june, 26 });
      row.SetData(dfHobbies, "打球、下棋、听音乐");
 
      row = listBox1.AddRow();
      row.tag = 2;
      row.SetData(dfId, 2);
      row.SetData(dfName, "王小早 2");
      row.SetData(dfBirthday, Date { 1988, june, 26 });
      row.SetData(dfHobbies, "打球、下棋、听音乐");
   }
}
 
Form1 form1 {};


The ListBox control is also a TreeView :D (treeBranches = true, collapseControl = true)

You can also use EDA to plug in a database directly, e.g. with eda::Table::GUIListBoxAddFields and eda::Table::GUIListBoxAddRowsField. This will automatically add DataFields and DataRows to the ListBox.

Regards,

Jerome
jerome
Site Admin
 
Posts: 623
Joined: Sat Jan 16, 2010 11:16 pm

Re: [Solved]How to iterate through ListBox

Postby samsam598 » Wed Sep 14, 2011 8:15 pm

Thanks Jerome,that's great!
After adding double-click event,noticed there is a sligth problem,when double click on the second row,the sort order of the both row changed.Don't know why.
Code: Select all
 
import "ecere"
import "ShortDate"
class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   size = { 640, 480 };
   nativeDecorations = true;
 
   DataField dfId
      {
          class(uint), width = 40,
          header = "ID"
      };
   DataField dfName
      {
          class(String), width = 100,
          header = "姓名", editable = true
      };
   DataField dfBirthday
      {
          class(ShortDate), width = 80,
          header = "出生日期", editable = true
      };
   DataField dfHobbies
      {
          class(String), width = 200,
          header = "喜好", editable = true
      };
   ListBox listBox1
      {
      this, size = { 500, 132 }, position = { 24, 24 }, moveRows = true, true, true, hasHeader = true, sortable = true;
 
      bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
      {
         char* name=listBox.currentRow.GetData(dfName);
         int id=listBox.currentRow.GetData(dfId);
         char IDstr[3];
         char temp[20];
         sprintf(IDstr,":ID=%d",id);
         strcpy(temp,name);
         strcat(temp,IDstr);
 
         MessageBox{contents=temp}.Modal();
         delete name;
         return true;
      }
   };
 
   Form1()   
      {
               DataRow row;       
               listBox1.AddField(dfId);     
               listBox1.AddField(dfName);     
               listBox1.AddField(dfBirthday);     
               listBox1.AddField(dfHobbies);       
               row = listBox1.AddRow();     
               row.tag = 1;     
               row.SetData(dfId, 1);     
               row.SetData(dfName, "王小早");     
               row.SetData(dfBirthday, Date { 1987, june, 26 });     
               row.SetData(dfHobbies, "打球、下棋、听音乐");       
               row = listBox1.AddRow();     
               row.tag = 2;     
               row.SetData(dfId, 2);     
               row.SetData(dfName, "王小早 2");     
               row.SetData(dfBirthday, Date { 1988, june, 26 });     
               row.SetData(dfHobbies, "打球、下棋、听音乐");   
        }
}
Form1 form1 {};
 


And one more question,trying win32 API PlaySound in a new added button event caused the app failed to build.
Code: Select all
 
Compiling...
grid.ec
   grid.ec:1:1: error: Couldn't open obj/debug.win32\grid.sym
 
grid (Debug) - 1 error, no warning         

Last time I encountered the same issue when I tried win32 API ShellExecute,since it failed,I use ShellOpen in the eC SDK.Below is the full source code with the issue.Please also note I've added winmm(.a) in the linker and placed the sound file in the project folder.
Code: Select all
 
#ifdef __WIN32__
#define WIN32_LEAN_AND_MEAN
#include <windefs.h>
#include <windows.h>
#include <mmsystem.h>
#endif       
 
 
import "ecere"
import "ShortDate"
class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   size = { 640, 480 };
   nativeDecorations = true;
 
   DataField dfId
      {
          class(uint), width = 40,
          header = "ID"
      };
   DataField dfName
      {
          class(String), width = 100,
          header = "姓名", editable = true
      };
   DataField dfBirthday
      {
          class(ShortDate), width = 80,
          header = "出生日期", editable = true
      };
   DataField dfHobbies
      {
          class(String), width = 200,
          header = "喜好", editable = true
      };
   Button button1
   {
      this, text = "button1", position = { 384, 192 };
 
      bool NotifyClicked(Button button, int x, int y, Modifiers mods)
      {
         PlaySound("hellowin.wav", NULL, SND_FILENAME | SND_ASYNC);
         return true;
      }
   };
   ListBox listBox1
      {
      this, size = { 500, 132 }, position = { 24, 24 }, moveRows = true, true, true, hasHeader = true, sortable = true;
 
      bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
      {
         char* name=listBox.currentRow.GetData(dfName);
         int id=listBox.currentRow.GetData(dfId);
         char IDstr[3];
         char temp[20];
         sprintf(IDstr,":ID=%d",id);
         strcpy(temp,name);
         strcat(temp,IDstr);
 
         MessageBox{contents=temp}.Modal();
         delete name;
         return true;
      }
   };
 
   Form1()   
      {
               DataRow row;       
               listBox1.AddField(dfId);     
               listBox1.AddField(dfName);     
               listBox1.AddField(dfBirthday);     
               listBox1.AddField(dfHobbies);       
               row = listBox1.AddRow();     
               row.tag = 1;     
               row.SetData(dfId, 1);     
               row.SetData(dfName, "王小早");     
               row.SetData(dfBirthday, Date { 1987, june, 26 });     
               row.SetData(dfHobbies, "打球、下棋、听音乐");       
               row = listBox1.AddRow();     
               row.tag = 2;     
               row.SetData(dfId, 2);     
               row.SetData(dfName, "王小早 2");     
               row.SetData(dfBirthday, Date { 1988, june, 26 });     
               row.SetData(dfHobbies, "打球、下棋、听音乐");   
        }
}
Form1 form1 {};                               
 
samsam598
 
Posts: 208
Joined: Thu Apr 14, 2011 9:44 pm

Re: [Solved]How to iterate through ListBox

Postby jerome » Wed Sep 14, 2011 8:53 pm

Hi Sam,

I noticed a couple of problems in your NotifyDoubleClick method.

First, you're deleting 'name' which was obtained through 'DataRow::GetData'.
The data belongs to the ListBox, so you should not delete that (it causes all kinds of problems when I ran your sample).

Then you have a buffer overflow when using sprintf with IDstr, you're putting at least 6 characters (:,I,D,=,1,\0) in that buffer and you only reserved space for 3. I suggest you make it bigger, like 30. temp is a bit on the small size as well, if you have a bigger name, keep in mind most Chinese characters will take up 3 bytes each in UTF-8 encoding.

Finally, since the ListBox has 'moveRows' set to true, when you click and drag a row it automatically drags it around. That's the behavior that you're seeing as changing the sort order, it's triggered after the NotifyDoubleClick finishes. To prevent this from happening, simply return 'false' from NotifyDoubleClick, and the ListBox will not continue processing the current mouse event. Of course you can also disable the moveRows functionality (it's normally not used in conjunction with 'sortable').

Here's your updated NotifyDoubleClick:
Code: Select all
      bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
      {
         char* name=listBox.currentRow.GetData(dfName);
         int id=listBox.currentRow.GetData(dfId);
         char IDstr[100];
         char temp[200];
         sprintf(IDstr,":ID=%d",id);
         strcpy(temp,name);
         strcat(temp,IDstr);
 
         MessageBox{contents=temp}.Modal();
         return false;
      }


Regards,

Jerome
jerome
Site Admin
 
Posts: 623
Joined: Sat Jan 16, 2010 11:16 pm

Re: [Solved]How to iterate through ListBox

Postby jerome » Wed Sep 14, 2011 9:02 pm

Sam,

The following will build:
Code: Select all
#ifdef __WIN32__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#endif
#undef MessageBox

It seems that windefs.h is conflicting with a lot of eC data types, so it it would just be a matter of singling which ones are problematic and renaming them temporarily with #define / #undef macros around the #include command, but you don't need to include it anyways.

Cheers,

Jerome
jerome
Site Admin
 
Posts: 623
Joined: Sat Jan 16, 2010 11:16 pm

Re: [Solved]How to iterate through ListBox

Postby samsam598 » Wed Sep 14, 2011 9:33 pm

Thank you Jerome,all fixed!!
samsam598
 
Posts: 208
Joined: Thu Apr 14, 2011 9:44 pm

Re: [Solved]How to iterate through ListBox

Postby samsam598 » Thu Sep 15, 2011 4:48 am

One more question,sorry!
If I wrote a separate function which will fill in the listBox with data and then pass the function to the form's constructor,the app will compile,but when runs,it will crash.So what makes this difference?
Code: Select all
 
Form1()
{
  //fill in listBox with data,fine
}
 

but this one won't work properly:
Code: Select all
 
void FillListBox()
{
   //fill in listBox with data
}
Form1()
{
    FillListBox();
}
 

This won't neither:
Code: Select all
 
void FillListBox(ListBox listBox1)
{
   //same code as in the original example
}
Form1()
{
    FillListBox(listBox1);
}
 
samsam598
 
Posts: 208
Joined: Thu Apr 14, 2011 9:44 pm

Re: [Solved]How to iterate through ListBox

Postby jerome » Thu Sep 15, 2011 9:13 am

Sam,

It really doesn't make any difference. The problem must be somewhere else.
Could you please paste the entire sample that crashes?

EDIT: I've managed to reproduce it, and found that the problem is a char buffer (name[10], in this case) too small again. This works:
Code: Select all
 
import "ecere"
import "ShortDate"
class Form1 : Window
{
   text = "Form1";
   background = activeBorder;
   borderStyle = sizable;
   hasMaximize = true;
   hasMinimize = true;
   hasClose = true;
   hasStatusBar = true;
   size = { 640, 480 };
   anchor = { horz = -3, vert = -5 };
   nativeDecorations = true;
 
   DataField dfId
   {
       class(uint),
       width = 40, header = "ID"
   };
   DataField dfName
   {
       class(String),
       width = 100, header = "姓名", editable = true  ; 
   };
   DataField dfBirthday
   {
       class(ShortDate),
       width = 80, header = "出生日期", editable = true
   };
   DataField dfHobbies
   {
       class(String),
       width = 200, header = "喜好", editable = true
   };
   ListBox listBox1
   {
      this, foreground = darkCyan, font = { "Tahoma", 10 }, anchor = { left = 0, top = 0, right = 0, bottom = 0 }, moveRows = true, hasHeader = true, sortable = true;
 
      bool NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods)
      {
         char* name=listBox.currentRow.GetData(dfName);
         int id=listBox.currentRow.GetData(dfId);
         char IDstr[100];
         char temp[200];
         sprintf(IDstr,":ID=%d",id);
         strcpy(temp,name);
         strcat(temp,IDstr);
 
         //show name and ID you've selected in the statusBar:
         statusBar.text=temp;
 
         return false;
      }
   };
 
   void FillListBoxes()
   {
       DataRow row;
       int i;
       char name[100]; 
       char hobbies[200]; 
       listBox1.AddField(dfId);     
       listBox1.AddField(dfName);     
       listBox1.AddField(dfBirthday);     
       listBox1.AddField(dfHobbies);   
       for(i=0;i<50;i++)
       {
          sprintf(name,"王小早(%d)",i+1);
          sprintf(hobbies,"打球、下棋、听音乐 (%d)",i+1); 
          row = listBox1.AddRow();     
          row.tag = i+1;     
          row.SetData(dfId, i+1);     
          row.SetData(dfName,name);     
          row.SetData(dfBirthday, Date { 1960+i, june, 26 });     
          row.SetData(dfHobbies, hobbies);       
 
       }             
   }
 
   Form1()   
   {
      FillListBoxes();
   }
}
Form1 form1 {};


Thanks,

Jerome
jerome
Site Admin
 
Posts: 623
Joined: Sat Jan 16, 2010 11:16 pm

Next

Return to GUI Toolkit & 2D Graphics

Who is online

Users browsing this forum: No registered users and 9 guests

cron