View Issue Details

IDProjectCategoryView StatusLast Update
0029525LazarusLCLpublic2017-02-25 16:28
ReporterCarsten Bager Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
PlatformWindowsOSWindows 
Product Version1.4.4 
Summary0029525: TCheckListBox dos not act like I expect. Check boxes are missing.
DescriptionI am moving a project from Delphi to Lazarus, In Lazarus v. 1..4.4(Windows) The TCheckListBox dos not act like I expect. Check boxes are missing.
I am using the TCheckListBox with style = lbOwnerDrawVariable
The same program works on Raspberry PI (Linux) using Lazarus V. 1.2.4, and in Delphi.
I attach the project and 2 photos. It compiles on Windows and Linux (Raspbarry PI).Carsten

Steps To ReproduceCompile and run
TagsNo tags attached.
Fixed in Revision
LazTarget-
Widgetset
Attached Files

Relationships

has duplicate 0030849 closedBart Broersma TCheckListBox haven't CheckBox 
related to 0025952 new TCheckListBox OnDrawItem method incorrect draw when setted style "lbOwnerDrawFixed" 

Activities

Carsten Bager

2016-01-28 12:40

reporter  

RadioCenter.ZIP (556,160 bytes)

Juha Manninen

2016-01-29 00:34

developer   ~0089490

Last edited: 2016-01-29 00:35

View 2 revisions

It does not work on Linux either when using QT.
GTK2 may be the only widgetset where it works.

Juha Manninen

2016-03-09 20:40

developer   ~0090810

Ok, it works in Raspberry PI with Lazarus 1.2.4 because the widgetset is GTK2. It works there also with Lazarus 1.6.
This is not a regression. Detaching myself ...

Zeljan Rikalo

2016-03-09 21:43

developer   ~0090816

It works on gtk2 because checkable listbox have it's own column + checkbox renderer and that's because how gtk2 works.

Juha Manninen

2016-03-15 21:28

developer   ~0091092

Zeljko, this is tricky. Checkboxes are quite important in a CheckListbox. The component should be somehow consistent between widgetset.

Zeljan Rikalo

2017-02-11 20:12

developer   ~0098109

I know that it should be consistent. Qt can draw themed checkbox (I can implement if it isn't implemented), but he is talking about win32, so someone with more knowledge must look into...if it's possible at all.

Soner

2017-02-12 01:57

reporter  

PatchForBugIssue29525.zip (148,699 bytes)

Soner

2017-02-12 02:03

reporter   ~0098112

Last edited: 2017-02-12 03:05

View 2 revisions

I uploaded patch file with the project.
with windows-widset the user have to draw the checkbox.
I modified it to draw checkbox first then call the drawitem-event.
---
Edit:
Sorry guys i made mistake PatchForBugIssue29525.zip. It has some drawing errors if it is focused. it is "half" patch but the right way.
i added now 2nd try.

Soner

2017-02-12 03:04

reporter  

Zeljan Rikalo

2017-02-12 10:16

developer   ~0098114

@Soner, that's not patch, but shows to reporter how to draw checkbox under other widgetsets. While this gtk2 behaviour looks like feature it is not.
In ownerdrawn checklistbox you must draw evertyhing, including checkboxes, and take care of checked/unchecked. IMO, this should be resolved as "won't fix".

Bart Broersma

2017-02-12 12:16

developer   ~0098116

In D7 with Style := lbOwnerDrawVariable checkboxes are drawn independently of the code in the OnDrawItem event. The OnDrawItem event is only responsible for drawing the text.
In Lazarus (trunk) checkboxs are not drawn. Rather counter-intuitive to me, even so if you cick on the area where you would expect to see the checkbox an OnItemClick is fired and Checked for that item is toggled.

This is a Delphi incompatibility.

Bart Broersma

2017-02-12 12:18

developer   ~0098117

B.t.w. Why is OnMeasureItem event not published?

Bart Broersma

2017-02-12 13:15

developer   ~0098118

Last edited: 2017-02-12 13:19

View 2 revisions

More issues: OnMeasureItem is called (with a random number for Index) when style is lbOwnerDrawFixed. It should not be called at all.

If Style = lbOwnerDrawVariable then OnMeasureItem should be called for each Item, but there is only 1 call to OnMeasureItem, again with an invalid number for Index.

Bart Broersma

2017-02-12 16:12

developer   ~0098121

Last edited: 2017-02-12 16:13

View 2 revisions

Here's what I get on Win32 Lazarus trunk r53925:

WindowProc:
 Msg=WM_MEASUREITEM,
 LParam=36172116
 WParam=38635856
 itemId=1930520905 //PMeasureItemStruct(LParam)^.itemId

TWindowProcHelper.DoWindowProc:
 Msg=WM_MEASUREITEM
 LParam=36172116
 WParam=38635856
 itemId=1930520905

TWindowProcHelper.DoMsgMeasureItem:
 PMeasureItemStruct(LParam)^.CtlType=2 //=ODT_LISTBOX

TWindowProcHelper.SetLMessageAndParams:
 WM_MEASUREITEM:
 ResetWinProcess=TRUE
 LParam=36172116
 WParam=38635856

TCustomListBox.LMMeasureItem [TCheckListBox]:
 itemId=1930520905
 idCtl=38635856 //=Self as it should be
 CtlType=2 //=ODT_LISTBOX as it should be
 TheMessage.MeasureItemStruct=36172116 //=LParam from message as it should be

It seems that itemId=1930520905 is always the same.

Bart Broersma

2017-02-12 16:17

developer   ~0098122

Another observation:
In class procedure TWin32WSCustomCheckListBox.DefaultWndHandler() TLMessage(AMessage).Msg never seems to be LM_MEASUREITEM.

jamie philbrook

2017-02-12 16:27

reporter   ~0098123

I vote that we have an option property to allow the checks to be drawn in the
list while owner draw is in play.
   
 There are times when it would be nice to draw your own custom indicator and
other times, use the default one that gets drawn to follow the themes settings
on users PC's.

 Of course, along with fixing the immediate problem.

Zeljan Rikalo

2017-02-12 16:37

developer   ~0098124

No, we should have Delphi compatibility in this case. That means win32,qt and others need to be fixed.

jamie philbrook

2017-02-12 16:57

reporter   ~0098126

My point was to have the option property, on by default to draw the check
mark, the way Delphi does it now. All code will port without issues.

 Coders could elect to have it not draw the checks but still provide the click
area like it does now so they can choose to have their own form of glyph.

 Just an idea, carry on gentleman!

Bart Broersma

2017-02-22 16:03

developer   ~0098370

In lsOwnerDrawVariable style, adding an item should trigger OnMeasureItem for that item (at least D7 does), but it does not.

Zeljan Rikalo

2017-02-22 16:53

developer   ~0098371

What's exact Delphi behaviour ? Does it draw checkboxes with owner draw ? If it draws, who handles checkboxes (checked/unchecked) ?

Ondrej Pokorny

2017-02-24 13:16

developer   ~0098421

> I vote that we have an option property to allow the checks to be drawn in the
list while owner draw is in play.
   
> There are times when it would be nice to draw your own custom indicator and
other times, use the default one that gets drawn to follow the themes settings
on users PC's.

I agree with Zeljko. If you need custom-drawn checkboxes you can use TListBox a do everything on your own.

Bart Broersma

2017-02-24 18:40

developer   ~0098427

> Does it draw checkboxes with owner draw ?

As explained in note 0098116: checkboxes are drawn in lbsOwnerDrawVariable and lbsOwnerDrawFixed style.
I cannot tell wether Delphi does the drawing or the WS does.

> If it draws, who handles checkboxes (checked/unchecked) ?
I have no idea what you mean by that.

Bart

Bart Broersma

2017-02-25 15:42

developer   ~0098454

Last edited: 2017-02-25 15:46

View 2 revisions

There is a difference between TListBox and TCheckListbox w.r.t. the messages:
Consider a TListBox and a TCheckListBox with 2 Items.
Now set Style to lbsOwnerDrawVariable and whatch the handling of the messages.

For TListBox:
-----------------------------------
TWin32WSCustomListBox.SetStyle: [TListBox:LB] lbOwnerDrawVariable
WindowProc: Msg=WM_MEASUREITEM
TWindowProcHelper.DoWindowProc: Msg=WM_MEASUREITEM
 WParam=37839184 = TListBox:LB
 LParam=36169112 (pointer to MEASUREITEMSTRUCT)
 CtlType=ODT_LISTBOX
 - itemId = 0
 - itemData = 37444076
 - itemHeight = 16
 - itemWidth = 0
 - NMHdr^.hwndFrom = 2
 - NMHdr^.idFrom = 37839184
 - NMHdr^.code = 0
TWindowProcHelper.DoMsgMeasureItem:
 - PMeasureItemStruct(LParam)^.CtlType=2
TWindowProcHelper.SetLMessageAndParams:
 - ResetWinProcess = TRUE
 - WParam = 37839184, LParam=36169112
TWindowProcHelper.DoWindowProc: calling DeliverMessage
TCustomListBox.LMMeasureItem [LB:TListBox]
 - itemId = 0
 - idCtl = 37839184
 - Check: (Self=CtlID=idCtl) = True
 - CtlType = ODT_LISTBOX
 - TheMessage.MeasureItemStruct = 36169112
LBMeasureItem: [LB:TListBox] Index=0, AHeight=15
 - itemHeight -> 25
TWindowProcHelper.DoWindowProc: Result = 0
 - itemId = 0
 - itemData = 37444076
 - itemHeight = 25
 - itemWidth = 0

WindowProc: Msg=WM_MEASUREITEM: Result=0
WindowProc: Msg=WM_MEASUREITEM
TWindowProcHelper.DoWindowProc: Msg=WM_MEASUREITEM
 WParam=37839184 = TListBox:LB
 LParam=36169112 (pointer to MEASUREITEMSTRUCT)
 CtlType=ODT_LISTBOX
 - itemId = 1
 - itemData = 37444076
 - itemHeight = 16
 - itemWidth = 0
 - NMHdr^.hwndFrom = 2
 - NMHdr^.idFrom = 37839184
 - NMHdr^.code = 1
TWindowProcHelper.DoMsgMeasureItem:
 - PMeasureItemStruct(LParam)^.CtlType=2
TWindowProcHelper.SetLMessageAndParams:
 - ResetWinProcess = TRUE
 - WParam = 37839184, LParam=36169112
TWindowProcHelper.DoWindowProc: calling DeliverMessage
TCustomListBox.LMMeasureItem [LB:TListBox]
 - itemId = 1
 - idCtl = 37839184
 - Check: (Self=CtlID=idCtl) = True
 - CtlType = ODT_LISTBOX
 - TheMessage.MeasureItemStruct = 36169112
LBMeasureItem: [LB:TListBox] Index=1, AHeight=15
 - itemHeight -> 35
TWindowProcHelper.DoWindowProc: Result = 0
 - itemId = 1
 - itemData = 37444076
 - itemHeight = 35
 - itemWidth = 0

WindowProc: Msg=WM_MEASUREITEM: Result=0


All is as expected: itemID is corect and MeasureItem is called for all items.

Now for TCheckListBox:

-----------------------------------
TWin32WSCustomListBox.SetStyle: [TCheckListBox:CheckLB] lbOwnerDrawVariable
WindowProc: Msg=WM_MEASUREITEM
TWindowProcHelper.DoWindowProc: Msg=WM_MEASUREITEM
 WParam=2066464 = TCheckListBox:CheckLB
 LParam=36167732 (pointer to MEASUREITEMSTRUCT)
 CtlType=ODT_LISTBOX
 - itemId = 1768319305
 - itemData = 0
 - itemHeight = 16
 - itemWidth = 0
 - NMHdr^.hwndFrom = 2
 - NMHdr^.idFrom = 2066464
 - NMHdr^.code = 1768319305
TWindowProcHelper.DoMsgMeasureItem:
 - PMeasureItemStruct(LParam)^.CtlType=2
TWindowProcHelper.SetLMessageAndParams:
 - ResetWinProcess = TRUE
 - WParam = 2066464, LParam=36167732
TWindowProcHelper.DoWindowProc: calling DeliverMessage
TCustomListBox.LMMeasureItem [CheckLB:TCheckListBox]
 - itemId = 1768319305
 - idCtl = 2066464
 - Check: (Self=CtlID=idCtl) = True
 - CtlType = ODT_LISTBOX
 - TheMessage.MeasureItemStruct = 36167732
LBMeasureItem: [CheckLB:TCheckListBox] Index=1768319305, AHeight=17
 - itemHeight -> 44
TWindowProcHelper.DoWindowProc: Result = 0
 - itemId = 1768319305
 - itemData = 0
 - itemHeight = 44
 - itemWidth = 0

WindowProc: Msg=WM_MEASUREITEM: Result=0

itemID is wrong and it MeasureItem is only called once.


Now notice:
procedure TCustomCheckListBox.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.Style := (Params.Style and not LBS_OWNERDRAWVARIABLE) or LBS_OWNERDRAWFIXED;
end;

This now in effect makes every TCheckListBox have the lbsOwnerDrawFixed style applied.

If you comment out the second line, then TCheckListBox correctly handles the MEASURE_ITEM messages:

-----------------------------------
TWin32WSCustomListBox.SetStyle: [TCheckListBox:CheckLB] lbOwnerDrawVariable
WindowProc: Msg=WM_MEASUREITEM
TWindowProcHelper.DoWindowProc: Msg=WM_MEASUREITEM
 WParam=3901472 = TCheckListBox:CheckLB
 LParam=36169044 (pointer to MEASUREITEMSTRUCT)
 CtlType=ODT_LISTBOX
 - itemId = 0
 - itemData = 3422924
 - itemHeight = 16
 - itemWidth = 0
 - NMHdr^.hwndFrom = 2
 - NMHdr^.idFrom = 3901472
 - NMHdr^.code = 0
TWindowProcHelper.DoMsgMeasureItem:
 - PMeasureItemStruct(LParam)^.CtlType=2
TWindowProcHelper.SetLMessageAndParams:
 - ResetWinProcess = TRUE
 - WParam = 3901472, LParam=36169044
TWindowProcHelper.DoWindowProc: calling DeliverMessage
TCustomListBox.LMMeasureItem [CheckLB:TCheckListBox]
 - itemId = 0
 - idCtl = 3901472
 - Check: (Self=CtlID=idCtl) = True
 - CtlType = ODT_LISTBOX
 - TheMessage.MeasureItemStruct = 36169044
LBMeasureItem: [CheckLB:TCheckListBox] Index=0, AHeight=17
 - itemHeight -> 27
TWindowProcHelper.DoWindowProc: Result = 0
 - itemId = 0
 - itemData = 3422924
 - itemHeight = 27
 - itemWidth = 0

WindowProc: Msg=WM_MEASUREITEM: Result=0
WindowProc: Msg=WM_MEASUREITEM
TWindowProcHelper.DoWindowProc: Msg=WM_MEASUREITEM
 WParam=3901472 = TCheckListBox:CheckLB
 LParam=36169044 (pointer to MEASUREITEMSTRUCT)
 CtlType=ODT_LISTBOX
 - itemId = 1
 - itemData = 3422924
 - itemHeight = 16
 - itemWidth = 0
 - NMHdr^.hwndFrom = 2
 - NMHdr^.idFrom = 3901472
 - NMHdr^.code = 1
TWindowProcHelper.DoMsgMeasureItem:
 - PMeasureItemStruct(LParam)^.CtlType=2
TWindowProcHelper.SetLMessageAndParams:
 - ResetWinProcess = TRUE
 - WParam = 3901472, LParam=36169044
TWindowProcHelper.DoWindowProc: calling DeliverMessage
TCustomListBox.LMMeasureItem [CheckLB:TCheckListBox]
 - itemId = 1
 - idCtl = 3901472
 - Check: (Self=CtlID=idCtl) = True
 - CtlType = ODT_LISTBOX
 - TheMessage.MeasureItemStruct = 36169044
LBMeasureItem: [CheckLB:TCheckListBox] Index=1, AHeight=17
 - itemHeight -> 37
TWindowProcHelper.DoWindowProc: Result = 0
 - itemId = 1
 - itemData = 3422924
 - itemHeight = 37
 - itemWidth = 0

WindowProc: Msg=WM_MEASUREITEM: Result=0

itemID is correct and MeasureItem is called for all items.

Bart Broersma

2017-02-25 15:57

developer  

clb.zip (69,667 bytes)

Bart Broersma

2017-02-25 15:59

developer   ~0098455

Uploaded test project (clb.zip) wich also contains a diff for lcl that produces the debug output.

Bart Broersma

2017-02-25 16:25

developer  

Bart Broersma

2017-02-25 16:28

developer   ~0098456

@Zeljan:
> Does it draw checkboxes with owner draw ?

See attached file: delphi-listbox-ownerdrawvariable.png

This is how D7 draws a TCheckListBox with lbsOwnerDrawVaraible style.
The OnDrawItem only draws the text.

Issue History

Date Modified Username Field Change
2016-01-28 12:40 Carsten Bager New Issue
2016-01-28 12:40 Carsten Bager File Added: RadioCenter.ZIP
2016-01-29 00:34 Juha Manninen Note Added: 0089490
2016-01-29 00:35 Juha Manninen Note Edited: 0089490 View Revisions
2016-03-09 17:08 Juha Manninen Assigned To => Juha Manninen
2016-03-09 17:08 Juha Manninen Status new => assigned
2016-03-09 20:40 Juha Manninen Note Added: 0090810
2016-03-09 20:40 Juha Manninen LazTarget => -
2016-03-09 20:40 Juha Manninen Assigned To Juha Manninen =>
2016-03-09 20:40 Juha Manninen Status assigned => new
2016-03-09 21:43 Zeljan Rikalo Note Added: 0090816
2016-03-12 12:34 Juha Manninen Relationship added related to 0025952
2016-03-15 21:28 Juha Manninen Note Added: 0091092
2016-11-02 21:08 Bart Broersma Relationship added has duplicate 0030849
2017-02-11 20:12 Zeljan Rikalo Note Added: 0098109
2017-02-12 01:57 Soner File Added: PatchForBugIssue29525.zip
2017-02-12 02:03 Soner Note Added: 0098112
2017-02-12 03:04 Soner File Added: PatchForBugIssue29525-2ndtry.zip
2017-02-12 03:05 Soner Note Edited: 0098112 View Revisions
2017-02-12 10:16 Zeljan Rikalo Note Added: 0098114
2017-02-12 12:16 Bart Broersma Note Added: 0098116
2017-02-12 12:18 Bart Broersma Note Added: 0098117
2017-02-12 13:15 Bart Broersma Note Added: 0098118
2017-02-12 13:19 Bart Broersma Note Edited: 0098118 View Revisions
2017-02-12 16:12 Bart Broersma Note Added: 0098121
2017-02-12 16:13 Bart Broersma Note Edited: 0098121 View Revisions
2017-02-12 16:17 Bart Broersma Note Added: 0098122
2017-02-12 16:27 jamie philbrook Note Added: 0098123
2017-02-12 16:37 Zeljan Rikalo Note Added: 0098124
2017-02-12 16:57 jamie philbrook Note Added: 0098126
2017-02-22 16:03 Bart Broersma Note Added: 0098370
2017-02-22 16:53 Zeljan Rikalo Note Added: 0098371
2017-02-24 13:16 Ondrej Pokorny Note Added: 0098421
2017-02-24 18:40 Bart Broersma Note Added: 0098427
2017-02-25 15:42 Bart Broersma Note Added: 0098454
2017-02-25 15:46 Bart Broersma Note Edited: 0098454 View Revisions
2017-02-25 15:57 Bart Broersma File Added: clb.zip
2017-02-25 15:59 Bart Broersma Note Added: 0098455
2017-02-25 16:25 Bart Broersma File Added: delphi-listbox-ownerdrawvariable.png
2017-02-25 16:28 Bart Broersma Note Added: 0098456