2017-11-27 172 views
5

chciałbym standardowego okna informacyjne i ostrzegawcze (błąd) i ikony malowane na indeks karcie z pagecontrol. Jednak wynik wygląda źle, jeśli kolor tła okna nie jest biały.Jak malować standardową ikonę informacji okien ładnie indeksowi JOT pagecontrol za

program Project111; 

uses 
    Vcl.Forms, 
    Vcl.Controls, 
    Vcl.Graphics, 
    Winapi.Windows, 
    Vcl.ComCtrls, 
    Vcl.ImgList; 

{$R *.res} 

var 
    mainForm: TForm; 
    imageList: TImageList; 
    icon: TIcon; 
    pageControl: TPageControl; 
    tabSheet: TTabSheet; 
begin 
    Application.Initialize; 
    Application.MainFormOnTaskbar := True; 

    Application.CreateForm(TForm, mainForm); 

    imageList := TImageList.Create(mainForm); 
    imageList.ColorDepth := cd32bit; 
    icon := TIcon.Create; 
    try 
    icon.Handle := LoadImage(0, IDI_INFORMATION, IMAGE_ICON, 16, 16, {LR_DEFAULTSIZE or} LR_SHARED); 
    imageList.AddIcon(icon); 
    finally 
    icon.Free; 
    end; 

    pageControl := TPageControl.Create(mainForm); 
    pageControl.Parent := mainForm; 
    pageControl.Images := imageList; 

    tabSheet := TTabSheet.Create(mainForm); 
    tabSheet.Parent := pageControl; 
    tabSheet.PageControl := pageControl; 
    tabSheet.ImageIndex := 0; 

    Application.Run; 
end. 

Oto zrzut ekranu: enter image description here

Jak widać białe obramowanie jest rozmyty, myślę, że to z powodu braku odpowiedniej przezroczystości Alpha TImageList ale nie wiem jak to naprawić to.

Rozwiązanie nie trzeba używać TImageList, cieszę się używać innego podejścia. Zauważ, że będą też podpisy, a nie wszystkie indeksy będą miały ikony, a ikony mogą się zmieniać/dodawać/usuwać wraz ze zmianą kontekstu.

używam Delphi XE-2, ja też mam składników DevExpress czy to pomaga.

+0

Spodziewaj się, że jest bardzo powszechne. Charakter tworzenia samych obrazów zakłada, że ​​zostaną użyte na jasnym tle. Problem tkwi w rzeczywistych obrazach. Nie wiele kodu może to naprawić. Poprawka ma zapewnić obraz zoptymalizowany do użycia na ciemnym tle. Albo jeszcze lepiej, spędziliśmy pół roku aktualizując wszystkie przyciski i ikony w naszym oprogramowaniu, aby być czcionką wektorową z tego konkretnego powodu. Teraz możemy kolorować ikony, które chcemy na dowolnym tle. –

Odpowiedz

6

Jak @Sertac mówi to, co widzisz, jest efektem zmiany rozmiaru powłoki ikonę Windows od 32x32 do 16x16, jako obejście wychodząc z Windows Vista można użyć funkcji SHGetStockIconInfo. przesłanie flagi SHGSI_SMALLICON w celu pobrania małej wersji ikony, określonej przez SM_CXSMICON i SM_CYSMICON.

Wartości SM_CXSMICON i SM_CYSMICON zależą od bieżącego ustawienia DPI. Dla DPI 96 jest 16x16.

Próbka

LIcon := TIcon.Create; 
    try 
    LIcon.Handle := 0; 
    if TOSVersion.Check(6, 0) then 
    begin 
     ZeroMemory(@LSHStockIconInfo, SizeOf(LSHStockIconInfo)); 
     LSHStockIconInfo.cbSize := sizeof(LSHStockIconInfo); 
     if SHGetStockIconInfo(SIID_INFO, SHGSI_ICON or SHGSI_SMALLICON, LSHStockIconInfo) = S_OK then 
     begin 
     LIcon.Handle := LSHStockIconInfo.hIcon; 
     imageList.AddIcon(LIcon); 
     end; 
    end; 
    finally 
    LIcon.Free; 
    end; 
3

co widzisz nie jest z powodu złamanego przezroczystości alfa ale artefaktu skalowania.

Jak documented, domyślny rozmiar ikony LoadImage ładunków jest SM_CXICON x SM_CYICON, który jest zwykle 32x32. Ponieważ żądasz ikony udostępnionej przez system, będzie to rozmiar ikony, która zostanie podana.

Można sprawdzić, czy tak jest w kodzie:

.. 
    try 
    icon.Handle := LoadImage(0, IDI_INFORMATION, IMAGE_ICON, 16, 16, {LR_DEFAULTSIZE or} LR_SHARED); 
    Assert(icon.Width = GetSystemMetrics(SM_CXICON)); 
    Assert(GetSystemMetrics(SM_CXICON) <> 16); 
    .. 

Co za tym idzie jest to, że ikona zostanie przeskalowany w celu dopasowania do listy obrazu prawdopodobnie przez nic lepszego niż StretchBlt z trybem COLORONCOLOR.

Niestety nie jest to możliwe, aby załadować ikonę systemową o niestandardowym rozmiarze, ponieważ, jak znowu udokumentowane,

Podczas ładowania ikonę systemową lub kursora, należy użyć LR_SHARED lub funkcja nie załaduje zasobu.


Co trzeba zrobić, to załadować ikonę współdzielony z domyślnego rozmiaru, a następnie zmienić jego rozmiar do 16x16 siebie za pomocą lepszego algorytmu. StretchBlt z HALFTONE byłby prawdopodobnie lepszy, ale użycie bardziej zaawansowanej biblioteki graficznej może dać najlepsze rezultaty.

Zdecydowanie odradzaną alternatywą jest załadowanie zasobu bezpośrednio z miejsca jego pobytu. Jeśli nie użyjesz flagi LR_SHARED, otrzymasz żądany rozmiar. Musisz wykonać pewne badania, aby znaleźć rzeczywisty indeks ikony, ponieważ nie jest to udokumentowane. I trzeba wziąć pod uwagę, że indeks lub miejsce, w którym żyje, może z czasem ulec zmianie. Nie zapomnij o zniszczeniu ikony w tym przypadku, ponieważ system nie zrobi tego dla zasobu niewspółużytkowanego.

icon.Handle := LoadImage(GetModuleHandle(user32), Pointer(104), IMAGE_ICON, 16, 16, 0);