Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Listbox Item Problems


  • Please log in to reply
9 replies to this topic

#1 HelpMePlz

HelpMePlz

    CC Newcomer

  • Member
  • PipPip
  • 20 posts

Posted 11 April 2012 - 02:46 AM

I have a couple of problems when using a list box. I have code which adds items to an empty list box depending on the contents of a file.

My first problem is - how do I edit the properties of these items once I have added them to the list box? As in, how do I edit the font, the colour etc.

My second and more difficult problem is - how do I set up events for these items which are only added to the listbox once the code is run? How do I make a procedure for when the item is clicked on?


Thanks a lot!!!
  • 0

#2 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 11 April 2012 - 04:47 AM

I have a couple of problems when using a list box. I have code which adds items to an empty list box depending on the contents of a file.

My first problem is - how do I edit the properties of these items once I have added them to the list box? As in, how do I edit the font, the colour etc.


For this, as beginner, the easiest way is by modifying the ListBox's Font property. But this way you can not modify individual item. A change in Font property will be reflected to all the items. If you really want to have different "style" for individual item, you will have to draw the items your self (usually called owner drawing), by setting the Style of the ListBox into lbOwnerDrawVariable or lbOwnerDrawFixed, properly handle OnMeasureItem event of the ListBox, and do your custom drawing in OnDrawItem event. For the mean time, I suggest to use the Font property.

My second and more difficult problem is - how do I set up events for these items which are only added to the listbox once the code is run? How do I make a procedure for when the item is clicked on?


Items in TListBox do not have event. You have to handle event of the TListBox where they reside then figure out which item you have to process. If you want to work with the currently focused item, you can use ItemIndex property of the TListBox. If you want to work on selected items (or the opposite), you can use Selected property of the TListBox.
  • 1

#3 HelpMePlz

HelpMePlz

    CC Newcomer

  • Member
  • PipPip
  • 20 posts

Posted 11 April 2012 - 05:00 AM

Thanks for the help on the first one it solved my problem!

I can't find the ItemIndex property for my list box :/

What I basically want to do is change labels' captions in the form depending on which item of the list box is selected as well as doing calculations based on values which the items in the listbox correspond to.

So for example, I want to be able to click the Item Share1 and have a labels' caption change to Share.

Thanks for all the help I am very grateful!!!
  • 0

#4 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 11 April 2012 - 05:25 AM

Thanks for the help on the first one it solved my problem!

Great.

I can't find the ItemIndex property for my list box


It's there. Believe me. But it's not published property, so it does not show in Object Inspector. It will available in you autocomplete list.

:/ What I basically want to do is change labels' captions in the form depending on which item of the list box is selected as well as doing calculations based on values which the items in the listbox correspond to. So for example, I want to be able to click the Item Share1 and have a labels' caption change to Share.


Check again the ItemIndex property (in runtime).

You use code something like this:
procedure ListBox1Click(Sender: TObject);
begin
  Label1.Caption := ListBox1.Items[ListBox1.ItemIndex];
end;


Thanks for all the help I am very grateful!!!

My pleasure.
  • 1

#5 HelpMePlz

HelpMePlz

    CC Newcomer

  • Member
  • PipPip
  • 20 posts

Posted 11 April 2012 - 06:46 AM

I sort of understand but it'd probably help if I fully explained what I am trying to do.


I have a list of stocks. Each type of stock is assigned a number between 1 and 101.

I have a file saved called StockPrices, each line has a price on it which is equivalent to a stock. E.g line five will say 1000 and this will be the price of whatever stock line five is equivalent to.

I also have a file called StockNames which works in the same way, and there are 101 lines in each users file, where each line is the amount of stock they own of the corresponding line.

So for example, we have HelpMePLz.txt and line twelvesays 23. This means that the user will have 23 shares of whatever stock corresponds to line twelve. If we open the StockNames file and go to line twelve we can find the name of this stock and if we go to the StockPrices file and go to line twelve we can find the price of this stock.



I have read all of these values into the program using arrays, and have filled in 101 lines of the edit box using the arrays for StockNames using this code.

For j := 1 to 101 do begin
    AllStocksList.Items.Add(StockNames[j]);
                         end;

What I want to happen, is when the user clicks on one of the stock names, the information about that stock is presented in labels. I.e, label 1 needs to change to StockNames[j] label 2 needs to change to StockPrices[j] and label3 will be how many of that stock the user owns so UsersStocks[j]

Sorry if I have confused you it's just quite difficult to explain.
  • 0

#6 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 11 April 2012 - 07:19 AM

I think I get what you mean. And, again, you already have your answer. In your example:

What I want to happen, is when the user clicks on one of the stock names, the information about that stock is presented in labels. I.e, label 1 needs to change to StockNames[j] label 2 needs to change to StockPrices[j] and label3 will be how many of that stock the user owns so UsersStocks[j].


Why don't you change j into ItemIndex of the ListBox that the user just clicked? You may want to add 1 to the ItemIndex if your StockPrices and UsersStocks array start from 1 instead of 0.
  • 0

#7 HelpMePlz

HelpMePlz

    CC Newcomer

  • Member
  • PipPip
  • 20 posts

Posted 11 April 2012 - 07:52 AM

That's great thanks! I didn't realise ItemIndex was an integer, haha.


What about if I don't wanna show all UserShares in the ListBox? I've written this code:


          For i := 1 to 101 do begin
                               If UsersShares[i] > 0 then begin
                                       ListBox.Items.Add((ShareNames[i]));
                                                           end;
                                end;

So if I use the j taken from ListBox it will only count the names in the box but I still have to go through all of the SharePrice values to get to the Price which corresponds to the name in the ListBox.

Any ideas on how to sort this?
  • 0

#8 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 11 April 2012 - 09:19 PM

Basically you have to define some sort of relationship between them, and store this relationships information somewhere that you don't have to depend on external entities (e.g. ListBox1 is external entity to them). Currently you are using line index as relationship between your items. Now that you hit a limitation of this kind of relationship, you have to define new and explicit relationship.

Basics of database will give you solution for good relationship information, i.e. primary key and foreign key. In your case, you need to add id to your items. So instead of this list of shareprices:
20
34
31

Now add ids, like:
0, 20
1, 34
2, 31

also for StockNames:
0, Stock Name One
1, Stock Name Two
2, Stock Name Three

Store these ids along with the stock names into the ListBoxs using AddObject method of the TListBox (casting the ids into objects), something like this:
type
  TStockInfo=record
    Id: Integer;
    Info: string;
  end;

  TStockInfoList = array of TStockInfo;

var
  StockNames: TStockInfoList;

procedure LoadStockNames;
begin
  ... here you load the stock names from file
end;

procedure PopulateListBoxWithStockNames(AListBox: TListBox);
var
  i: Integer;
begin
  AListBox.Clear;
  for i := Low(StockNames) to High(StockNames) do
    AListBox.AddObject(StockNames[i].Info, TObject(StockNames[i].Id));
end;

function FindStockNameId(AListBox: TListBox; var AId: Integer): Boolean;
begin
  Result := AListBox.ItemIndex > -1;
  if Result then
  begin
    AId := Integer(AListBox.Items.Objects[AListBox.ItemIndex]);
  end;
end;

Note that:
  • The above code not tested, just coming from my head.
  • Study how I get the stored id in function FindStockNameId.

You must then use the id to lookup to other information in other list, as long as the other lists also stored ids along with the main information.

-- Edit

Actually you can use the line numbers as implicit id. In that case, use this:
  for i := Low(StockNames) to High(StockNames) do
    AListBox.AddObject(StockNames[i].Info, TObject(i));

instead of this:
  for i := Low(StockNames) to High(StockNames) do
    AListBox.AddObject(StockNames[i].Info, TObject(StockNames[i].Id));

in the example routine PopulateListBoxWithStockNames.
  • 0

#9 HelpMePlz

HelpMePlz

    CC Newcomer

  • Member
  • PipPip
  • 20 posts

Posted 12 April 2012 - 02:20 AM

Thanks a lot, how do I read in the stock names from the file without reading in their ids into the array StockNames?

At the minute I'm using this code to read in the stock names: (Roughly :P)

AssignFile(StockNameFile, 'C:\StockNameFile.txt');
         Reset(StockNameFile);
         For i := 1 to 101 do Readln(StockNameFile, StockNames[i]);
         CloseFile(StockNameFile);


  • 0

#10 Luthfi

Luthfi

    CC Leader

  • Expert Member
  • PipPipPipPipPipPipPip
  • 1320 posts
  • Programming Language:PHP, Delphi/Object Pascal, Pascal, Transact-SQL
  • Learning:C, Java, PHP

Posted 12 April 2012 - 02:43 AM

Thanks a lot, how do I read in the stock names from the file without reading in their ids into the array StockNames?


When reading from file, you don't skip the id. You must also read the id. That's why I introduced you to custom record TStockInfo and dynamic array TStockInfoList.

When populating the ListBox, see routine PopulateListBoxWithStockNames in my previous sample.

At the minute I'm using this code to read in the stock names: (Roughly :P)

AssignFile(StockNameFile, 'C:\StockNameFile.txt');
		 Reset(StockNameFile);
		 For i := 1 to 101 do Readln(StockNameFile, StockNames[i]);
		 CloseFile(StockNameFile);


There is a better, simpler, and easier to maintain approach for this, by using help of TStrings object. Like this:

uses
  ...
  , Classes     // unit where TStrings and TStringList was declared
  , ...
  ;

type
  TStockInfo=record
    Id: Integer;
    Info: string;
  end;

  TStockInfoList = array of TStockInfo;

var
  StockNames: TStockInfoList;  // global variable to store stock names

procedure LoadStockNamesFromFile(const AFileName: string);
var
  i: Integer;
  vLine: string;
  vFileContent: TStrings;
begin
  StockNames := nil;    // clear the content ot StockNames dynamic array

  vFileContent := TStringList.Create;  // create an instance of TStrings class
  try
    vFileContent.LoadFromFile(AFileName);          // load the content of the file to vFileContent
    SetLength(StockNames, vFileContent.Count);  // resize StockNames dimension to the number of lines loaded from file

    // now parse the lines
    for i := 0 to vFileContent.Count-1 do
    begin
      vLine := vFileContent.Strings[i];  // or you can use "vLine := vFileContent[i];" since Strings is a default array property
      // here you parse vLine to extract id and stock name, remember the format would be "ID, STOCKNAME"
      // I leave the parsing and extraction for you as exercise
      StockNames[i].Id := ....;
      StockNames[i].Info := ...;
    end;
  finally
    vFileContent.Free;
  end;
end;

  • 0




Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download