ListCtrl Zeile für Zeile füllen


  • Mod

    Warum gehst Du nicht einfach Schrittweise vor um Dir Infos zu beschaffen? 👎

    1. Du hast CListCtrl Control (findet man sofort über die Google Suche "msdn CListCtrl")
    http://msdn.microsoft.com/en-us/library/hfshke78(VS.80).aspx
    2. Du möchtest etwas damit tun. Also schaust Du Dir die Member Functions an. (Link ganz unten)
    http://msdn.microsoft.com/en-us/library/zdff988k(VS.80).aspx
    3. In dem Du Dir die Operationen (Operations) durchliest wird Dir InsertItem ins Gesicht hüpfen:
    InsertItem Inserts a new item in a list view control.
    http://msdn.microsoft.com/en-us/library/8b9s12fc(VS.80).aspx

    Solch eine Frage wird nicht mal durch auf den Schlauch stehen oder Smileys entschuldigt.



  • Die beiden Methoden, die du benötigst lauten: InsertItem und SetItemText. Wenn du von Anfang an weisst wie viele Einträge es werden, dann steht die korrekte Position ja fest - wenn nicht musst du die Zeilen bei jedem neuen Wert per SetItemText runterziehen.

    Eine zweite Möglichkeit wäre mit SortItems zu arbeiten: chronologisches Sortieren.



  • Ok, erstmal danke für die Tipps !

    Ich hab ja schon die Funktion fertig, dass ich die Werte in der ersten Zeile einfügen kann, nur hab ich noch überlegt (und deswegen gefragt), was man tun kann, um das ListCtrl Zeile für Zeile füllen zu können, weil bis jetzt meine Werte immer in der ersten Zeile eingefügt werden bzw. überschrieben werden.

    Hätte mehr Infos geben sollen...



  • Unix-Tom schrieb:

    Einfach an Position 1 einfügen. Dann geht es.
    SChau dir mal die Member davon an.
    Da findest Du etwas.

    Hab das mal so probiert, funktioniert nicht. Das verstehe ich noch nicht ganz.

    Ich zeig endlich mal etwas Code:

    void C...View::FillListCtrl()
    {
    	m_tool.SetRedraw(FALSE);
    	CString data;
    	CTime ct = CTime::GetCurrentTime();
    
    	int counter = 0;
    	data.Format("%02d:%02d:%02d", ct.GetHour(), ct.GetMinute(), ct.GetSecond());
    	m_tool.SetItemText(counter, 0, "test1");
    	m_tool.SetItemText(counter, 1, "test2");
    	...
            m_tool.SetRedraw(TRUE);
    }
    

    Und diese Funktion wird in OnInitialUpdate des Views aufgerufen:

    void C...View::InitListCtrl()
    {
    	CRect rectListCtrl;
    	m_tool.EnableToolTips(TRUE);
    	m_tool.SetRedraw(FALSE);
    	m_tool.GetClientRect(&rectListCtrl);
    
    	m_tool.InsertColumn(0, "0", LVCFMT_LEFT, 70);
    	m_tool.InsertColumn(1, "1", LVCFMT_LEFT, 60);
    	m_tool.InsertColumn(2, "2", LVCFMT_LEFT, 60);
    	m_tool.InsertColumn(3, "3", LVCFMT_LEFT, 60);
    	m_tool.InsertColumn(4, "4", LVCFMT_LEFT, 75);
    	m_tool.InsertColumn(5, "5", LVCFMT_LEFT, 85);
    	m_tool.InsertColumn(6, "6", LVCFMT_LEFT, 70);
    	m_tool.InsertColumn(7, "7", LVCFMT_LEFT, 80);
    	m_tool.InsertColumn(8, "8", LVCFMT_LEFT, 70);
    	m_tool.InsertColumn(9, "9", LVCFMT_LEFT, 80);
    	m_tool.InsertColumn(10, "10", LVCFMT_LEFT, 70);
    	m_tool.InsertColumn(11, "11", LVCFMT_LEFT, 70);
    	m_tool.InsertColumn(12, "12", LVCFMT_LEFT, 60);
    
    	LVITEM lvItem;
    	lvItem.mask = LVIF_TEXT;
    	lvItem.iItem = 0; lvItem.iSubItem = 0;
    	lvItem.pszText = "";
    	m_tool.InsertItem(&lvItem);
    	for (int i = 1; i <= 12; i++)
    	{
    		lvItem.mask = LVIF_TEXT;
    		lvItem.iItem = 0; lvItem.iSubItem = i;
    		m_tool.InsertItem(&lvItem);
    	}
    	m_tool.SetRedraw(TRUE);
    	m_tool.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
    }
    

    Wenn counter beim 1. Aufruf 0 ist, dann 1, ... sollten die Werte ja in der nächsten Zeile eingefügt werden oder ?? (was aber auch nicht der Fall ist)
    Ist zwar noch nicht das Ziel, aber erstmal ok für den Anfang.

    Und fest steht, das ich 13 Spalten habe, und Zeilen sollen max. 12 angezeigt werden, aber das ist jetzt unwichtig.



  • Gut, mit dem Zeile für Zeile füllen hat sich geklärt, sieht jetzt so aus:

    void C...View::FillListCtrl()
    {
    	m_tool.SetRedraw(FALSE);
    	CString data;
    	CTime ct = CTime::GetCurrentTime();
    
    	LVITEM lvItem;
    	lvItem.mask = LVIF_TEXT;
    	lvItem.iItem = 0; lvItem.iSubItem = 0;
    	lvItem.pszText = "";
    	m_tool.InsertItem(&lvItem);
    	for (int i = 0; i < 13; i++)
    	{
    		lvItem.iItem = m_tool.GetItemCount(); lvItem.iSubItem = i;
    		m_tool.InsertItem(&lvItem);
    	}
    	m_tool.SetItemText(0, 0, "test1");
    	m_tool.SetItemText(0, 1, "test2");
            ...
    }
    

    und die Initialisierung:

    void C...View::InitListCtrl()
    {
        CRect rectListCtrl;
        m_tool.EnableToolTips(TRUE);
        m_tool.SetRedraw(FALSE);
        m_tool.GetClientRect(&rectListCtrl);
    
        m_tool.InsertColumn(0, "0", LVCFMT_LEFT, 70);
        m_tool.InsertColumn(1, "1", LVCFMT_LEFT, 60);
        ...
    
        m_tool.SetRedraw(TRUE);
        m_tool.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
    }
    

    Hab ich halt nur noch das Problem, die "aktuellste" Zeile am Anfang stehen zu haben, aber werde es jetzt mal mit SortItems probieren. 👍


  • Mod

    Dann setze 0 als Einfügeposition und dann steht es oben:

    lvItem.iItem = 0;
    m_tool.InsertItem(&lvItem);
    


  • Ok, stimmt, und passt !
    Danke euch !!

    Und entschuldige mich für den Ärger mit mir ! 😉



  • Es muss mich nochmal melden: Ich habe jetzt das Flicker-Problem mit meinem ListCtrl.
    Ich aktualisiere mein Control auch immer nur dann, wenn ich in jeder Spalte per SetItemText den Inhalt festgelegt habe.

    Hab jetzt schon einige Seiten und Lösungen durchgelesen, aber bin auch nur etwas schlauer geworden und es stand auch auf einigen Seiten, dass man SetRedraw(FALSE) und SetRedraw(TRUE) aufrufen soll, was ich ja tue, aber es ändert sich trotzdem nix.

    Das soll also heißen, ich muss meine Items, das "allgemeine" Layout usw. meines ListCtrl selber zeichnen ? So ist es dort erkennbar: http://www.codeproject.com/KB/GDI-plus/what_is_a_basename_.aspx. Habe auch wie es dort beschrieben ist, WM_PAINT... hinzugefügt und muss mich jetzt noch um OnPaint() kümmern.

    Nur hab ich keine Anhung wie ich da anfangen soll, hab nix weiter mit DC... gemacht !


  • Mod

    Das CListCtrl ist optimiert. Du musst gar nichts aktualisieren. Invalidate bzw. InvalidateRect ist bei einem CListCtrl unnötig genauso wie SetRedraw etc.



  • Ich weiß nicht, aber ich hab mal SetRedraw ... entfernt, aber das Flickern ist nach wie vor da !

    EDIT:
    hab auch grad gemerkt, dass manche Linien des LVS_GRIDLINES-Style nicht gezeichnet werden, wenn man in der Liste z.B. runterscrollt
    habe dazu WM_VSCROLL hinzugefügt und dort den LVS_GRIDLINES-Style nochmal gesetzt, aber das bringt auch nix



  • Martin Richter schrieb:

    Das CListCtrl ist optimiert. Du musst gar nichts aktualisieren. Invalidate bzw. InvalidateRect ist bei einem CListCtrl unnötig genauso wie SetRedraw etc.

    Das sehe ich etwas anders. Beim Hinzufügen von mehreren Einträgen nacheinander hilft ein SetRedraw schon sehr, den Vorgang zu beschleunigen. Es verhindert, dass die Listenansicht nach jedem InsertItem interne Positionen und den Scrollbereich neu berechnet.

    Gegen das Trennlinien-Problem hilft folgendes:

    // WM_HSCROLL
    //
    //	-> Horizontales Scrollen
    void CMfxListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
    {
    	// Standardverarbeitung
    	CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
    
    	// Scrollen beendet
    	//	-> Aktualisierung (Tut not, wenn bei eingeschalteten Trennlinien per Rad gescrollt wird)
    	if (SB_ENDSCROLL == nSBCode && GetExtendedStyle() & LVS_EX_GRIDLINES)
    	{
    		RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
    	}
    }
    
    // WM_HSCROLL
    //
    //	-> Vertikales Scrollen
    void CMfxListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
    {
    	// Standardverarbeitung
    	CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
    
    	// Scrollen beendet
    	//	-> Aktualisierung (Tut not, wenn bei eingeschalteten Trennlinien per Rad gescrollt wird)
    	if (SB_ENDSCROLL == nSBCode && GetExtendedStyle() & LVS_EX_GRIDLINES)
    	{
    		RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
    	}
    }
    


  • @sri:
    Ok, also ich hab den Code mal probiert, aber so wirklich hilft das nicht, die Probleme mit den Linien ist nach wie vor da, egal ob ich den Scrollbalken runterziehe oder per Mausrad scrolle.

    Und das Flickern ist natürlich auch nach wie vor da, ne Lösung hab ich auch noch nicht gefunden !

    Und als 3. Problem hab ich noch: ich muss noch einen Ansatz finden, wie ich "neue" Daten im ListCtrl auch gleich noch in ein Logfile schreiben kann, gibts vllt ne Funktion, die aufgerufen wird, wenn der Inhalt eines ListCtrls geändert wird ?? Vllt LVN_ITEMCHANGED ? 😕
    D.h. ich fülle meine Liste und will gleich danach immer die Funktion zum Schreiben ins Logfile aufrufen, muss aber irgendwas haben, dass diese ListTextToLog-Funktion erst aufruft, wenn neue Daten in der Liste stehen !
    Das Schreiben ins Logfile funktioniert, nur eben noch nicht, wie ich mir das vorstelle.

    Konnte bis jetzt diese 3 Dinge noch nicht lösen ! 😞
    Evtl kann jemand noch was dazu sagen ??



  • Die Einträge in der MessageMap für ON_WM_VSCROLL/ON_WM_HSCROLL hast Du auch gesetzt?

    Zu Problem 3: Einfach eine Wrapperfunktion schreiben, die die Einträge in die Liste einfügt und gleichzeitig ins Logfile schreibt. LVN_ITEMCHANGED ist nur für die Änderung von Stilen (Fokussierung, Auswahl) gedacht.



  • Erdtmal danke für deine Antwort.
    Ok, gut, werde das so angehen mit der Wrapperfunktion.

    Ja, das mit den Funktionen passt, sind ja mit Assistent eingefügt (aber man weiß ja nie 🙂 )
    Und die Funktionsprototypen sind:

    void CToolTip::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    

    und

    void CToolTip::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    

    und die Message Map sieht so aus:

    BEGIN_MESSAGE_MAP(CToolTip, CListCtrl)
    	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
    	ON_WM_HSCROLL()
    	ON_WM_VSCROLL()
    END_MESSAGE_MAP()
    

    und die Funktionen werden auch aufgerufen (Breakpoint springt an!)
    Trotzdem ist dieser Fehler mit den Linien nach wie vor da, verstehe das nicht.



  • Warum nennst Du das ListCtrl CToolTip?



  • Ist ne Klasse die ich von Codeproject geladen hab und etwas verändert habe.

    Ich will in meinem ListCtrl nur in einer bestimmten Spalte ein Tooltip anzeigen lassen und hab dafür die Klasse gebraucht und auch verstanden.
    Die Klasse ist von CListCtrl abgeleitet.

    Kanns heut nicht mehr probieren, aber werde morgen mal testen, was passiert, wenn ich ohne die Klasse arbeite.

    Meld mich morgen wieder. Schönen Abend noch !



  • Hey, also ich muss mich nochmal zu dem Thema melden.
    Das Flickern ist nach wie vor, habs bis jetzt nicht hinbekommen. 👎

    Ich habe eine Wrapperfunktion, die anspringt, wenn mein Thread mir per Sendmessage mitteilt, dass neue Daten vorliegen und mir die auch gleich als LPARAM übergibt. SetRedraw wird auf false gesetzt, die ganzen 14 Spalten werden gefüllt, für 2 Spalten werden die Tooltips gesetzt und dann rufe ich wieder SetRedraw(TRUE) auf.
    Kann das Flickern natürlich verringern, wenn ich nach dem Sendmessage im Thread ein längeres Sleep einbaue, aber vollkommen verschwunden ist es da noch nicht, und ich will den User nicht unbedingt länger als 800ms warten lassen.

    Beim Scrollen ist das Flickern auch da. 😞

    Vllt hat jemand mal noch paar Tipps, komme hier einfach nicht weiter.



  • Ruf mal nach dem SetRedraw(TRUE) ein UpdateWindow() auf.



  • So wirklich hat das nix gebracht. 😞

    Krieg das irgendwie nicht hin.

    Hab selber auch keine Idee mehr.



  • Aus der Ferne ohne Code ist es leider nicht ganz so einfach, die richtigen Hinweise zu geben. Den erweiterten LVS_EX_DOUBLEBUFFER-Stil hast Du schon gesetzt?


Anmelden zum Antworten