Przycisk podobny do TBitBtn, ale koniecznie w WinAPI.

0

Cześć. Wiecie, że rzadko proszę o pomoc i staram sobie radzić sam. Jednak mimo, że coś tam potrafię zakodować w WinAPI, to tego nie potrafię do końca sam zrobić. Zobaczcie na exek i kod w załączniku. Chodzi o to żeby górny przycisk z tekstem This is test dało się zablokować przez funckję EnableWindow(Uchwyt, False) i nie skopała się grafika oraz tekst. Teraz jak widać pojawia się szary prostokąt na cały button. A odblokowywać i blokowac przycisk można klikając dolnym przyciskiem tylko z ikonką choinki. To co jest w kodzie funkcji CreateBitBtn po ButtonEnabled to cześc z modułu bitbtn.pas co mamy przy rysowaniu captiona przy state disabled. Jednak to się nie sprawdza. Oczywiście dla VCL nie ma problemu bo mamy TBitBtn działąjący jak trzeba, jednak ja chcę osiągnąc to w WinAPI i to dla HICON zamiast HBITMAP jako obrazka i koniecznie by można było ustawić Enabled na False i grafika oraz tekst wyświetlały się odpowiednio jako nieaktywne. Póki co przycisk jest tworzony "na sztywno", później jak pomożecie mi to okiełznać zamiast tego tworzenia będzie ustawianie stylów i HDC dla podanego uchwytu. I jak za pewne widać - próbowałem kombinować z użyciem Color_Values_Arr kiedy nie ustawiamy EnableWindow(Uchwyt, False); tylko parametr ButtonEnabled na False. Wtedy ikonka ładowana z takimi flagami przez LoadImage miała by ok kolory, ale przycisk można klikać i nadal problem z rysowaniem tekstu. Liczę na Waszą pomoc, bo sporo googlowałem i sam kombinowałem, ale posiłokowałem się głownie kodami podanymi w tym wątku: http://pl.comp.lang.delphi.narkive.com/vLIXHiLD/delphi-winapi-tworzenie-przycisku-z-ikona-i-tekstem - może @kAzek lub @-321oho będą wiedzieć. Albo ktoś inny, kto coś dłubał w WinAPI i Delphi. Dodam, że nie upieram się przy tej metodzie, ale jeżeli jest sposób na wyświetlenie przycisku z obrazkiem jako ikonka i tekstem jednocześnie, ustawienie mu Enabled jak należy, a można by to jakoś zrobić przez obsługę komunikatu WM_DRAWITEM czy WM_PAINT to prosił bym o przykładowe kody. Załaczony plik to kompletne żródło, exek i plik buildujący. Kompilowac się to będzie bez probleów pod Delphi 7, w nowszych chyba też może dać radę. Poniżej kod tego co na razie działa ok tylko przy Enabled na True. Docelowo jak wspomniałem tworzenie na sztywno oraz dopasowanie pozycji ikonki i tekstu do rozmairów przycisku ustawie odpowiednio. Bo to teraz jest pisane na szybko, dla testów. Sorry za rozpisanie się. Czekam na Wasze pomysły.

function CreateBitBtn(HParentWnd : HWND; ButtonIcon : HICON; Text : string;
  TextFont : HFONT; ButtonEnabled : boolean) : HWND;
const
  BtnWidth = 200;
  BtnHeight = 74;
  BtnStyle = WS_CHILDWINDOW or WS_VISIBLE or BS_BITMAP;
  Color_Values_Arr : array[boolean] of UINT = (LR_MONOCHROME, LR_DEFAULTCOLOR);
var
  BtnH : HWND;
  BtnDc : HDC;
  MemDC : HDC;
  NullBmp : HBITMAP;
  BitmapH : HICON;
  BmpRect : TRect;
  Txtrect : TRect;
  Caption : PChar;
  BMInf : TagBITMAP;
  IconInf : TIconInfo;
  IconWidth, IconHeight : integer;
begin
  Result := 0;
  Caption := PChar(TexT);
  BtnH := CreateWindow('Button', nil, BtnStyle, 18, 30,
    BtnWidth, BtnHeight, HParentWnd, 0, HInstance, nil);
  if GetLastError = 0 then
  begin
    Result := BtnH;
    BtnDc := GetDC(BtnH);
    MemDC := CreateCompatibleDC(BtnDc);
    IconWidth := LR_DEFAULTSIZE;
    IconHeight := LR_DEFAULTSIZE;
    if GetIconInfo(ButtonIcon, IconInf) then
    begin
      if GetObject(IconInf.hbmColor, SizeOf(BMInf), @BMInf) > 0 then
      begin
        IconWidth := BMInf.bmWidth;
        IconHeight := BMInf.bmHeight;
      end;
    end;
    BitmapH := CreateCompatibleBitmap(BtnDc, BtnWidth - 8, IconHeight);
    ReleaseDC(BtnH, BtnDc);
    NullBmp := SelectObject(MemDC, BitmapH);
    BmpRect.Left := 0;
    BmpRect.Top := 0;
    BmpRect.Right := BtnWidth - 8;
    BmpRect.Bottom := IconHeight;
    FillRect(MemDC, BmpRect, GetSysColorBrush(COLOR_BTNFACE));
    DrawIconEx(MemDC, 0, 0, ButtonIcon, 0, 0, 0, 0, DI_NORMAL);
    SelectObject(MemDc, TextFont);
    SetTextColor(MemDC, GetSysColor(COLOR_WINDOWTEXT));
    SetBkColor(MemDC, GetSysColor(COLOR_BTNFACE));
    TxtRect.Left := IconWidth + 8;
    TxtRect.Top := 0;
    TxtRect.Right := BtnWidth - 8;
    TxtRect.Bottom := 16;
    DrawText(MemDC, Caption, -1, txtrect, DT_END_ELLIPSIS);
    if not ButtonEnabled then
    begin
      SetTextColor(MemDC, GetSysColor(COLOR_BTNHIGHLIGHT));
      //Fnt Font.Color := clBtnHighlight;
      DrawText(BtnH, PChar(Caption), Length(Caption), TxtRect,
        DT_CENTER or DT_VCENTER);
      SetTextColor(MemDC, GetSysColor(COLOR_BTNSHADOW));
      DrawText(BtnH, PChar(Caption), Length(Caption), TxtRect,
        DT_CENTER or DT_VCENTER);
    end
    else
    begin
      DrawText(BtnH, PChar(Caption), Length(Caption), TxtRect,
        DT_CENTER or DT_VCENTER);
    end;
    SelectObject(MemDC, NullBmp);
    DeleteDC(MemDC);
    SendMessage(BtnH, BM_SETIMAGE, IMAGE_BITMAP, BitmapH);
  end;
end;
0

Graficzne WinApi nie jest moją mocną stroną ale czy po majstrowaniu na MemDC nie powinieneś tego gdzieś przekopiować?
Np. przy pomocy BitBlt?

http://msdn.microsoft.com/en-us/library/kwxzck32.aspx
http://www.ucancode.net/faq/CBitmap.htm

0

Dziękuję za odpowiedź. Jednak w Delphi nie ma takich typów z C w nazwie. Poza tym nie wiem jak to kopiowac aby dało to efekt. Może trzeba kombinować z WM_DRAWITEM. Teraz zaczeła działać ta strona (w nocy trzeba było się do niej dobijać przez webarchive podając bezpośrednie linki stron z google co nie jest za wygodne). Póki co pokombinuje jak pokazano na: http://www.angelfire.com/hi5/delphizeus/inunits.html - tylko, że tam jest opis dla comcoBoxa. Jednak jeżeli ktoś z Was będzie wiedział jak ogarnąć temat aby uzyskać taki efekt jak chcę, to prosze Was bardzo o odpowiedzi z możliwymi przykładowymi kodami.

0

Tu masz przykład w Delphi - musisz tylko uważać na parametry bo ten przykład rysuje przezroczystą bitmapę
z MemDC (tu hdcMem):

http://www.delphipages.com/articles/drawing_transparent_bitmaps-9224.html

0

Oj ciężki przypadek z tym już kilka lat już już się nie bawię w WinApi ale o ile pamiętam chyba robiłem zwykle używając bitmap robiłem osobną bitmapę dla nie aktywnego buttona i wstawiałem ją po EnableWindow tylko nie wiem czy to coś dało wiem że sam miałem kiedyś z tym problem ale to nie było nić ważnego i nie wiem czy znalazłem rozwiązanie ale jak znajdę chwilkę (w tym tygodniu bo trochę zapiernicz przed świętami) to pogrzebię na starym dysku w w starych kodach bo wydaje mi się że jakoś to zrobiłem jak coś to napiszę.

0

@kAzek: jak znajdziesz jakiś kod to daj znać. Bo ja jednak wykombinowałem z WM_DRAWITEM. Nie jest to idealny kod, ponieważ jako noga z matematyki i nie ogarniający wszystkiego w kodzie VCL modułu Buttons, zrobiłem zmienianie pozycji horyzontalnej Ikony (glypha) względem: szerokości tekstu, szerokości ikony oraz szerokości samego buttona, jak potrafiłem. W archiwum dołaczam kod wersji 0.2. Może się komyś przyda, ale jak znajdziecie lepsze rozwiązanie - to prosze napiszcie. W google nie znalazłem niestaty dobrych przykładów w Delphi poza stroną o API tego Zeusa. Także może przyszłe wyszukiwania będa kierować ludzi tutaj po mój załącznik.

1 użytkowników online, w tym zalogowanych: 0, gości: 1