[C++ Win32] Deleten van ListView items

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
Zie m'n volgende post, nu blijft het probleem over dat maar de helft van de selectie wordt verwijderd.

Ben ik weer (vraag nummer 3) over List Views. Nu heb ik een probleem met items verwijderen.

Eerst de code. De functie die (sub)item toevoegt.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void AddItem(int lijstindex) {
    // Arrays vullen
    SendMessage(hNaam,WM_GETTEXT,16,(LPARAM)name);
    SendMessage(hRatio,WM_GETTEXT,16,(LPARAM)CijferRatioChar);
    SendMessage(hFouten,WM_GETTEXT,16,(LPARAM)AantalFoutChar);
    float CijferRatio = atof(CijferRatioChar);
    float AantalFout = atof(AantalFoutChar);
    float fCijfer = 10 - (AantalFout/CijferRatio);
    if(fCijfer < 1.0) {
        fCijfer = 1.0;
    } else if(fCijfer > 10.0) {
        fCijfer = 10.0;
    }
    sprintf(Cijfer,"%.1f",fCijfer);
    
    // Erase de array voor hergebruik
    for(int a = 0;a < 16;a++) {
        leerlingen[lijstindex].naam[a] = 0;
        leerlingen[lijstindex].verhouding[a] = 0;
        leerlingen[lijstindex].fouten[a] = 0;
        leerlingen[lijstindex].cijfer[a] = 0;
    }

    // Struct opvullen
    strcat(leerlingen[lijstindex].naam,name);
    strcat(leerlingen[lijstindex].verhouding,CijferRatioChar);
    strcat(leerlingen[lijstindex].fouten,AantalFoutChar);
    strcat(leerlingen[lijstindex].cijfer,Cijfer);
    
    // Lijstitem toevoegen
    LVITEM lvI;
    lvI.mask = LVIF_TEXT|LVIF_STATE;
    lvI.iSubItem = 0;
    lvI.state = 0;
    lvI.iItem = lijstindex;
    lvI.pszText = LPSTR_TEXTCALLBACK; // deze gaat naar WM_NOTIFY, LVN_GETDISPINFO
    SendMessage(hNote,LVM_INSERTITEM,0,(LPARAM)&lvI);
}


De structs. Eentje per rij.
C++:
1
2
3
4
5
6
struct {
    char naam[16];
    char verhouding[16];
    char fouten[16];
    char cijfer[16];
} leerlingen[64];


Toevoegen en verwijderen in WM_COMMAND.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
case IDC_PUT: {
    AddItem(nextitem);
    nextitem++;
    break;
}
case IDC_DEL: {
    int count = SendMessage(hNote,LVM_GETITEMCOUNT,0,0);
    for(int a = 0;a < count;a++) {
        if(SendMessage(hNote,LVM_GETITEMSTATE,a,LVIS_SELECTED) == LVIS_SELECTED) {
            SendMessage(hNote,LVM_DELETEITEM,a,0);
        }
    }
    break;
}


En als laatst nog WM_NOTIFY, die de kolommen invult.
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
case WM_NOTIFY: {
    switch (((LPNMHDR) lParam)->code) {
        case LVN_GETDISPINFO: {
            NMLVDISPINFO* plvdi;
            plvdi = (NMLVDISPINFO*) lParam;
            switch (plvdi->item.iSubItem) {
                case 0: {
                    plvdi->item.pszText = leerlingen[plvdi->item.iItem].naam;
                    break;
                }
                case 1: {
                    plvdi->item.pszText = leerlingen[plvdi->item.iItem].verhouding;
                    break;
                }
                case 2: {
                    plvdi->item.pszText = leerlingen[plvdi->item.iItem].fouten;
                    break;
                }
                case 3: {
                    plvdi->item.pszText = leerlingen[plvdi->item.iItem].cijfer;
                    break;
                }
                default:
                    break;
            }
            break;
        }
        case LVN_ENDLABELEDIT:
            return true;
        default: 
            return DefWindowProc(hwnd, Message, wParam, lParam);
    }
    break;
}


Het probleem is dat het deleten van lijstitems de verkeerde items verwijdert. Ook, als bijvoorbeeld een item wordt verwijderd, en er wordt er weer één toegevoegd, dat dan de oude inhoud wordt teruggezet. dat terwijl ik toch echt NIET structs wil hergebruiken (de aan de functie meegegeven index kan alleen maar meer worden).

Edit: Voorbeeld. Hier maken we een paar items aan.
Afbeeldingslocatie: http://img571.imageshack.us/img571/95/36801828.png

Dan verwijderen we die drie, en maken er 5 aan met een nieuwe naam, 'Pieter'.
Afbeeldingslocatie: http://img687.imageshack.us/img687/280/31824519.png

Dan zie je dat de oudes weer terugkomen. Terwijl lijstindex in AddItem() gewoon constant met 1 toeneemt.

Edit2: HTML-uitdraai gemaakt van die 64 structs na wat random toevoegen. Hier lijkt alles goed te gaan.
Afbeeldingslocatie: http://img686.imageshack.us/img686/1880/45368595.png

Na het verwijderen van de items blijft de inhoud in de structs. Da's niet zo'n probleem. Die gebruiken we toch niet meer. We tellen gewoon door.

[ Voor 20% gewijzigd door Orwell op 15-06-2010 09:06 ]


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 12:01
Na je eerste LVM_DELETEITEM is de lijst veranderd, houd je daar rekening mee?

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
farlane schreef op dinsdag 15 juni 2010 @ 01:15:
Na je eerste LVM_DELETEITEM is de lijst veranderd, houd je daar rekening mee?
Dat zou niets uit moeten maken. De lijstitems behouden elk hun eigen struct, alleen valt er een gat in, en wordt één van die structs niet meer gebruikt.

En zo worden als het goed is alle items afgegaan, maar het probleem is, dat maar ongeveer de helft van de selectie verwerkt wordt (de for-loop stopt bij de helft, ook al is 'count' goed).

Heb nu overigens het probleem van de herhalende namen (zie screen één en twee) weggekregen door de achtergebleven structs van weggegooide items te legen, en de structs van nieuwere (hogere index) allemaal op te schuiven naar beneden.

Dus als je bijvoorbeeld #3 weggooit, gaat struct van #4 naar #3, #5 naar #4, enzovoorts.

Acties:
  • 0 Henk 'm!

  • ATS
  • Registratie: September 2001
  • Laatst online: 10-09 06:36

ATS

Als je lijsten doorwerkt en er items uit wil verwijderen, kan je in mijn ervaring het beste achteraan de lijst beginnen en dan naar voren werken. Dan heb je nooit problemen met het feit dat de lijst veranderd is.

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant


Acties:
  • 0 Henk 'm!

  • jmzeeman
  • Registratie: April 2007
  • Laatst online: 08-09 07:36
Er zijn twee dingen mis met je delete loopje:

1: Je gaat er vanuit dat de return waarde van LVM_GETITEMSTATE altijd exact LVIS_SELECTED is waneer een item geselecteerd is. Dit hoeft niet zo te zijn, alleen de bits die 1 zijn in LVIS_SELECTED zijn geldig. Dit betekend dat je niet zomaar met LVIS_SELECTED kan vergelijken. Je zal eerst de uitkomst met LVIS_SELECTED moeten bitwise anden.
dus:
C++:
1
2
3
if(SendMessage(hNote,LVM_GETITEMSTATE,a,LVIS_SELECTED) & LVIS_SELECTED == LVIS_SELECTED ) {
            SendMessage(hNote,LVM_DELETEITEM,a,0);
        }
quote: MSDN
The only valid bits in the return value are those that correspond to the bits set in the lParam parameter.
http://msdn.microsoft.com.../bb761053%28VS.85%29.aspx

2: Daarnaast hou je er geen rekening mee dat de listview items in de listview opschuiven als je een item verwijderd. Dit zou je op kunnen lossen door zoals ATS zegt van achteren te beginnen of door de delete met PostMessage te sturen (postmessage plaatst een message in de queue en sendmessage handelt hem inline af).
Zoals het er nu staat verwijder je een item (je gebruikt sendmessage dus de delete wordt nog in je loop gedaan) het volgende item krijgt je huidige index maar je verhoogt de index waardoor dat item wordt overgeslagen.

[ Voor 28% gewijzigd door jmzeeman op 15-06-2010 11:09 ]


Acties:
  • 0 Henk 'm!

  • Orwell
  • Registratie: December 2009
  • Laatst online: 08-09 22:11
ATS en jmzeeman schreven op dinsdag 15 juni 2010:
Probeer de selectie eens andersom af te werken.
Geen idee waarom, maar het werkt nog ook. :D

Laten we eens niet asociaal doen, en de oplossing posten. ;)
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
case IDC_DEL: {
    int count = SendMessage(hNote,LVM_GETITEMCOUNT,0,0);
    for(int a = count-1;a >= 0;a--) {
        if(SendMessage(hNote,LVM_GETITEMSTATE,a,LVIS_SELECTED) && LVIS_SELECTED == LVIS_SELECTED) { // 0-based
            SendMessage(hNote,LVM_DELETEITEM,a,0);
            for(int b = a+1;b <= nextitem;b++) {
                strcpy(leerlingen[b-1].naam,leerlingen[b].naam); // (dest,source)
                strcpy(leerlingen[b-1].verhouding,leerlingen[b].verhouding);
                strcpy(leerlingen[b-1].fouten,leerlingen[b].fouten);
                strcpy(leerlingen[b-1].cijfer,leerlingen[b].cijfer);
            }
            nextitem--;
        }
    }
    break;
}


Wat ie nu dus doet is bovenaan de index (en dus onderaan de lijst) beginnen met selectie uitgummen. Daarbij wordt bij elke hit de struct van dat item overgeschreven met die van een index hoger, en zo schuiven de hogere structs allemaal eentje op.

Over het wachten met messages afhandelen, en ze op de wachtdump in de messageloop gooien; het is nu niet nodig, maar bedankt voor de tip! Wist niet eens wat PostMessage was. :P
Pagina: 1