Recent

Author Topic: [ONLY FOR BEGINNERS] Listbox item color by TAG  (Read 1120 times)

PDV

  • New Member
  • *
  • Posts: 12
[ONLY FOR BEGINNERS] Listbox item color by TAG
« on: November 20, 2023, 08:45:47 pm »
I was looking for how to color an item in a listbox to get information on the status of the inserted element, it wasn't easy, I didn't find any working examples except for a very complex one which is beyond my current language skills. After all, searching on Google I saw that it is a problem that interests many and that various answers are found, but as long as the code doesn't work you won't get anything. Given a working project, which can be useful to anyone searching on this topic, the first 3 examples are taken from the web and in any case are not very useful, the fourth is what I arrived at after a long time of trying and trying and trying again, or how color an item based on other information, which is very useful. From the examples you can expand the possibilities and do other things.
Bye

wp

  • Hero Member
  • *****
  • Posts: 12466
Re: [ONLY FOR BEGINNERS] Listbox item color by TAG
« Reply #1 on: November 20, 2023, 09:42:17 pm »
At first let me assume that the four examples are the listboxes in your project. But which one is the "successful" listbox? To me, all of them show colored lines... So, what is your requirement? What do you want to achieve? What is the criterion by which you can tell that the listbox is colored correctly?

Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1227
Re: [ONLY FOR BEGINNERS] Listbox item color by TAG
« Reply #2 on: November 21, 2023, 01:22:22 am »
Wouldn’t this involve using owner drawn option? I know it’s possible with tcombobox. The behavior is defined in the ondrawitem event.
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

PDV

  • New Member
  • *
  • Posts: 12
Re: [ONLY FOR BEGINNERS] Listbox item color by TAG
« Reply #3 on: November 21, 2023, 01:59:10 pm »
At first let me assume that the four examples are the listboxes in your project. But which one is the "successful" listbox? To me, all of them show colored lines... So, what is your requirement? What do you want to achieve? What is the criterion by which you can tell that the listbox is colored correctly?

Hi,
these listboxes are not in my project, they illustrate what is possible to obtain and how to obtain it, it is stuff for beginners, as I wrote.
I was looking for a way to add more information to a list in a listbox, and I thought about using a TAG but the code to obtain the value of the TAG, necessary to establish the color, didn't work:

** case TFurbone(LCOLORE2.Items.Objects[LCOLORE2.Itemindex]).Attaccone of  ** : this code generates an error etc, but in other contexts it works fine;

** case TFurbone(LCOLORE2.Items.Objects[Index]).Attaccone of  ** : in this context we need this code that works.

Carlo
Brubo
Walter
Giuseppe
etc.,
 they are personal names, if I color them, if necessary, I can obtain other information, e.g. Carlo RED means that Carlo's laboratory tests report problems (report generated automatically by an algorithm that reads the data and decides), Bruno BLACK means that there are no problems etc etc etc, all possibilities are open.
I had many difficulties and for a long time to achieve all this, I am a begginer with FreePascal, if I had immediately found this code that I publish I would have saved a lot of time, but you learn by making mistakes.

PDV

  • New Member
  • *
  • Posts: 12
Re: [ONLY FOR BEGINNERS] Listbox item color by TAG
« Reply #4 on: November 21, 2023, 02:04:09 pm »
Wouldn’t this involve using owner drawn option? I know it’s possible with tcombobox. The behavior is defined in the ondrawitem event.

Yes, that's what I did

wp

  • Hero Member
  • *****
  • Posts: 12466
Re: [ONLY FOR BEGINNERS] Listbox item color by TAG
« Reply #5 on: November 21, 2023, 03:07:26 pm »
Drawing the lines of a Listbox in different colors is related to two tasks:
  • How to draw the listbox lines in a different way?
  • How to tell the drawing procedure which color should be used for which line?
But first of all, there's the question: What exactly should be done? Should the text be drawn in different color? Or should be background be drawn differently? Or both? I'll be assuming the first case, drawing text in different colors.

Ad 1.
The listbox items normally are drawn by the operating system. But when the Listbox.Style is switched to one of the "owner-draw" options (lbOwnerDrawFixed or lbOwnerDrawVariable), you tell the OS that you will take responsibility of drawing the lines. Then, in order to add the code that you want the listbox to execute for drawing its lines, you double-click on the OnDrawItem event of the listbox. This inserts an empty code block in the source editor, and you must complete it with your own code:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  2.   ARect: TRect; State: TOwnerDrawState);
  3. begin
  4.  
  5. end;
This event handler has the parameters "Control", "Index", "ARect" and "AState":
  • Control is the Control which wants to be redrawn by your code, well - the listbox (you can use the same handler for multiple listboxes, then Control tells you which one actually has to be painted). But note that Control is given in a general way as a TWinControl, you must type-cast it to TListbox to access the listbox properties!
  • Index is the index of the item to be painted. Use it to get the text to be painted: Listbox1.Items[Index], or more general using the Control parameter: TListbox(Control).Items[Index]
  • ARect tells you the rectangle in which the painted text will be expected
  • AState tells you the state of the line: normal (set is empty), selected ([odSelected]), selected+focused ([odSelected, odFocused], disabled ([odDisabled]).
The code how to draw the text, finally, uses one of the Canvas methods, most often TCanvas.TextOut(x, y, text), where x and y are the coordinates of the top-left corner of the text to be drawn.

Here is an example assuming that you want to draw every odd line in bold type-face
Code: Pascal  [Select][+][-]
  1. procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  2.   ARect: TRect; State: TOwnerDrawState);
  3. begin
  4.   // Determine canvas properties to be used
  5.   Listbox1.Canvas.Font.Assing(Listbox1.Font);
  6.   if (odSelected in AState) then
  7.   begin
  8.     Listbox1.Canvas.Brush.Color := clRed;
  9.     Listbox1.Canvas.Font.Color := clYellow;
  10.   end else
  11.   begin
  12.     Listbox1.Canvas.Brush.Color := clWhite;
  13.     Listbox1.Canvas.Font.Color := clBlack;
  14.   end;
  15.   if odd(Index) then
  16.     Listbox1.Canvas.Font.Style := [fsBold]
  17.   else
  18.     Listbox1.Canvas.Font.style := [];
  19.   // Draw the background, using the canvas brush
  20.   Listbox1.Canvas.FillRect(ARect);
  21.   // Draw the text, using the canvas font
  22.   Listbox1.Canvas.TextOut(ARect.Left, ARect.Top, Listbox1.Items[Index]);
  23. end;

Ad 2:
One simple possibility, although a bit hacky, to pass the requested colors to the OnDrawItem procedure is to add them to the Listbox along with the text. The Listbox items can store a pointer to an object in addition to the text: Listbox.Items.Strings[index], or ListBox.Items[index] in short, refers to the text, Listbox.Items.Objects[index] refers to the object at the given index. The object is passed by a special Items method: AddObject. A color is not an object (just an integer data type), but the Listbox.Items do not check this and can be fooled by type-casting the TColor to an object. Basically an object is a pointer, and a typecast tells the compiler: Use the same bits as in the TColor variable but consider it to be a pointer - of course you cannot deference this pointer because it points to non-allocated memory. There is one more complication: TColor is declared as LongInt (32-bit), but a pointer has the same size in a 32-bit application only, in a 64-bit application is is 64 bit in size. Therefore, you must type-cast TColor to PtrInt before casting it to a pointer - PtrInt is an integer which has the same size as a pointer independent of the application's bitness. Without this type-cast your application will crash in 64-bit.

Example: Add the strings 'Carlo', 'Brubo', 'Walter', 'Giuseppe' to the listbox and define the color for Carlo to be red, for Brubo to be black, for Walter to be green and for Guiseppe to be blue:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.PopulateListbox(Listbox: TListbox);
  2. begin
  3.   Listbox.Items.Clear;
  4.   Listbox.Items.AddObject('Carlo', TObject(PtrInt(clRed)));
  5.   Listbox.Items.AddObject('Brubo', TObject(PtrInt(clBlack)));
  6.   Listbox.Items.AddObject('Walter', TObject(PtrInt(clGreen)));
  7.   Listbox.Items.AddObject('Guiseppe', TObject(PtrInt(clBlue)));
  8. end;

The drawing code is essentially the same as in the example above, only color-definition is different:
Code: Pascal  [Select][+][-]
  1.     Listbox1.Canvas.Font.Color := TColor(PtrInt(Listbox1.Items.Objects[Index]));

See details in attachment.





PDV

  • New Member
  • *
  • Posts: 12
Re: [ONLY FOR BEGINNERS] Listbox item color by TAG
« Reply #6 on: November 21, 2023, 04:07:00 pm »
Drawing the lines of a Listbox in different colors is related to two tasks:
...........
See details in attachment.

Yes, everything is clear and works well. Many thanks WP

 

TinyPortal © 2005-2018