Filter ListView/ListIcon contents

Just starting out? Need help? Post your questions and find answers here.
Amundo
Enthusiast
Enthusiast
Posts: 200
Joined: Thu Feb 16, 2006 1:41 am
Location: New Zealand

Filter ListView/ListIcon contents

Post by Amundo »

Greetings,

I've had a search through the forum, but before I go down the rabbit hole, I wanted to post the question here.

In my application, which uses a ListIcon gadget to list, for example, computers, I'd like to apply a filter which would only display matching entries.

I'm thinking that alongside my ListIcon, I need a structured array to buffer what the ListIcon would display but with an additional dimension (called "Filtered"?) which would be true/false according to whether the array element gets copied to the ListIcon or not.

And the Filter gadget itself (an Edit) field, would have a delay if anything is entered, before traversing the array and updating the Filtered field, resulting in a row being (virtually) visible or hidden.

Thanks in advance for any help,
Amundo
Win10, PB6.x, okayish CPU, onboard video card, fuzzy monitor (or is that my eyesight?)
"When the facts change, I change my mind" - John Maynard Keynes
User avatar
jacdelad
Addict
Addict
Posts: 1991
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Filter ListView/ListIcon contents

Post by jacdelad »

On Windows you can create 2 groups in the ListIconGadget. One group visible, one not. By moving the items between the groups, you can control visibility. If you use header less groups, it even won't look differently.
https://github.com/jacdelad/LIGEnhancements
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Amundo
Enthusiast
Enthusiast
Posts: 200
Joined: Thu Feb 16, 2006 1:41 am
Location: New Zealand

Re: Filter ListView/ListIcon contents

Post by Amundo »

jacdelad wrote: Tue Mar 11, 2025 7:24 am On Windows you can create 2 groups in the ListIconGadget. One group visible, one not. By moving the items between the groups, you can control visibility. If you use header less groups, it even won't look differently.
https://github.com/jacdelad/LIGEnhancements
Thanks jacdelad, I'll take a look
Win10, PB6.x, okayish CPU, onboard video card, fuzzy monitor (or is that my eyesight?)
"When the facts change, I change my mind" - John Maynard Keynes
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: Filter ListView/ListIcon contents

Post by Zapman »

If I had to approach this problem, I would consider it as an interface to a database.
I would build a database with all the data (unfiltered). This can be done with SQL if the amount of data is large, or simply as a list of items (with NewList(), in PureBasic) if the number is small.
  • The content presented in the ListIcon is then only an interface, that is, a sort of "window" allowing you to view part of the data based on the applied filter.
  • Each time the filter is modified, a search is performed in the database and the result replaces what was previously in the ListIcon.
  • You will probably need to maintain a reliable link between the database data and the displayed data. If there is a unique field that identifies each database item and this field is displayed in the ListIcon, this will be sufficient to establish the link. If not, you can assign a unique number to each item and store this number in the hidden part of the ListIcon, using SetGadgetItemData(). This way, when the user clicks on a row in the ListIcon, you can simply get the corresponding number with GetGadgetItemData() to find the corresponding item in your database.
And to answer your question in PM, yes, of course, you can use the code from "ColumnSortedListIconGadget.pbi" as you want, without any restrictions, like all the other codes I have published on the forum.
User avatar
jacdelad
Addict
Addict
Posts: 1991
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Filter ListView/ListIcon contents

Post by jacdelad »

It is much faster, at least ln windows, to switch between visible and invisible groups, than to fill/refill the ListView. This still applies when using SendMessage_(MyLIGID, #WM_SetRedraw, 0, 0).
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Amundo
Enthusiast
Enthusiast
Posts: 200
Joined: Thu Feb 16, 2006 1:41 am
Location: New Zealand

Re: Filter ListView/ListIcon contents

Post by Amundo »

Thanks Zapman, as I stated in my initial post, I went down the rabbit hole and used a List to buffer the data for the gadget (attached demo code shamelessly copied from Zapman's code and uses his Sortable ListIcon: https://www.purebasic.fr/english/viewtopic.php?t=86369)

By the way, the real application reads data from several Windows servers to display in the ListIcon. Being able to filter "on the fly" is a god-send when you're trying to quickly find one piece of information amongst potentially hundreds of rows. The demo only filters on the first column, but you get the idea...

Code: Select all

EnableExplicit

XIncludeFile "ColumnSortedListIconGadget.pbi"

Define Timer0
Define Filter0$
Define Event
Define FilterLen

Structure RowElement
  Col0.s
  Col1.s
  Col2.s
  Col3.s
  Col4.s
  Col5.s
  Col6.s
  Filtered.b    ; Visible (0) Or Hidden (1)?
EndStructure

Global NewList ListIconData.RowElement() ; use a List as opposed to an Arry because all the sorting
                                         ; is handled by Zapman's code - thanks again, Zapman!

Procedure Resort(GagdetID)
  Protected LastColumn, LastAscentDescent
  LastColumn = GetLastSortingColumn(GagdetID)
  LastAscentDescent = GetLastSortingAscentDescent(GagdetID)
  SortListIcon(GagdetID, LastColumn, LastAscentDescent)
EndProcedure

Procedure ResetFilteredField()
  ForEach ListIconData()
    ListIconData()\Filtered = #False
  Next
EndProcedure

Procedure FilterGadget(Col, Str$)
  ; Filter List field based on Col
  Protected Field$
  ForEach ListIconData()
    Select Col
      Case 0
        Field$ = ListIconData()\Col0
      Case 1
        Field$ = ListIconData()\Col1
      Case 2
        Field$ = ListIconData()\Col2
      Case 3
        Field$ = ListIconData()\Col3
      Case 4
        Field$ = ListIconData()\Col4
      Case 5
        Field$ = ListIconData()\Col5
      Case 6
        Field$ = ListIconData()\Col6
    EndSelect          
    If FindString(Field$, Str$, 1, #PB_String_NoCase)
      ListIconData()\Filtered = #False
    Else
      ListIconData()\Filtered = #True
    EndIf
  Next
EndProcedure

Procedure UpdateListIcon(GagdetID)
  ; Populate ListIcon taking Filtered field into account
  Protected Line$
  ClearGadgetItems(GagdetID)
  ForEach ListIconData()
    If ListIconData()\Filtered
      Continue
    EndIf
    Line$ = ListIconData()\Col0 + Chr(10)
    Line$ + ListIconData()\Col1 + Chr(10)
    Line$ + ListIconData()\Col2 + Chr(10)
    Line$ + ListIconData()\Col3 + Chr(10)
    Line$ + ListIconData()\Col4 + Chr(10)
    Line$ + ListIconData()\Col5 + Chr(10)
    Line$ + ListIconData()\Col6 + Chr(10)
    AddGadgetItem(GagdetID, - 1, Line$)
  Next
  Resort(GagdetID)
EndProcedure

Define HWindow = OpenWindow(#PB_Any, 0, 0, 550, 320, "Sortable ListIconGadget demo", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
;
Global ListIconGagdet = ListIconGadget(#PB_Any, 0, 30, WindowWidth(HWindow), 225, "", 0, #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection)
Define Filter0 = EditorGadget(#PB_Any, 0, 5, 70, 20)
;
AddGadgetColumn(ListIconGagdet, 0, "Alpha", 70)
SetGadgetItemAttribute(ListIconGagdet, 0, #PB_ListIcon_ColumnAlignment, #PB_ListIcon_Center, 0)
AddGadgetColumn(ListIconGagdet, 1, "Integer", 70)
AddGadgetColumn(ListIconGagdet, 2, "Decimal", 80)
AddGadgetColumn(ListIconGagdet, 3, "Hexa", 80)
AddGadgetColumn(ListIconGagdet, 4, "Dates", 80)
AddGadgetColumn(ListIconGagdet, 5, "Hours", 80)
AddGadgetColumn(ListIconGagdet, 6, "Sporty", 80)
SetGadgetItemAttribute(ListIconGagdet, 0, #PB_ListIcon_ColumnAlignment, #PB_ListIcon_Center, 6)
;
Define ct
For ct = 1 To 5
  SetGadgetItemAttribute(ListIconGagdet, 0, #PB_ListIcon_ColumnAlignment, #PB_ListIcon_Right, ct)
Next
;
Define mDate.q = Date()
Define AlphaList$ = "élève,devant,front,Absent,Column,Final,tirant,global,$,"
Define HourList$ = "12:30:20,12:30:00,12:30,18:10,6:00 PM,11:00 AM,9:45:15,8:45,16h30mn,"
Define SportyTimeList$ = "30'',5'20'',1'14''80''',1'14,5'80''',20'',10'50'',4'40''30''',90'''"
For ct = 1 To 9
  AddElement(ListIconData())
  ListIconData()\Col0 = StringField(AlphaList$, ct, ",")
  ListIconData()\Col1 = Str(Random($FFFF))
  ListIconData()\Col2 = StrF(Random($FFFFFF)/10000, 3)
  ListIconData()\Col3 = "$" + RSet(Hex(Random($7FFFFFFF)), 8, "0")
  ListIconData()\Col4 = FormatDate(CSLI_DateFormat$, mDate)
  mDate + 100000
  ListIconData()\Col5 = StringField(HourList$, ct, ",")
  ListIconData()\Col6 = StringField(SportyTimeList$, ct, ",")
  ListIconData()\Filtered = 0           ; 0 = visible
Next
UpdateListIcon(ListIconGagdet)      ; populate gadget from List data
                                    ;
Define NotSortableOption     = OptionGadget(#PB_Any, 15, WindowHeight(HWindow) - 50, 140, 22, "Reset to not sortable")
Define DontShowArrowsOption  = OptionGadget(#PB_Any, 190, WindowHeight(HWindow) - 50, 150, 22, "Sortable with no arrows")
Define ShowLeftArrowsOption  = OptionGadget(#PB_Any, 375, WindowHeight(HWindow) - 50, 150, 22, "Sortable with left arrows")
Define ShowTopArrowsOption   = OptionGadget(#PB_Any, 15, WindowHeight(HWindow) - 30, 400, 22, "Sortable with top arrows (when clicked) - (XP compatible)")
SetGadgetState(ShowLeftArrowsOption, 1)
:
;
MakeListIconSortable(ListIconGagdet, #CSLI_LeftArrows) ; <-- This is the only line you need to make the gadget sortable.
                                                       ;
                                                       ; But you can also decide to sort the gadget by default from one column content:
SortListIcon(ListIconGagdet, 0, #CSLI_Ascent)
;
Repeat
  Event = WaitWindowEvent()
  If Event = #PB_Event_Timer
    Select EventTimer()
      Case Timer0
        Debug "Timer0 triggered, time to apply Filter0"
        RemoveWindowTimer(HWindow, Timer0)
        Filter0$ = GetGadgetText(Filter0)
        FilterGadget(0, Filter0$)
        UpdateListIcon(ListIconGagdet)
    EndSelect
  EndIf
  If Event = #PB_Event_Gadget
    Select EventGadget()
      Case Filter0
        If EventType() = #PB_EventType_Change
          Filter0$ = GetGadgetText(Filter0)
          Debug "Filter0 changed!" + Filter0$
          If Len(Filter0$) = 0
            ; filter field cleared, reset Filtered field(s) to all be visible
            ResetFilteredField()
            UpdateListIcon(ListIconGagdet)
            RemoveWindowTimer(HWindow, Timer0)
          Else
            RemoveWindowTimer(HWindow, Timer0)      ; reset timer
            AddWindowTimer(HWindow, Timer0, 1000)
          EndIf
        EndIf
      Case NotSortableOption
        MakeListIconSortable(ListIconGagdet, #CSLI_NotSortable)
      Case DontShowArrowsOption
        MakeListIconSortable(ListIconGagdet, #CSLI_NoArrow)
      Case ShowLeftArrowsOption
        MakeListIconSortable(ListIconGagdet, #CSLI_LeftArrows)
      Case ShowTopArrowsOption
        MakeListIconSortable(ListIconGagdet, #CSLI_TopArrows)
    EndSelect
  EndIf
Until Event = #PB_Event_CloseWindow
Win10, PB6.x, okayish CPU, onboard video card, fuzzy monitor (or is that my eyesight?)
"When the facts change, I change my mind" - John Maynard Keynes
User avatar
Zapman
Enthusiast
Enthusiast
Posts: 205
Joined: Tue Jan 07, 2020 7:27 pm

Re: Filter ListView/ListIcon contents

Post by Zapman »

Good point, Amundo, it works perfectly for me. The timer setting seems perfect.
Did you achieve exactly what you wanted?
Amundo
Enthusiast
Enthusiast
Posts: 200
Joined: Thu Feb 16, 2006 1:41 am
Location: New Zealand

Re: Filter ListView/ListIcon contents

Post by Amundo »

Hi Zapman,

I'm (mostly) back from solving a long real-life issue, but yes, it seems to work great - just a few bugs to iron out (famous last words, right?).

Thanks again for all your help and sharing.

(Actually, the next major task is to populate the ListIcon from a thread...wish me luck!)
Win10, PB6.x, okayish CPU, onboard video card, fuzzy monitor (or is that my eyesight?)
"When the facts change, I change my mind" - John Maynard Keynes
User avatar
mk-soft
Always Here
Always Here
Posts: 6201
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Filter ListView/ListIcon contents

Post by mk-soft »

As long as it is Windows, you can also fill the ListIconGadget from a thread.
But be sure to activate the ThreadSafe compiler option.
Under Linux and macOS you have to pass the data to the MainScope with PostEvent.
To do this, search for: ‘Mini Thread Control’
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
boddhi
Enthusiast
Enthusiast
Posts: 524
Joined: Mon Nov 15, 2010 9:53 pm

Re: Filter ListView/ListIcon contents

Post by boddhi »

Hello,

For filtering rows in a LIG, you can also see this post by nicolaus and the adaptation made by flype.
Note : Some constants are now native in PB and must be commented :wink:
If my English syntax and lexicon are incorrect, please bear with Google translate and DeepL. They rarely agree with each other!
Except on this sentence...
Post Reply