Cześć.
Na wstępie wybaczcie rozpisanie się. Dodam, że trochę googlowałem i pokombinowałem samodzielnie, ale niewiele mi to dało :/ Sam raczej sobie nie poradzę.
Piszę w Newbie, bo pewnie ktoś podsunie mi rozwiązanie równie proste jak wcześniej @kAzek z przesywaniem ScrollBara. Poza tym ten dział czyta nemalże każdy :) Rozpocznę od tego, że interesują mnie kody WinAPI pod Delphi.
Skończyłem już jakiś czas temu przepisywać swój plugin dla Total Commandera na WinAPI. Jednak okazało się, że rysowanie poprzez WM_DRAWITEM
i/lub WM_PAINT
ikonek dla staticów powoduje kaszanienie się wyglądu i działania pluginu po załadowaniu przez podgląd z Ctrl+Q pod Total Commanderem po kolei kilkuset plików i krótkiego odtworzenia około sekundy modułów muzycznych. Dlatego z moich testów wynika, że kiedy ustawimy bitmapę dla kontrolki poprzez STM_SETIMAGE
sprawia, że plugin działa lepiej.
Button tworzę i ładuję grafikę, która jest plikiem *.ico - w taki sposób:
//...
const
GFX_BASE = 500;
Buttons_Icon_Size = 32;
var
PlayIconH : HICOn;
IconInfo : TIconInfo;
PlayBtnHandle : HWND;
PlayBtnHandle := CreateWindow('Static', '',
WS_CHILD or WS_VISIBLE or SS_NOTIFY or SS_BITMAP,
GetControlLeft(ModulePositionSBHandle),
GetControlTop(ModulePositionSBHandle) + GetControlHeight(ModulePositionSBHandle) + Controls_Vert_Distance,
Buttons_Icon_Size, Buttons_Icon_Size, ControlsGBHandle, IDC_PLAYBTN, HInstance, nil);
PlayIconH := LoadImage(HInstance, MAKEINTRESOURCE(GFX_BASE + (1 mod 100)), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
GetIconInfo(PlayIconH, IconInfo);
SendMessage(PlayBtnHandle, STM_SETIMAGE, IMAGE_BITMAP, IconInfo.hbmColor);
I teraz problem, ponieważ mam taką procedurę do rysowania przezroczystego jak poniżej i ona oczywiście działa. Ale chciałbym poznać kod, który pozowoli przekszałcić mi to co siedzi w IconInfo.hbmColor
na przezroczystą bitmapę. Ponieważ ten kod rysuje, a nie operuje na bitmapie. I nie mając dużego doświadczenia z grafiką i WinAPI, nie wiem jak go poprawić aby powodował że mogę albo ustawić przezroczysty kolor (tło w moim pluginie można zmieniać z czarnego na te z ustawień tła dla Listera z Total Commander, więc po zmianie, widać pod buttonem domyślne czarne tło).
procedure DrawTransparentBitmap(DC : HDC; HBmp : HBITMAP; XStart, YStart : integer; TransparentColor : COLORREF);
var
BM : BITMAP;
PtSize : TPOINT;
CColor : COLORREF;
HdcMem, HdcBack, HdcObject, HdcTemp, HdcSave : HDC;
BMAndBack, BMAndObject, BMAndMem, BMSave, BMBackOld, BMObjectOld, BMMemOld, BMSaveOld : HBITMAP;
begin
HdcTemp := CreateCompatibleDC(DC);
SelectObject(HdcTemp, HBmp);
GetObject(HBmp, SizeOf(BITMAP), @BM);
PtSize.X := BM.bmWidth;
PtSize.Y := BM.bmHeight;
DPToLP(HdcTemp, PtSize, 1);
HdcBack := CreateCompatibleDC(DC);
HdcObject := CreateCompatibleDC(DC);
HdcMem := CreateCompatibleDC(DC);
HdcSave := CreateCompatibleDC(DC);
BMAndBack := CreateBitmap(PtSize.X, PtSize.Y, 1, 1, nil);
BMAndObject := CreateBitmap(PtSize.X, PtSize.Y, 1, 1, nil);
BMAndMem := CreateCompatibleBitmap(DC, PtSize.X, PtSize.Y);
BMSave := CreateCompatibleBitmap(DC, PtSize.X, PtSize.Y);
BMBackOld := SelectObject(HdcBack, BMAndBack);
BMObjectOld := SelectObject(HdcObject, BMAndObject);
BMMemOld := SelectObject(HdcMem, BMAndMem);
BMSaveOld := SelectObject(HdcSave, BMSave);
SetMapMode(HdcTemp, GetMapMode(DC));
BitBlt(HdcSave, 0, 0, PtSize.X, PtSize.Y, HdcTemp, 0, 0, SRCCOPY);
CColor := SetBkColor(HdcTemp, TransparentColor);
BitBlt(HdcObject, 0, 0, PtSize.X, PtSize.Y, HdcTemp, 0, 0, SRCCOPY);
SetBkColor(HdcTemp, CColor);
BitBlt(HdcBack, 0, 0, PtSize.X, PtSize.Y, HdcObject, 0, 0, NOTSRCCOPY);
BitBlt(HdcMem, 0, 0, PtSize.X, PtSize.Y, DC, XStart, YStart, SRCCOPY);
BitBlt(HdcMem, 0, 0, PtSize.X, PtSize.Y, HdcObject, 0, 0, SRCAND);
BitBlt(HdcTemp, 0, 0, PtSize.X, PtSize.Y, HdcBack, 0, 0, SRCAND);
BitBlt(HdcMem, 0, 0, PtSize.x, PtSize.y, HdcTemp, 0, 0, SRCPAINT);
BitBlt(DC, XStart, YStart, PtSize.X, PtSize.Y, HdcMem, 0, 0, SRCCOPY);
BitBlt(HdcTemp, 0, 0, PtSize.X, PtSize.Y, HdcSave, 0, 0, SRCCOPY);
DeleteObject(SelectObject(HdcBack, BMBackOld));
DeleteObject(SelectObject(HdcObject, BMObjectOld));
DeleteObject(SelectObject(HdcMem, bMMemOld));
DeleteObject(SelectObject(HdcSave, BMSaveOld));
DeleteDC(HdcMem);
DeleteDC(HdcBack);
DeleteDC(HdcObject);
DeleteDC(HdcSave);
DeleteDC(HdcTemp);
end;
Probówałem też tłumaczyć kod z http://www.codeproject.com/Articles/2841/How-to-replace-a-color-in-a-HBITMAP na Delphi, ale po takich operacjach jak poniżej nie działa. Pewnie tę pętlę trzeba przetłumaczyć inaczej, ale wlaśnie nie wiem jak. A z tego co mi się zdaję to taki kod działający pod Delphi by mnie urządzał. Czekam na przykłady od Was i z góry dziekuję.
type
PByteArray = ^TByteArray;
TByteArray = array[0..32767] of Byte;
function COLORREF2RGB(Color : COLORREF) : COLORREF;
begin
Result := (Color and $FF00) or ((Color shr 16) and $FF) or ((Color shl 16) and $FF0000);
end;
function ReplaceColor(hBmp : HBITMAP; cOldColor : COLORREF; cNewColor : COLORREF; hBmpDC : HDC) : HBITMAP;
var
BM : BITMAP;
I : integer;
ptPixels : PUINT;
BufferDC, DirectDC : HDC;
RetBmp, hTmpBitmap, DirectBitmap : HBITMAP;
PreviousBufferObject, PreviousObject : HGDIOBJ;
RGB32BitsBITMAPINFO : TBitmapInfo;
begin
RetBmp := 0;
if hBmp > 0 then
begin
BufferDC := CreateCompatibleDC(0); // DC for Source Bitmap
if BufferDC > 0 then
begin
if hBmpDC > 0 then
if hBmp = HBITMAP(GetCurrentObject(hBmpDC, OBJ_BITMAP)) then
begin
hTmpBitmap := CreateBitmap(1, 1, 1, 1, nil);
SelectObject(hBmpDC, hTmpBitmap);
end;
PreviousBufferObject := SelectObject(BufferDC, hBmp);
// here BufferDC contains the bitmap
DirectDC := CreateCompatibleDC(0); // DC for working
if DirectDC > 0 then
begin
// Get bitmap size
GetObject(hBmp, SizeOf(BM), @BM);
// create a BITMAPINFO with minimal initilisation
// for the CreateDIBSection
ZeroMemory(@RGB32BitsBITMAPINFO, Sizeof(TBitmapInfo));
RGB32BitsBITMAPINFO.bmiHeader.biSize := Sizeof(BITMAPINFOHEADER);
RGB32BitsBITMAPINFO.bmiHeader.biWidth := bm.bmWidth;
RGB32BitsBITMAPINFO.bmiHeader.biHeight := bm.bmHeight;
RGB32BitsBITMAPINFO.bmiHeader.biPlanes := 1;
RGB32BitsBITMAPINFO.bmiHeader.biBitCount := 32;
// pointer used for direct Bitmap pixels access
DirectBitmap := CreateDIBSection(DirectDC,
TBitmapInfo(RGB32BitsBITMAPINFO),
DIB_RGB_COLORS,
Pointer(ptPixels),
0, 0);
if DirectBitmap > 0 then
begin
// here DirectBitmap!=NULL so ptPixels!=NULL no need to test
PreviousObject := SelectObject(DirectDC, DirectBitmap);
BitBlt(DirectDC, 0, 0,
bm.bmWidth, bm.bmHeight,
BufferDC, 0, 0, SRCCOPY);
// here the DirectDC contains the bitmap
// Convert COLORREF to RGB (Invert RED and BLUE)
cOldColor := COLORREF2RGB(cOldColor);
cNewColor := COLORREF2RGB(cNewColor);
// After all the inits we can do the job : Replace Color
for I := (bm.bmWidth * bm.bmHeight) - 1 downto 0 do
begin
if PByteArray(ptPixels)^[I] = cOldColor then
begin
PByteArray(ptPixels)^[I] := cNewColor;
end;
end;
// little clean up
// Don't delete the result of SelectObject because it's
// our modified bitmap (DirectBitmap)
SelectObject(DirectDC, PreviousObject);
// finish
RetBmp := DirectBitmap;
end;
// clean up
DeleteDC(DirectDC);
end;
if hTmpBitmap > 0 then
begin
SelectObject(hBmpDC, hBmp);
DeleteObject(hTmpBitmap);
end;
SelectObject(BufferDC, PreviousBufferObject);
// BufferDC is now useless
DeleteDC(BufferDC);
end;
end;
Result := RetBmp;
end;