News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

mcLB2, a new Windows control

Started by NoCforMe, May 19, 2025, 05:25:41 AM

Previous topic - Next topic

NoCforMe

Quote from: _japheth on May 21, 2025, 08:18:02 PMLooking at the source I see that _SETTEXT and _SETDATA use HIWORD( LParam ) to select the row. So I guess there's currently a 64k limit for rows, at least in 32-bit Windoze?

I completely missed that. Easily fixed: I can have the user pass a structure of 2 DWORDs for row & col., since I guess we're aiming at supporting >64K rows.

But really: how realistic is that? How many programs are going to have more than a few dozen rows at most? What applications can you think of where we'd need to have that many rows? I can't think of any, so I'm wondering just what ridiculous lengths I should go to in order to achieve that notional capability ...

QuoteHowever, what I really miss is some visual response for the user so he/she can see what item is currently selected. The MS listview even allows multiple rows to be selected. Another side note: your control doesn't handle keyboard input - AFAICS the only way to scroll is using the mouse.

Noted. Both selection and keyboard input could be added (my other mcLB control has them). Let me see what other kinds of input I get here.
32-bit code and Windows 7 foreva!

NoCforMe

BTW, two things that definitely need fixed:

1. Destroying controls and creating new ones:
Currently I'm using the next available slot in the "master control table" for the next control created, with no regard for controls that get destroyed.

Easily fixed, though: I'll use the ctrlHandle member to see if a "slot" is available when creating a new control: either zero, meaning a control was never created there, or -1, meaning a control was destroyed and the slot is available.

2. Text heap:
Currently there's one text heap for all controls. No good, as no text heap memory can be released when a control is destroyed, so each control will have its own text heap.
32-bit code and Windows 7 foreva!

NoCforMe

Looking for input on this project. If interested, maybe you can respond to this informal questionnaire:

1. Should this control be responsive? IOW, should you be able to click on rows to select them, and have them highlighted? (Or use the keyboard.)
And should you be able to select certain columns in the row, or should the entire row be highlighted?

(If selection is implemented, then that implies that the control will issue notifications for both single and double clicks, using WM_NOTIFY.)

2. Is it important that the control be able to handle > 64K rows? (Kind of a moot point, as it now does with my most recent changes. But I'm just wondering who in the world would need this kind of capacity.)

3. Should this control be usable from C (or other non-assembly language) programs? This would only require creating a .h file for it.

4. Should the user be able to change column characteristics (font, text & background colors) on the fly? Currently these are set at control-creation time and can't be changed thereafter.

5. Any other features you think this control really really needs?

I'm open to suggestions--to a point. I'm not sure about making this a "common controls" class control; it was just kind of a groovy idea that I followed through on. But I'm listening.
32-bit code and Windows 7 foreva!

jj2007

Over 64k rows is a lot, but not unrealistic, see below one from the UN that approaches that limit. Re selections, yes, it is very important to know what you selected.


sinsi

Quote from: NoCforMe on May 22, 2025, 02:40:30 PM1. Should this control be responsive? IOW, should you be able to click on rows to select them, and have them highlighted? (Or use the keyboard.)
And should you be able to select certain columns in the row, or should the entire row be highlighted?
It's good to know where in a list you are, and I would expect the full row to be selected.

Quote from: NoCforMe on May 22, 2025, 02:40:30 PM2. Is it important that the control be able to handle > 64K rows? (Kind of a moot point, as it now does with my most recent changes. But I'm just wondering who in the world would need this kind of capacity.)
Not really, but you can guarantee that one person will want it, and bitch and moan that it's limited. However, it's so trivial to implement that you night as well.

Quote from: NoCforMe on May 22, 2025, 02:40:30 PM3. Should this control be usable from C (or other non-assembly language) programs? This would only require creating a .h file for it.
Don't care

Quote from: NoCforMe on May 22, 2025, 02:40:30 PM4. Should the user be able to change column characteristics (font, text & background colors) on the fly? Currently these are set at control-creation time and can't be changed thereafter.
Yes to all three, what is legible to you may just be blobs to another.

I would't personally use it as I think a ListView is easier

sinsi

OK, you have piqued my interest in custom controls. My thoughts:


A control should be self-contained, so use a structure for per-instance data (per control).
When you register the class, add 4 bytes (SIZEOF PTR) to WNDCLASSEX.cbWndExtra. This would be a pointer
to any private data, stored in a structure.

On WM_NCCREATE you would allocate memory for the structure and initialise it, using
SetWindowLong to save it to that control.

On WM_NCDESTROY you get the structure with GetWindowLong then free any memory in the
structure then free the structure itself.


No need to keep track of created controls, the HWND takes care of finding the data.

NoCforMe

Quote from: sinsi on May 22, 2025, 11:05:15 PM
Quote from: NoCforMe on May 22, 2025, 02:40:30 PM4. Should the user be able to change column characteristics (font, text & background colors) on the fly? Currently these are set at control-creation time and can't be changed thereafter.
Yes to all three, what is legible to you may just be blobs to another.
Yes, but all of these can be set when the control is created; are you suggesting being able to change them after creation? Could be done, with a bit of complexity.

QuoteI would't personally use it as I think a ListView is easier
Now that's an interesting data point, so noted: I haven't seen much interest in using this yet here, so it might just end up being another one of my private custom controls.

But really, is it easier for you to use a ListView? I'm surprised, as I find that control's interface to be a hot mess. But maybe you've figured it out and have a set of routines to handle it. One thing I found annoying was that in order to delete rows in a ListView you have to start at the end and work your way backwards.

Quote from: sinsi on May 23, 2025, 03:56:30 PMA control should be self-contained, so use a structure for per-instance data (per control).
When you register the class, add 4 bytes (SIZEOF PTR) to WNDCLASSEX.cbWndExtra. This would be a pointer to any private data, stored in a structure.
Good suggestion (and easy to implement) on the private data, always a handy thing.
The control is that way now, with a "master control structure" ($mcs2) for each instance.

QuoteOn WM_NCCREATE you would allocate memory for the structure and initialise it, using SetWindowLong to save it to that control.
I do this, but on WM_CREATE instead. No need to use SetWindowLong(), as all that is done internally. But yeah, basically the same scheme.

QuoteNo need to keep track of created controls, the HWND takes care of finding the data.
Yes, except that I need to locate the master control structure for each control. I suppose you could use GWL_USERDATA as a pointer to that structure. (I have a routine, FindControl()) which locates the structure using the handle passed into the control's proc.)
32-bit code and Windows 7 foreva!

_japheth

Quote from: NoCforMe on May 24, 2025, 05:03:54 AMOne thing I found annoying was that in order to delete rows in a ListView you have to start at the end and work your way backwards.

:biggrin:

I guess that's just a "misunderstanding" on your side - i.e to delete rows 10-12 in a listview of 20 rows, you probably should take into account that after deleting row 10, the former rows 11-12 have become rows 10-11 ( IOW: to delete rows 10-12 you just have to delete row 10 3 times ).



Dummheit, gepaart mit Dreistigkeit - eine furchtbare Macht.

sinsi

Quote from: NoCforMe on May 24, 2025, 05:03:54 AMYes, except that I need to locate the master control structure for each control.
Why do that, when each control has it's data within?
Let Windows keep track of controls, your code's job is to act on the control.

I use WM_NCCREATE because there are some things that are needed well before we receive a WM_CREATE and it's the first message posted.
Same reason for using WM_NCDESTROY, it's the final one received. I read this tip in a Windows 95 Programming book, I'll see if I can find it and post the reasoning behind it.

Quin

If my knowledge is correct, WM_NCCREATE is posted before the window is fully created, but after the call to CreateWindowEx. Pretty sure you're supposed to SetWindowLongPtr(hwnd, GWLP_USERDATA, ...) here if subclassing. You can also veto creation when handling it by returning FALSE.

NoCforMe

Quote from: Quin on May 24, 2025, 12:17:33 PMIf my knowledge is correct, WM_NCCREATE is posted before the window is fully created, but after the call to CreateWindowEx. Pretty sure you're supposed to SetWindowLongPtr(hwnd, GWLP_USERDATA, ...) here if subclassing. You can also veto creation when handling it by returning FALSE.

You can veto creation when handling WM_CREATE as well (though using a different return value, -1 instead of zero). That message is just sent earlier than WM_CREATE. No subclassing is going on here.

Well, all this is very nice, but pretty much icing on the cake. The control works just fine as it is; changing it to use WM_NCCREATE would be pretty much six of one, half a dozen of the other. From my point of view there's really nothing to be gained by using the NC version of that message.

What's more of a concern is the apparent lack of interest in people using this control. If I don't get much more feedback soon then I'll just take my toys and go home; no percentage in seeking input on something that nobody wants to use. (No harm, no foul, just a gauge of how much effort I should be putting into this.)

BTW, found this interesting comment in a Stack Overflow thread on these two messages:
QuoteWM_NCCREATE is an example of an arms race in progress. It seems to have been introduced to serve a need where DefWindowProc (or the base window proc of a commonly subclassed window) needed to perform some initialization perhaps before WM_CREATE was processed (or to make up for the fact that many window implementations handle WM_CREATE directly and return TRUE rather than passing it on to DefWindowProc).

WM_NCCREATE therefore is the message you should respond to if you are implementing a default window procedure, that needs to perform initialization before the users window proc handles the WM_CREATE message. WM_NCCREATE also MUST be passed on to the appropriate DefWindowProc, probably before you do your own processing as some lower level aspects of the window are clearly in an uninitialized state before WM_NCCREATE is processed.

If trying to guarantee first-look processing is NOT your consideration, then WM_CREATE is the appropriate place to perform your window initialization: All other layers that might have jist-in-time setup via WM_NCCREATE have been done, and the window is in a stable state wrt things like its non client metrics, screen position etc.

Or: If you don't know why you should use WM_NCCREATE over WM_CREATE, then you should not be using WM_NCCREATE.
32-bit code and Windows 7 foreva!

sinsi

Quote from: NoCforMe on May 24, 2025, 12:28:00 PMWhat's more of a concern is the apparent lack of interest in people using this control. If I don't get much more feedback soon then I'll just take my toys and go home; no percentage in seeking input on something that nobody wants to use. (No harm, no foul, just a gauge of how much effort I should be putting into this.)
It seems to have been made for a specific purpose, whereas most controls are more general but more complex because of it.
If I want a simple list then a ListBox is fine, but if I want proper columns I will use a ListView.


Perhaps think of a control that is in other frameworks but not ASM.
For example, dotnet has a DataGridView (very complex) and a Splitter/SplitContainer that I would love to use.
My splitter is sort of working but really low priority. One day...

NoCforMe

Quote from: sinsi on May 24, 2025, 12:44:29 PMPerhaps think of a control that is in other frameworks but not ASM.
For example, dotnet has a DataGridView (very complex) and a Splitter/SplitContainer that I would love to use.

DataGridView: tell us more. Sounds like it's at least related to my mcLB.

QuoteMy splitter is sort of working but really low priority. One day...

I started work on a splitter too (not a control, just splittable windows). A bit tricky; still on the "unfinished" pile.
32-bit code and Windows 7 foreva!

Quin

Here are the docs for DataGridView.
I've used it from C# and VB.NET, it works quite well.

NoCforMe

Unfortunately no pictures there, but I was able to find some elsewhere.
So it looks a lot like a ListView, though a whole lot more complex and with much more functionality.
32-bit code and Windows 7 foreva!