MFC Listelement mit Image

Dieses Thema MFC Listelement mit Image im Forum "Webentwicklung, Hosting & Programmierung" wurde erstellt von Don_Pazo, 21. Feb. 2006.

Thema: MFC Listelement mit Image Hallo, ich habe ein Dialog mit einem Listelement. Ich möchte so was ereichen: -------------------------------------...

  1. Hallo,
    ich habe ein Dialog mit einem Listelement. Ich möchte so was ereichen:

    Code:
    -------------------------------------
    Name  | Status   | Status   | Status 
    -------------------------------------
    Anna  |    G         |   GL       |    R     
    Mila    |    G         |   G         |    G     
    --------------------------------------
    Jeweils sind:
    G = Grün;   GL = Gelb;  R = Rot;
    Die Fargen habe ich als *.ico Dateien und sind auch in VC als IDR_GRUEN,
    IDR_GELB, IDR_ROT importiert.

    in On INITDIALOG habe ich:

    Code:
    HICON  hIcon = NULL;
    
    // Create image list
    m_ImageList.Create(16, 16, NULL, 3, 1);
    
    // Add some icons
    hIcon = AfxGetApp()->LoadIcon(IDR_GRUEN);
    m_ImageList.Add(hIcon);
    
    hIcon = AfxGetApp()->LoadIcon(IDR_GELB);
    m_ImageList.Add(hIcon);
    
    hIcon = AfxGetApp()->LoadIcon(IDR_ROT);
    m_ImageList.Add(hIcon);
    
    m_List1.SetImageList(&m_ImageList,LVSIL_NORMAL); // von CListBox
    
        m_List1.InsertColumn(0, Name ,LVCFMT_LEFT, 100);
        m_List1.InsertColumn(1, Status  ,LVCFMT_LEFT, 70);
        
        // Elemente einfügen
        m_List1.InsertItem(0, Anna);
         
      // HIER WILL ICH DIE ICONEN INCLUDEN
    Meinem Problemm ist, ich weiss es nicht wie ich die Image´s in der Listelement schreiben kann. Könnte mir bitte jemand helfen ??
     
  2. Du könntest den erweiterten Stil LVS_EX_SUBITEMIMAGES setzen (s.u.).

    Die Icons sind ja in Deinem Fall 16x16 Pixel groß; Du solltest dann auch LVSIL_SMALL statt LVSIL_NORMAL benutzen:

    m_List1.SetImageList(&m_ImageList, LVSIL_SMALL);

    Mit->InsertItem' und->SetItem' kannst Du die Zeilen bzw. Sub-Icons einfügen:

    int idx= m_List1.InsertItem(0, _T(Anna), -1); // oder leeres Icon verwenden

    // 2 ist hier der Index des Icons in der Image-Liste, 1 die Spalte, die geändert werden soll
    m_List1.SetItem(idx, 1, LVIF_IMAGE, NULL, 2, 0, 0, 0);

    Die Sache hat aber zwei Haken:
    Es gibt immer eine größere Lücke (Iconbreite + Default-Abstand Icon<->Label) zwischen dem linken Rand des ListControls und dem Text der ersten Spalte, auch wenn kein Icon verwendet wird. Außerdem wird der Selektionsbalken nicht bis zum Rand des gezeichnet, was besonders hässlich ist. Das kann man sicher lösen, aber Problem 2 nicht ohne weiteres:
    Microsoft hat offenbar vergessen, dass man bei der Verwendung des Stils->LVS_EX_SUBITEMIMAGES' vielleicht auch Icons in den Spalten zentrieren möchte. Das geht offenbar nicht ...

    Dann bleiben Dir noch zwei Möglichkeiten: Owner Draw und Custom Draw. Ich würde hier Custom Draw verwenden.

    Ein mögliches Gerüst:

    -----
    In die Message-Map des Listenbesitzers (z.B. Dialog)

    ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST1, OnCustomdrawList1)

    einfügen und in den Header

    void DrawListCtrlItem(const CListCtrl& list, const LVITEM& item, CDC& pDC);
    afx_msg void OnCustomdrawList1(NMHDR* pNMHDR, LRESULT* pResult);
    -----

    oder

    -----
    von CListCtrl ableiten und

    ON_NOTIFY_REFLECT (NM_CUSTOMDRAW, OnCustomDraw)

    in die Message-Map dieser Klasse einfügen sowie in den entsprechenden Header

    void DrawListCtrlItem(const CListCtrl& list, const LVITEM& item, CDC& pDC);
    afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
    -----

    Ich habe hier der Einfachheit halber die erste Variante gewählt. Du kannst alles in die Funktion OnCustomdrawList1 bzw. OnCustomDraw schreiben, aber ich denke, es ist wie folgt etwas übersichtlicher.

    Code:
    // Image-List erzeugen
    VERIFY(m_ImageList.Create(16, 16, ILC_MASK, 3, 1));
    
    // Icons hinzufügen
    ...
    
    // List-Control initialisieren
    m_List1.SetImageList(&m_ImageList, LVSIL_SMALL);
    
    // Erweiterten Stil setzen (LVS_EX_GRIDLINES ist natürlich optional)
    DWORD oldExStyle= m_List1.GetExtendedStyle();
    m_List1.SetExtendedStyle(oldExStyle | LVS_EX_SUBITEMIMAGES | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
    	
    m_List1.InsertColumn(0, _T(Name), LVCFMT_LEFT, 100);
    m_List1.InsertColumn(1, _T(Status A), LVCFMT_CENTER, 70);
    m_List1.InsertColumn(2, _T(Status B), LVCFMT_CENTER, 70);
    m_List1.InsertColumn(3, _T(Status C), LVCFMT_CENTER, 70);
    
    
    Code:
    // Zeilen hinzufügen
    
    // Der Icon-Index für die erste Spalte spielt keine Rolle, da wir sowieso selbst zeichnen (ohne Icon)
    int idx= m_List1.InsertItem(0, _T(Anna), -1);
    // In den weiteren Spalten (1, 2, 3) nur Icons zeichnen; Text= NULL, danach der Icon-Index
    m_List1.SetItem(idx, 1, LVIF_IMAGE, NULL, 0, 0, 0, 0);
    m_List1.SetItem(idx, 2, LVIF_IMAGE, NULL, 0, 0, 0, 0);
    m_List1.SetItem(idx, 3, LVIF_IMAGE, NULL, 2, 0, 0, 0);
    
    idx= m_List1.InsertItem(1, _T(Frank), -1);
    m_List1.SetItem(idx, 1, LVIF_IMAGE, NULL, 0, 0, 0, 0);
    m_List1.SetItem(idx, 2, LVIF_IMAGE, NULL, 1, 0, 0, 0);
    m_List1.SetItem(idx, 3, LVIF_IMAGE, NULL, 1, 0, 0, 0);
    
    // Per SetItem kannst Du auch später die Icons ändern, wenn der Status wechselt.
    
    Code:
    void TestDialog::DrawListCtrlItem(CListCtrl& list, LVITEM& item, CDC& pDC)
    {
      const int halfIconWidth = 8;
      CRect drawArea;
    
      list.GetSubItemRect(item.iItem, item.iSubItem, LVIR_BOUNDS, drawArea);
    
      // Hintergrund zeichnen
      if (item.state & LVIS_SELECTED)
        pDC.FillSolidRect(drawArea, GetSysColor(COLOR_HIGHLIGHT));
      else
        pDC.FillSolidRect(drawArea, GetSysColor(COLOR_WINDOW));
        
      if(item.iSubItem == 0) {
        // In der ersten Spalte nur Text darstellen
        
        pDC.SetBkMode(TRANSPARENT);
        
        // Text nicht ganz an den linken Rand drücken
        drawArea.left += 4;
    
        if(item.state & LVIS_SELECTED)
          pDC.SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
        else
          pDC.SetTextColor(GetSysColor(COLOR_BTNTEXT));
    
        CString text = list.GetItemText(item.iItem, 0);
          
        pDC.DrawText(text, drawArea, DT_VCENTER | DT_SINGLELINE );
      } else {
    
        // Spalten > 0: Icon zentriert zeichnen
        drawArea.left= drawArea.left + (drawArea.Width() / 2 - halfIconWidth);
        m_ImageList.Draw(&pDC, item.iImage, drawArea.TopLeft(), ILD_TRANSPARENT);
      }
    }
    
    void TestDialog::OnCustomdrawList1(NMHDR* pNMHDR, LRESULT* pResult)
    {  
    
      NMLVCUSTOMDRAW* pCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
    
      *pResult = 0;
    
      if (pCD->nmcd.dwDrawStage == CDDS_PREPAINT)
        *pResult = CDRF_NOTIFYITEMDRAW;
      else if (CDDS_ITEMPREPAINT == pCD->nmcd.dwDrawStage)
        *pResult = CDRF_NOTIFYSUBITEMDRAW;
      else if (pCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM))
      {
        LVITEM item;
        int nItem = static_cast<int>(pCD->nmcd.dwItemSpec);
    
        ZeroMemory(&item, sizeof(LVITEM));
        item.iItem = nItem;
        item.iSubItem = pCD->iSubItem;
        item.mask = LVIF_IMAGE | LVIF_STATE;        
        item.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
    
        m_List1.GetItem(&item);
    
        CDC* pDC = CDC::FromHandle(pCD->nmcd.hdc);
    
        DrawListCtrlItem(m_List1, item, *pDC);
    
        *pResult = CDRF_SKIPDEFAULT;
      }    
    }
    
    Wenn Du die andere Variante wählst (von CListCtrl ableiten), sind die beiden Funktionen natürlich dort (DeinListCtrl::DrawListCtrlItem, DeinListCtrl::OnCustomDraw).
    Für den Icon-Hintergrund kannst Du die transparente Farbe im Visual Studio Icon-Editor verwenden (das ist die, die grünlich dargestellt wird).

    [​IMG]

    [​IMG]

    Normalerweise würde ich die Parameter von DrawListCtrlItem (bzw. dann die ganze Methode) const machen, aber da MS überall rumgeschlampt hat, müsste man mehrmals casten:
    const_cast<CListCtrl&>(list).GetSubItemRect(item.iItem, item.iSubItem, LVIR_BOUNDS, drawArea);
    was auch nicht so schön ist und hier im Beispiel eh keine Rolle spielt.
     
  3. Ich will mich bie dir herzlich bedanken.
    Ich habe gestern den ganzen Tag damit verbracht, dieses Problem zu lösen. Ich bin mir sicher, dass ich ohne deine Hilfe nicht veiter gekommen wäre.

    Danke schön.
     
  4. Hallo ich habe noch eine Frage zu diesem Beispiel.

    Wie kann ich eigentlich der Inhalt aus dem CListCtrl drucken.
    Den Text kann ich ausdrucken, aber mit der Icon´s kriege ich es nicht hin.


    Ich bitte um hilfe !!!
     
  5. Das hat ja nichts mit dem Code oben zu tun, sondern mit Deiner Druckroutine ...
     
  6. Ja, stimt.
    Ich meinte eigentlich ==>>>  http://www.wintotal-forum.de/index.php/topic,109499.0.html
     
Die Seite wird geladen...

MFC Listelement mit Image - Ähnliche Themen

Forum Datum
image einspielen Windows 7 Forum 1. Apr. 2016
Images der Windows UI Kacheln downloaden Windows 8 Forum 7. Jan. 2016
Acronis True Image 2015 Installationspfad ändern?? Software: Empfehlungen, Gesuche & Problemlösungen 13. Nov. 2015
Acronis True Image 2015 Installationspfad ändern?? Software: Empfehlungen, Gesuche & Problemlösungen 13. Nov. 2015
Systemwiederherstellung mit Windowsimagebackup Windows 8 Forum 21. Apr. 2015