3 Stimmen

ImageList-Transparenz bei Listenansichten?

EDITAR: Ich habe ein Kopfgeld ausgesetzt, da ich sonst wohl keine Antworten bekomme.

In letzter Zeit habe ich mit Listenansichten gearbeitet und beschlossen, eine Symbol für jedes Element, das angibt, ob es eine Eingabe oder eine Ausgabe ist. Die Symbole fügen sich gut ein, aber sie sind nicht transparent:

Example of icon not being transparent

Wie man sieht, sind die Icons eindeutig nicht transparent. Ich bin derzeit so etwas tun, laden Sie die Symbole:

  hImageList = ImageList_Create(16, 16, ILC_MASK | ILC_COLOR32, 2, 2);
  if (hImageList != NULL)
  {
    iIN  = ImageList_AddIcon(hImageList, LoadIcon(hInstance, MAKEINTRESOURCE(101)));
    iOUT = ImageList_AddIcon(hImageList, LoadIcon(hInstance, MAKEINTRESOURCE(102)));
  }

Ich habe versucht, mit den Flags für ImageList_Create & LoadIcon / LoadImage aber ich hatte kein Glück, und um ehrlich zu sein, sind mir die Ideen ausgegangen.

Für jede Hilfe wären wir Ihnen sehr dankbar.

0 Stimmen

Haben Sie Ihre Quelle irgendwo zur Verfügung, damit wir damit herumspielen können? Ich sehe einige Kommentare, in denen Leute Ihren Code testen. Ich würde gerne einen Blick darauf werfen, da ich eine Menge Arbeit in diesem Bereich gemacht habe...

0 Stimmen

Bitte lesen Sie meine Antwort (Antwort 2) für stackoverflow.com/questions/6893351/ Thema. Olexiy

13voto

Chris Becke Punkte 32199

Zunächst einmal kopiert ImageList_ReplaceIcon die Icon-Daten, wenn es zu einer Bildliste hinzugefügt wird. Daher muss das HICON anschließend wieder freigegeben werden.

Außerdem handelt es sich bei den Bildlisten von Natur aus um Bitmaps und nicht um Symbole. Und die Art und Weise, wie Sie Ihre Imageliste erstellen, macht die Konvertierung von Icon zu Bitmap sehr zweideutig. ILC_COLOR32 impliziert, dass die Imageliste als 32-Bit-Dib-Abschnitt erstellt werden sollte, der normalerweise Transparenzinformationen über einen eingebetteten Alphakanal enthält. ILC_MASK bedeutet stattdessen, dass die internen Bitmaps DDB-Bitmaps sind, wobei die Transparenzinformationen als 1bpp-Maskenbitmap gespeichert werden.

Die schnellste Lösung für Ihr Problem - nehmen Sie Ihre beiden Icons:

  • Fügen Sie sie zu einer einzigen Bitmap-Ressource zusammen, die 32 Pixel breit und 16 Pixel hoch ist. Füllen Sie den Hintergrund mit einer Maske Farbe :- lila oder etwas.
  • Erstellen Sie die Bitmap mit ILC_COLOR|ILC_MASK
  • Laden Sie die Bitmap und achten Sie darauf, dass Sie NICHT LR_TRANSPARENT verwenden.
  • Fügen Sie die Bitmap mit ImageList_AddMasked hinzu und übergeben Sie eine COLORREF, die die Maskenfarbe darstellt.

ODER, für einen besseren visuellen Effekt...

  • exportieren Sie Ihre PNG-Daten als 32x16 32bpp-Bitmap-Datei mit vormultiplizierten Alphakanaldaten.
  • Erstellen Sie die Imageliste mit dem Wert ILC_COLOR32.
  • LoadImage() mit LR_CREATEDIBSECTION, um die Bitmap als 32bpp dib-Abschnitt zu laden.
  • Hinzufügen des Bildes mit ImageList_Add()

(die letzte Option ist etwas schwierig, da die Anzahl der Tools, die 32-Bit-Bmp-Dateien mit korrekt vormultiplizierten Alphakanälen ausgeben können, eher gering ist).


Bearbeitet, um das folgende Codebeispiel hinzuzufügen. Mit einem 4bpp Bitmap in der Entwicklungsumgebung erstellt dies funktioniert einfach großartig :-

HWND hwndCtl = CreateWindowEx(0,WC_LISTVIEW,TEXT("ListView1"),WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL,0,0,cx,cy,hWnd,(HMENU)101,hModule,NULL);
HBITMAP hbm = (HBITMAP)LoadImage(hModule,MAKEINTRESOURCE(IDB_BITMAP1),IMAGE_BITMAP,0,0,0);
COLORREF crMask=RGB(255,0,255);
HIMAGELIST himl = ImageList_Create(16,16,ILC_COLOR|ILC_MASK,2,0);
ImageList_AddMasked(himl,hbm,crMask);
ListView_SetImageList(hwndCtl,himl,LVSIL_NORMAL);

0 Stimmen

Ich habe heute die erste Option ausprobiert und hatte das gleiche Problem. Nachdem ich Ihren Beitrag gelesen habe, habe ich die zweite Möglichkeit ausprobiert, und es machte absolut keinen Unterschied. Bitte sehen Sie sich das an: pastebin.com/f5617ac8a

0 Stimmen

Wenn Sie ILC_MASK|ILC_COLOR angeben, wie laden Sie die Bitmap? Sie sollten wahrscheinlich das DIBSECTION-Flag weglassen und sich auch darüber im Klaren sein, dass das Laden von Bitmaps auf DDB-Oberflächen verlustbehaftet ist, so dass ein COLORREF, der die idealen RGB-Werte in der Datei beschreibt, nicht mit den Pels in der DDB übereinstimmen kann. Verwenden Sie reine Farben.

0 Stimmen

...Sie haben es völlig versäumt, sich zur zweiten Option zu äußern. Außerdem habe ich das LR_CREATEDIBSECTION-Flag für die erste Option weggelassen. Meine Maskenfarbe war rosa (RGB(255, 0, 255)), so dass es keine Übereinstimmungen gegeben hätte.

0voto

i_am_jorf Punkte 52346

Sie möchten, dass Ihre Icons eine Hintergrundfarbe haben, die nirgendwo sonst im Icon verwendet wird, wie z.B. ein wirklich hässliches Lila, und dann verwenden Sie LoadImage(..., LR_LOADTRANSPARENT); Das Flag sagt, schauen Sie sich das erste Pixel bei 0,0 an und machen Sie alles in dieser Farbe transparent.

1 Stimmen

Ich habe dies bereits versucht (mit dem ersten Pixel als RGB(255, 0, 255)) und zitiere die Dokumentation: LR_LOADTRANSPARENT lädt das Bild nicht transparent. Es erzeugt eine undurchsichtige Bildliste, die nur deshalb transparent erscheint, weil alle Hintergrundpixel auf COLOR_WINDOW geändert wurden.

0 Stimmen

Ah ja, das macht Sinn. Blöde Windows und transparente Icons.

0voto

Murray Punkte 680

Ihr Code sieht für mich gut aus. Ich verwende immer LoadImage statt LoadIcon, aber ich vermute, das spielt keine Rolle. Haben Sie überprüft, dass die Icons tatsächlich transparente Bereiche haben und nicht selbst einen festen Hintergrund haben?

Meine LoadImage-Aufrufe sehen wie folgt aus:

HICON hIcon = (HICON)LoadImage(hinstResources,MAKEINTRESOURCE(IDI_ICON),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);

0 Stimmen

Wie in meinem ursprünglichen Beitrag erwähnt, habe ich bereits mit LoadIcon & LoadImage herumprobiert. Ich habe auch versucht, nur das LR_DEFAULTCOLOR-Flag allein zu verwenden, und es machte keinen Unterschied. Oh, und ja, meine Icons sind transparent: img12.imageshack.us/img12/6117/reseditxpirc776.png

0voto

LarryF Punkte 4745

Hier... Erstellen Sie eine ImageList, wie vorgeschlagen, machen Sie Ihre Icons in ein Bitmap, 16 Pixel hoch, mal 16*n lang, wobei n= die Anzahl der Icons...

Setzen Sie die Hintergrundfarbe auf 255, 0, 255, wie Sie es getan haben.

Laden Sie es dann, und fügen Sie es der Bilderliste hinzu, wie ich es hier getan habe:

 m_ImageList.Create(16, 16, ILC_COLOR16 | ILC_MASK, 7, 1);
 CBitmap bm;
 bm.LoadBitmap(IDB_SUPERTREEICONS);
 m_ImageList.Add(&bm, RGB(255, 0, 255));
 GetTreeCtrl().SetImageList(&m_ImageList, TVSIL_NORMAL);

Natürlich wurde dies in MFC geschrieben, aber wie Sie wissen, ist es nur ein Wrapper für Win32...

Andernfalls müssen Sie ein benutzerdefiniertes Steuerelement zum Zeichnen verwenden, mit dem Sie das Symbol über einen beliebigen Hintergrund zeichnen, auf dem das Symbol gerade sitzt. Es gibt nicht wirklich eine magische "transparente" Farbe, die ich kenne, in einem dieser Steuerelemente.

Im Falle einer benutzerdefinierten Auslosung müssen Sie einen Code wie den folgenden verwenden:

#define TRANSPARENT_COLOR (255,0,255)

UINT iBitmap = IDB_ICON_UP
CDC *dc = GetDC();
int x = 0, y = 0;

    CDC *pDisplayMemDC = new CDC;
    CDC *pMaskDC = new CDC;
    CDC *pMemDC = new CDC;
    CBitmap *pBitmap = new CBitmap;
    CBitmap *pMaskBitmap = new CBitmap;
    CBitmap *pMemBitmap = new CBitmap;
    int cxLogo, cyLogo;
    BITMAP bm;

    pBitmap->LoadBitmap(iBitmap);
    pDisplayMemDC->CreateCompatibleDC(dc);
    CBitmap *pOldBitmap = (CBitmap *)pDisplayMemDC->SelectObject(pBitmap);

    pBitmap->GetObject(sizeof(bm), &bm);
    cxLogo = bm.bmWidth;
    cyLogo = bm.bmHeight;

    pMaskBitmap->CreateBitmap(cxLogo, cyLogo, 1, 1, NULL);
    pMaskDC->CreateCompatibleDC(dc);
    CBitmap *pOldMask = (CBitmap *)pMaskDC->SelectObject(pMaskBitmap);
    COLORREF oldBkColor = pDisplayMemDC->SetBkColor(TRANSPARENT_COLOR);
    pMaskDC->BitBlt(0, 0, cxLogo, cyLogo, pDisplayMemDC, 0, 0, SRCCOPY);

    pMemBitmap->CreateCompatibleBitmap(dc, cxLogo, cyLogo);
    pMemDC->CreateCompatibleDC(dc);
    CBitmap *pOldMem = (CBitmap *)pMemDC->SelectObject(pMemBitmap);

    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, dc,            x, y, SRCCOPY);
    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, pDisplayMemDC, 0, 0, SRCINVERT);
    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, pMaskDC,       0, 0, SRCAND);
    pMemDC->BitBlt(0, 0, cxLogo, cyLogo, pDisplayMemDC, 0, 0, SRCINVERT);
        dc->BitBlt(x, y, cxLogo, cyLogo, pMemDC,        0, 0, SRCCOPY);

    delete pMemDC->SelectObject(pOldMem);
    delete pMemDC;

    delete pMaskDC->SelectObject(pOldMask);
    delete pMaskDC;

    delete pDisplayMemDC->SelectObject(pOldBitmap);
    delete pDisplayMemDC;

Dieser Code entscheidet, wo das Symbol gezeichnet werden soll, und macht einen Schnappschuss des Hintergrunds, erstellt eine Maske für das Symbol und zeichnet es dann über den Hintergrund, wodurch es einen vollständig transparenten Hintergrund erhält...

Ich hoffe, das hilft ein wenig. Wenn nicht, erklären Sie bitte genauer, was Sie versuchen zu erreichen, und was Sie sehen, oder was Sie NICHT sehen...

0voto

vishayp Punkte 13

Ich kämpfte mit dem gleichen Problem mit einer ImageList in einer Strukturansicht. Schließlich gelang es mir, die zweite Lösung von Chris Becke zum Laufen zu bringen, indem ich eine ImageList mit dem Flag ILC_COLOR32 erstellte und LoadImage() mit dem Flag LR_CREATEDIBSECTION verwendete. Diese Lösung, und wahrscheinlich auch die erste Lösung, erfordert, was unten beschrieben wird.

Transparenz (und Themen) werden nur mit comctl32.dll Version 6+ unterstützt, um die richtige Version zu verwenden, hat die Präprozessoranweisung auf dieser Seite bei mir funktioniert: https://docs.microsoft.com/en-us/Windows/win32/controls/cookbook-overview

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X