CListCtrl, wie hoch ist die maximale Aufnahmekapazität von Daten
-
Hallo,
weiss jemand, wie viele Daten ich in ein CListCtrl mit 8 Spalten (ca. 20-40 Byte pro Feld)
Ich muss nämlich 50000 Zeile darstellen, aber es leider klappt es nicht, weil Prg beim Anzeigen abstürzt.
Bei ca. 9000 Zeilen geht es jedoch. Mir drängt sich der Gedanke auf, dass die Liste gar nicht so viele Daten auf nehmen kann und deswegen absürzt.
Liege ich hier richtig?
-
Keine Ahnung, liegt aber Nahe 50000 * ~30 Byte = 1500000 Byte = 1446 Kbyte = 1,43 MByte , hm also fürn Heap ist das nicht viel fürn Stack wärs wohl der Tod^^
Kommt eine Fehlermeldung?
-
Beim MFC-GridControl bei CodeProject gibt es einen "virtual mode": Bei großen Datenmengen werden über eine Callback-Funktion vom Grid nur die Daten angefordert, die momentan zum Anzeigen benötigt werden.
Eventuell gibt es so etwas bei CListCtrl auch? (Ich habe es noch nie verwendet).
Ansonsten wäre vielleicht der Umstieg auf dieses MFC-GridControl auch eine denkbare Alternative (ich setze es inzwischen bestimmt in 20 Programmen ein, und habe noch keine Probleme damit festgestellt).Gruß Andreas
-
Pellaeon schrieb:
Keine Ahnung, liegt aber Nahe 50000 * ~30 Byte = 1500000 Byte = 1446 Kbyte = 1,43 MByte , hm also fürn Heap ist das nicht viel fürn Stack wärs wohl der Tod^^
Kommt eine Fehlermeldung?Hallo,
danke, aber es kommt keine Fehlermeldung, einfach alles weiss und nichts geht mehr!
-
AndRo67 schrieb:
Beim MFC-GridControl bei CodeProject gibt es einen "virtual mode": Bei großen Datenmengen werden über eine Callback-Funktion vom Grid nur die Daten angefordert, die momentan zum Anzeigen benötigt werden.
Eventuell gibt es so etwas bei CListCtrl auch? (Ich habe es noch nie verwendet).
Ansonsten wäre vielleicht der Umstieg auf dieses MFC-GridControl auch eine denkbare Alternative (ich setze es inzwischen bestimmt in 20 Programmen ein, und habe noch keine Probleme damit festgestellt).Gruß Andreas
Hallo,
Danke für den Tip, wenn es anders nicht geht, muss ich wahrscheinlich hierhin ausweichen.
-
Andy007 schrieb:
Pellaeon schrieb:
Keine Ahnung, liegt aber Nahe 50000 * ~30 Byte = 1500000 Byte = 1446 Kbyte = 1,43 MByte , hm also fürn Heap ist das nicht viel fürn Stack wärs wohl der Tod^^
Kommt eine Fehlermeldung?Hallo,
danke, aber es kommt keine Fehlermeldung, einfach alles weiss und nichts geht mehr!
Das spricht dafür das die Nachrichtenschleife blockiert ist, weil er sich grade mit was beschäftigt. Kannst ja mal testen,. wenn du startest und dann 5 min nichts machst, ob dann was kommt
-
Pellaeon schrieb:
Das spricht dafür das die Nachrichtenschleife blockiert ist, weil er sich grade mit was beschäftigt. Kannst ja mal testen,. wenn du startest und dann 5 min nichts machst, ob dann was kommt
Danke dir,
bei 15000 Zeilen kommen erst nach 8 Minuten diese zur Anzeige, aber bei 50000 kommt vermutlich nichts mehr - zumindest nicht innerhalb 1 Std. denke ich
-
AndRo67 schrieb:
Beim MFC-GridControl bei CodeProject gibt es einen "virtual mode": Bei großen Datenmengen werden über eine Callback-Funktion vom Grid nur die Daten angefordert, die momentan zum Anzeigen benötigt werden.
Eventuell gibt es so etwas bei CListCtrl auch? (Ich habe es noch nie verwendet).
Ansonsten wäre vielleicht der Umstieg auf dieses MFC-GridControl auch eine denkbare Alternative (ich setze es inzwischen bestimmt in 20 Programmen ein, und habe noch keine Probleme damit festgestellt).Gruß Andreas
Hallo,
kannst du mir den genaueren Link direkt zu dem Grid posten? Danke.
-
Hi,
die Klasse CListCtrl kann diesen 'virtual mode' auch. Der Style nennt sich LVS_OWNERDATA, Du kannst auch einfach 'Benutzerdaten' in den Eigenschaften des Controls anhaken.
Wenn Du jetzt die Nachricht LVN_GETDISPINFO abfängst, kannst Du darin immer genau den Inhalt reinschreiben, der zur Zeit gerade angezeigt werden soll.
Wir haben hier ein Projekt, wo ca. 500.000 Listen-Einträge mit einer CListCtrl Tabelle dargestellt werden + läuft mit OWNERDATA superschnell
Gruß T.
-
Andy007 schrieb:
Hallo,
kannst du mir den genaueren Link direkt zu dem Grid posten? Danke.
Kann ich:
http://codeproject.com/miscctrl/gridctrl.aspEventuell ein paar mal probieren, die Site hat notorische Zugangsprobleme.
-
gerade kein login schrieb:
Hi,
die Klasse CListCtrl kann diesen 'virtual mode' auch. Der Style nennt sich LVS_OWNERDATA, Du kannst auch einfach 'Benutzerdaten' in den Eigenschaften des Controls anhaken.
Wenn Du jetzt die Nachricht LVN_GETDISPINFO abfängst, kannst Du darin immer genau den Inhalt reinschreiben, der zur Zeit gerade angezeigt werden soll.
Wir haben hier ein Projekt, wo ca. 500.000 Listen-Einträge mit einer CListCtrl Tabelle dargestellt werden + läuft mit OWNERDATA superschnell
Gruß T.
Super! Hab nicht gewußt, daß es auch mit dem Standard-CListCtrl geht. Danke!!! Hast du eventuell einen Schnipsel, wie man LVN_GETDISPINFO umsetzt?
-
AndRo67 schrieb:
Kann ich:
http://codeproject.com/miscctrl/gridctrl.aspEventuell ein paar mal probieren, die Site hat notorische Zugangsprobleme.
Danke dir!
-
Hab mal die Stelle aus dem Projekt kopiert, wie gesagt wir schreiben an der Stelle Daten aus einer DB. Je nach dem wo Deine Daten herkommen, musst Du sie halt hier dynamisch bereitstellen.
/* =================================================================================== Nachricht des ListControls abfangen, die geforderten Infos aus der Datenbank lesen und in die Liste schreiben =================================================================================== */ void CMyDlg::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; // Initialisierungen: CString str = _T(""); CString stemp = _T(""); CString strArtikelPlusTitel; COleVariant varValue; long index = pDispInfo->item.iItem; long subItem = pDispInfo->item.iSubItem; long lDataColumn = 1; if(pDispInfo->item.mask & LVIF_TEXT) //gültiger Textpuffer? { try { if ( m_RecordList.m_lCrntRecord == -1 ) // wenn Variable wegen Requery oder bei Prog-Start auf -1 gesetzt wurde { MyRecords->SetAbsolutePosition(index); // Den Index der DB mit Fenster syncronisieren m_RecordList.m_lCrntRecord = index; } else { if ( m_RecordList.m_lCrntRecord != index ) // Die Listenposition gegen glob, Hilfs-Variable checken { if ( !(MyRecords->IsEOF() || MyRecords->IsEOF()) ) { // relative Position if ( index <= (int)MyRecords->GetRecordCount() )//Check ob Listen-Pos kleiner als Anzahl der Records { const long lOffset = index - m_RecordList.m_lCrntRecord; //Offset errechnen (Differenz) if ( lOffset != 0 ) // Nochmal check ob Offset != 0 { MyRecords->Move(lOffset); //Record aktualisieren m_RecordList.m_lCrntRecord += lOffset; //glob, Hilfs-Variable um Offset korregieren } } } } } } catch(CDaoException* e) { MyRecords->DisplayDaoException(e); e->Delete(); return; } try { //Daten aus dem Datensatz ziehen: if(subItem) { lDataColumn = TranslateColumns(subItem); MyRecords->GetFieldValue(lDataColumn, varValue); } else { MyRecords->GetFieldValue(0, varValue); } } catch(CDaoException* e) { MyRecords->DisplayDaoException(e); e->Delete(); return; } const VARIANT* variant = LPCVARIANT(varValue); if(variant->vt & VT_BYREF) return; str = Variant2String(variant); if (lDataColumn == 5) { if (MyRecords->m_ARTIKEL != _T("")) { strArtikelPlusTitel = MyRecords->m_ARTIKEL + _T(" "); strArtikelPlusTitel += str; str = strArtikelPlusTitel; } } lstrcpyn(pDispInfo->item.pszText, str, pDispInfo->item.cchTextMax);//Text kopieren } if(pDispInfo->item.mask & LVIF_IMAGE) { pDispInfo->item.iImage = 0; //gültiges Bild? } *pResult = 0; }
Mit 'ner DB als Datenquelle ist der Aufwand zur Synkronisierung von DB-Zeilen und Listenzeilen etwas fummelig, aber man wird mit sehr angenehmer Performance belohnt...
Gruß T.
-
gerade kein login schrieb:
............ Mit 'ner DB als Datenquelle ist der Aufwand zur Synkronisierung von DB-Zeilen und Listenzeilen etwas fummelig, aber man wird mit sehr angenehmer Performance belohnt...
Gruß T.
Super! Ich werde versuchen, das umzusetzen. Danke!!!
-
gerade kein login schrieb:
Mit 'ner DB als Datenquelle ist der Aufwand zur Synkronisierung von DB-Zeilen und Listenzeilen etwas fummelig, aber man wird mit sehr angenehmer Performance belohnt...
Gruß T.
Hallo,
ich habe versucht, diesen "Virtual Mode" für das CListCtrl einzusetzen. Irgendwie habe ich noch nicht verstanden, was da abgeht
Unser Projekt "ID3Sort", in dem die Liste benutzt wird http://www.informatik-gruppe.de/projekte/id3sort/id3sort.htm
Vielleicht kannst du mir hier weiterhelfen
Ich habe bereits die Methode OnGetDispInfo geschrieben. Weiss aber nicht, ob sie so ungefähr richtig ist. Jedenfalls erfolgt kein Aufruf dieser Funktion! Wann wird sie denn überhaupt aufgerufen? Und von wem wird sie aufgerufen
void CID3Sort_Win_MFCDlg::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; // TODO: Code für die Behandlungsroutine der Steuerelement-Benachrichtigung hier einfügen LV_ITEM &lvItem = pDispInfo->item; if( lvItem.mask & LVIF_TEXT ) { CID3 tag; vector<CID3> tagListe = m_liste.getAllTag(); vector<CID3>::iterator current; current = tagListe.begin(); int nItem = lvItem.iItem; for( int i = 0; ( i < nItem && current != tagListe.end()); i++) { current++; } tag = *current; switch( lvItem.iSubItem ) { case 0: lvItem.pszText = (LPSTR) tag.getFileName().c_str(); break; case 1: lvItem.pszText = (LPSTR) tag.getSongTitle().c_str(); break; case 2: lvItem.pszText = (LPSTR) tag.getArtist().c_str(); break; case 3: lvItem.pszText = (LPSTR) tag.getAlbum().c_str(); break; case 4: lvItem.pszText = (LPSTR) tag.getComment().c_str(); break; case 5: lvItem.pszText = (LPSTR) tag.getYear().c_str(); break; case 6: lvItem.pszText = (LPSTR) tag.getGenre().c_str(); break; case 7: char str[10]; LongToString(tag.getFileSize(), 8, str); lvItem.pszText = (LPSTR) str; break; } } *pResult = 0; }
-
Ich schau's mir heute abend mal genauer an, bin gerade auf'er Arbeit...
Gruß T.
-
Ist noch nicht ganz korrekt, was Du machst.
Zum Verständinis: Die virtuelle Liste wird nur mit den Daten befüllt, die gerade angezeigt werden sollen.
Wenn Du diesen Ownerdata Style einsetzt, dann fordert die LVN_GETDISPINFO Nachricht Dich auf, eine Zelle der Tabelle mit Daten zu füllen.
Vorgehensweise:
- CListCtrl Membervariable erstellen.
- Eigenschaft 'Besitzerdaten' oder 'Ownerdata' im Eigenschaften Dialog aktivieren.
- Im Klassen-Assi Deine Liste auswählen (hier IDC_LIST1) und die Behandlungsroutine für LVN_GETDISPINFO erstellen lassen.
- Jetzt bekommst Du in OnGetdispinfo über pDispInfo->item.iItem bzw. pDispInfo->item.iSubItem immer genau die Zelle beschrieben, die jetzt gefüllt werden soll.
- Wichtig: Sobald Deine Applikation ermittelt hat, wieviele Einträge (Zeilen) in Deine Liste insgesamt kommen sollen, sollte das der Liste über m_ctrl_List1.SetItemCount() mitgeteilt werden. Wenn sich die Anzahl ändern sollte, musst Du auch das mitteilen.Du kannst also die For-Schleife weglassen und musst stattdessen die Daten mit Hilfe der Koordinaten die Dir LV_DISPINFO liefert, aus dem Vector holen und in die Zelle schreiben die gerade dran ist. Für die nächste Zelle kommt eine neue Nachricht.
Gruß T.
-
Super, danke dir! Ich konnte wegen Probleme mit VC++ nicht testen. Werde nun sofort testen. Vielen Dank!
-
Vielen Dank,
dieser Thread hat mir sehr geholfen.
Eine "Kleinigkeit" hab ich aber noch. Ich kann ja normalerweise mit
SetItemData dem LVITEM einen Parameter mitgeben.
Geht das auch irgendwie in der LVN_GETDISPINFO? Ich braeuchte den Parameter naemlich dringen.
Ich habe ein abgeleitetes ListCtrl das mir anhand von GetItemData() die Hintergrundfarbe setzt.
Diese Klasse moechte ich ungern nochmal grossartig veraendern.Ich dachte mir jetzt, dass ich mit
if(pItem->mask & LVIF_TEXT) { ConfP* pEl; csConf.Lock(); pEl=conf.getItem(pItem->iItem); csConf.Unlock(); if (pE!=NULL) { pDispInfo->item.lParam=43; pItem->mask=pItem->mask | LVIF_PARAM;
eben diesen LVITEM Parameter auf 43
setzen kann. Ich bekomme aber beim auslesen mit GetItemData(iRow) immer 0.
Gibts da irgendwelche Vorschlaege?
Oder muss ich wirklich nochmal alle mit SetItemData "ausserhalb" von GETDISPINFO setzen was ziemlich bloed waere.
vielen Dank
t2x