Jump to content
Tuts 4 You

How to handle dynamic tabs & controls?


LCF-AT

Recommended Posts

Hi guys,

I have again a little question and need some input from others.This time I would like ask how you do handle dynamic controls.

Example: Just imagine you do create a tab control and each tab does show new controls like a listview / box and more and you can also delete and move tabs to other positions etc.The question I have is how to store all handles of all controls what does belong to one and same tab?Lets say you create a tab control with 5 tabs and 5 Listview controls then you can store all LV handles in a free section from first tab till last tab in a row.Now if you do move a tab to other position like in browser then you can also move the handles into free section to new position.Also if you delete a tab then you can also delete the LV handle from free section and move all following handle postions 4 bytes up.All almost ok so far.But what is if you have a lot more to handle?How to store all the infos which belongs to one tab correctly and smart?As I said its just a question and wanted to know how you do handle such issues then I think my handling is not so smart. :)

greetz

Link to comment

I think you can use a mixture of dynamic multi-dimensional arrays, this way you can set them, retrieve them, and I also heard you can adjust them accordingly with some memory allocation later on at runtime so it fits perfectly for the job.

You could do a 4x4 Multi-Dimensional Array, like so:

FFef0vm.png

then:

M75kn.png

You can say:

a[0] // Will store our LV Handlers.
a[1] //Tab 1 / Row Position ... ? / Data ... ?

Edited by 0xNOP
  • Like 1
Link to comment

Hi again,

thanks for the info.Its still tricky.The only thing what I could maybe do its to create a static struct to store all handles of one tab into a section.

Section:
--------------------------------
00000000 | TabIndex
00000004 | Handle1
00000008 | Handle2
0000000C | Handle3
00000010 | 00000000
00000014 | TabIndex
00000018 | Handle4
0000001C | Handle5
00000020 | Handle6
00000024 | Handle7
00000028 | FFFFFFFF
etc

Maybe in blocks of 14 bytes lenght to store max the tab index at top of block + max 4 handles below.Hhmmmm.Its also not so smart or?If I exchange first tab with second tab then I also need first to backup both blocks and exchange them into store section or just only the tabindex value.What is if I delete one tab....then I also need to move all below one block higher.So anyhow there comes no better idea in my head how to handle this.

greetz

  • Like 1
Link to comment
  • 8 months later...

Hi again,

so I have another question about building any smart arrays.I am still fighting to create something simple and good working way to handle the entire stuff.

Example: Almost same as I did post above.I have LVs with Tabs (tab x does show LV x) and 5 rows in each LV and dynamic entrys in the LV etc.Now I have that problem...

lets say I have 5 entrys in LV 1.

LV 1
--------------------------
A | B  | Count
--------------------------
1 | NY | 1000
2 | IL | 1001
3 | NH | 2222
4 | BE | 3001
5 | UR | 5555
--------------------------

Thats the example content of my LV 1.I also can change the positions of all lines (line 1 to line 2 or 3 etc).All clear & ok so far.Now the problem I have...I do select any line in this LV (maybe line 1) and I do start now a new thread (thread does count all seconds since the thread was startet and does add each second into the count row of the line I have selected).Now right before I do start the thread I have to send also the info into this thread which line I have  selected (in this case LV 1 handle and line 1 in the LV).All ok so far.The problem now is that the value of the selected line I did send with into the thread is a static information.

Thread has info about the LV handle which keeps same & if LV keeps alive if it wasnt deleted.The line info (line 1 position) instead can be changed by the user if the user does change the line positions in the LV itself.

Again: I do select line 1 and start a thread to count elapsed time seconds into the count row of line 1.Now the thread does run and  also has the into about LV handle and the line 1 to fill the new datas into the count row of line 1 = working so far.Now the thread is running and now lets say I wanna change the line position 1 with the line 5 during  the thread is running.Now I have changed line 1 with line 5 BUT my working thread dosent know that I did change the line.So the question is how to tell my thread that line 1 is now on line 5 to fill another count infos into line 5 and no more into line 1.You know what I mean right?So i want prevent filling count datas into any wrong line.So how can I check this and update the line info into my thread BEFORE the thread does write new infos into line x?So that the tricky part for me to handle  that anyhow without to disable line movings in the LV itself.

The question is how to handle this on any good and possible simple way without to make any mistakes and to prevent  sending datas into wrong lines.So has anyone of you any ideas how it could be handled nice & correctly?

Are there maybe other methods I could use and dont know yet?Maybe something like to mark a selected with one thread (make it fix / lock anyhow) so that it will also send automatically the datas into the right line also if I have changed the position of this line in the LV?So you can also change the row positions from left to right or else without to have that problems sending the datas into right row you know so maybe there is also something like this for line positions too or?

Maybe anyone has some ideas to handle that problem I have with that LV positions etc.Some help would be very nice again of course just to bring me on the right direction. :)

Thank you

Link to comment

well each LVITEM / LV_ITEM (https://msdn.microsoft.com/en-us/library/windows/desktop/bb774760(v=vs.85).aspx) does also have an lParam field which you can use for storing a unique index, then it shouldn't matter if the listitem moves position as its original designated index (iItem) is always what it was when it was created and stored as lParam.

you could set or get lParam something like this:
 

ListViewSetItemParam PROC PUBLIC hListview:DWORD, nItemIndex:DWORD, ParamValue:DWORD
    LOCAL LVItem:LV_ITEM
    mov LVItem.imask,LVIF_PARAM
    mov eax, nItemIndex
    mov LVItem.iItem, eax
    mov LVItem.iSubItem,0
    mov eax, ParamValue
    push eax
    pop LVItem.lParam
    invoke SendMessage, hListview, LVM_SETITEM, 0, Addr LVItem
    ret
ListViewSetItemParam ENDP

ListViewGetItemParam PROC PUBLIC hListview:DWORD, nItemIndex:DWORD
    LOCAL LVItem:LV_ITEM
    mov LVItem.imask,LVIF_PARAM
    mov eax, nItemIndex
    mov LVItem.iItem, eax
    mov LVItem.iSubItem,0
    invoke SendMessage, hListview, LVM_GETITEM, nItemIndex, Addr LVItem
    .iF eax == TRUE
        mov eax, LVItem.lParam
    .ELSE
        mov eax, -1
    .ENDIF
    ret
ListViewGetItemParam ENDP

 

Edited by fearless
add code for set/get lparam
  • Like 1
Link to comment

Hi again,

could you explain it a little more?So before I start any thread I do read the selected line of LV & handle of LV.Thats the 2 infos I have and send them also in the thread where it does fill new results into line 2.

So do you mean I should use the ListViewSetItemParam (hListview = handle & nItemIndex = selected line & what do I set in ParamValue into?) and in my thread I do use ListViewGetItemParam before I write something into LV?Hhmmm,somehow I dont get it yet. :(

greetz

Link to comment

It depends on how your setting the information in the listview. But ordinarily if you have the listitem's index you can use that to set text for the item or subitems. So if you have already got that info then should be ok, if not then you can send a parameter to the thread, like a special block of data that holds some useful information:

 

SOMEDATA 		STRUCT
	hListview 	DD 0 ; handle to listview
	iItem 		DD 0 ; item index no
SOMEDATA 		ENDS

 

when you use LVM_INSERTITEM or similar it returns index of new item or -1 if unsuccessful. You can store that in the lParam of the listitem, but only if required, otherwise you can store other info in this field

So really depends on the code works and how exactly the information is relayed back and forth i suppose.

 

Link to comment

Hi again,

still dont get it.

Once again.I have a LV with some lines  into and some rows.If I start the thread I read the selected line position & handle of LV and this data I send with in my thread.Now if the thread does run it does write new datas into the line x row y.If I change the position of line x with the mouse to other position then the thread will of course write new datas into wrong line now.

checkoIN.p_loc = Selected line info I did read before I did start the thread
TIMEBUFF = Time Data info I do read in the thread
checkoIN.p_hwnd = Handle of LV I did read before starting the thread

mov lvis.imask, LVIF_TEXT
mov ecx, checkoIN.p_loc
mov lvis.iItem, ecx
mov lvis.iSubItem, 4
lea ecx, TIMEBUFF
mov lvis.pszText, ecx
mov lvis.cchTextMax, sizeof TIMEBUFF 
invoke SendMessage,checkoIN.p_hwnd, LVM_SETITEM, 0, addr lvis

I only use SETITEM to set actually infos into right location x and subitem 4.Thats all.

Now before I do write go on infos into location x I need to know whether location x is still same or not to prevent writing new infos into wrong location.So how could LPARAM help or the ListViewSetItemParam & ListViewGetItemParam procs?

greetz

Link to comment

Depends on how the listitems are being moved, as in is the listview being generated anew each time by deleting all listitems and added them again.

If the index of positions is changing then its harder to define what the original item is or was.

In some cases it might be easier to sort all the data out in an array before it is added to the listview, and use the lParam value as a way of tracking the offset into the array.

otherwise you can loop through all listview items and read the lParam value and see if that == original item that was sent to the thread. Requires the lParam of the original item to have been sent to the thread.

So its just using lParam as a master index, but that only works in certain circumstances and depends on how the listitems are added/deleted/moved etc - in some cases it might not be appropriate to use this, so the other suggestion of using an array to map all the data might be handier.

  • Like 1
Link to comment

Hi again,

so I have checked this again and using Param isnt good in my case so its already used for sorting process where it does set Param index same as LV count lines.So if I sort a row then all entrys get also a Param.If I dont sort then no Param is used but if I now set a custom Param at the line I have selected then it will keep on this line also if I move the lines to other position via drag / drop.In this case I also would  need to move the Param too during a position move.Also if this would work then I should first check where the set Param value x is to find in my LV in my thread and I couldnt just use the Param value x to update any text entry.

Before thread starts: I get selected line x = 3 example.Now set a Param  value of 111 for this line

My thread: Has info about Line 3 and handle.Now I need to search for Param value 111 in entire LV which belongs to handle I did send with.If it was found then I also have  the right line x and then I could use it to send new text into.But as I said if I do a sort then the Param does change to 2 = no more 111 into.

Maybe I need to disable sort function so long the thread is working or I need to find any other way & solution.

greetz

Link to comment

Hi again,

ok I tried something else now.So I did just add another row into my LVs where I do set a counter into and before I start any thread I do increase the counter one time for each thread and in the thread itself I just check first all entrys at the counter row to find the counter value I did set before starting the thread and if found then I use this iItem.So in this case I dont need to store any location position anymore.So on first tests it does work.

I selected line  1
Now I inc a static variable
Then I set R x into selected line at row C
Now I start the thread with the info R x only
In the thread I search for R x in  entire LV and if found = item value
If nothing was found = failed = line no more present = terminate thread
If found then I can write / update new text in the right location


LV 1
--------------------------
A | B  | Count | C
--------------------------
1 | NY | 1000  | R 1
2 | IL | 1001  |
3 | NH | 2222  |
4 | BE | 3001  |
5 | UR | 5555  |
--------------------------


LV 1
--------------------------
A | B  | Count | C
--------------------------
1 | UR | 5555  |
2 | IL | 1001  |
3 | NH | 2222  |
4 | BE | 3001  |
5 | NY | 1000  | R 1
--------------------------

Ok,it seems to work so far.Maybe not so great that I have to use a new visible LV row but with that I can also live. :) Just hope that this method not makes any trouble later or so.

greetz

Link to comment

you could still use lParam - you just need to allocate a block of memory to it for the value for sorting and the thread/index information

so like a structure of memory could be
 

SOMEEXTRADATA 			STRUCT
  dwMasterIndexThreadThing 	DD 0
  dwOriginallParamValue 	DD 0
SOMEEXTRADATA 			ENDS

each lParam can be an addr of a SOMEEXTRADATA structure memory sized block

then in the compare function of LVM_SORTITEMS you take the lParam1 value which is an addr of a SOMEEXTRADATA block of mem, fetch original lParam to compare against vs lParam1's SOMEEXTRADATA.dwOriginallParamValue

so something like:
 

CompareListItemsProc USES ebx lParam1:DWORD, lParam2:DWORD, wParam:DWORD
	LOCAL dwOriginallParam1:DWORD
	LOCAL dwOriginalParam2:DWORD

	mov ebx, lParam1
	mov eax, [ebx].SOMEEXTRADATA.dwOriginallParamValue
	mov dwOriginallParam1, eax
	mov ebx, lParam2
	mov eax, [ebx].SOMEEXTRADATA.dwOriginallParamValue
	mov dwOriginallParam2, eax

	.IF eax == dwOriginallParam1
		; return whatever LVM_SORTITEMS proc says to return for lParam1 == lParam2
	.ELSEIF eax > dwOriginallParam1
		; return whatever LVM_SORTITEMS proc says to return for lParam1 < lParam2
	.ELSEIF eax < dwOriginallParam1
		; return whatever LVM_SORTITEMS proc says to return for lParam1 > lParam2
	.ENDIF
	
	ret
CompareListItemsProc ENDP

 

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...