Ir al contenido


Foto

TSkinButton


  • Por favor identifícate para responder
3 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.955 mensajes
  • LocationMadrid - España

Escrito 05 junio 2015 - 06:29

Se trata de un componente conocido por los miembros platino y que he querido liberar con un lavado de cara.
 
Básicamente se trata de un botón con piel que resultará del uso de un bitmap que la dará la forma. Se requieren 2 bitmaps principales con el dibujo del botón en reposo y presionado, más dos bitmaps adicionales con ambos estados "luminosos", si queremos que al pasar por encima el cursor del ratón, muestre ese aspecto.
 
Por lo demás se trata de un botón delphi normal y corriente.
 
La magia gráfica se basa en el uso de regiones en Windows y la realiza esta función:

delphi
  1. procedure SkinControl(Control: TWinControl; bmp: TBitmap);
  2. var
  3.   TransparentColor: DWORD;
  4.   rgn, rgnTemp: HRGN;
  5.   ini, x, y: integer;
  6.   Pixel: PADWord;
  7. begin
  8.   bmp.HandleType:= bmDIB;
  9.   bmp.PixelFormat:= pf32bit;
  10.   Control.SetBounds(Control.Left, Control.Top, bmp.Width, bmp.Height);
  11.  
  12.   TransparentColor:= PADWord(bmp.ScanLine[bmp.Height-1])[0];
  13.  
  14.   rgn:= CreateRectRgn(0, 0, Control.Width, Control.Height);
  15.   CombineRgn(rgn, rgn, rgn, RGN_DIFF);
  16.  
  17.   for  y:=0 to bmp.Height-1 do
  18.   begin
  19.     Pixel:= PADWord(bmp.ScanLine[y]);
  20.     ini:= 0;
  21.     for x:=0 to bmp.Width-1 do
  22.     begin
  23.        if pixel[x] <> TransparentColor then
  24.        begin
  25.          rgnTemp:= CreateRectRgn(ini, y, x, y+1);
  26.          CombineRgn(rgn, rgn, rgnTemp, RGN_OR);
  27.          DeleteObject(rgnTemp);
  28.          ini:= x;
  29.        end
  30.        else inc(ini);
  31.     end;
  32.   end;
  33.   SetWindowRgn(Control.Handle, rgn, true);
  34.   DeleteObject(rgn);
  35. end;

post-12294-0-07595100-1433508066.png
 
 
Mientras que el cambio gráfico entre los estados, lo realiza esta otra:

delphi
  1. procedure TSkinButton.CNDrawItem(var Message: TWMDrawItem);
  2. var
  3. Push: boolean;
  4. Bitmap: TBitmap;
  5. begin
  6. FCanvas.Handle:= Message.DrawItemStruct.hDC;
  7. FCanvas.Refresh();
  8.  
  9. if (csDesigning in ComponentState) then
  10. begin
  11. if fBmpUp.Empty then
  12. fBmpUp.LoadFromResourceName(HInstance, 'SKINBUTTON');
  13. ActivateSkin;
  14. FCanvas.Draw(ClientRect.Left, ClientRect.Top, fBmpUp);
  15. exit;
  16. end;
  17.  
  18. ActivateSkin;
  19.  
  20. Push:= ((Message.DrawItemStruct.itemState and ODS_SELECTED)<>0) and ((Message.DrawItemStruct.itemAction and ODA_SELECT)<>0);
  21.  
  22. if Enabled then
  23. begin
  24. if Push and (fAllowUp = false) then
  25. fDown:= fDown xor true
  26. else if fAllowUp then
  27. fDown:= Push;
  28. end;
  29.  
  30. if fDown then // El botón está pulsado
  31. begin
  32. if fBmpDown.Empty = false then Bitmap:= fBmpDown
  33. else Bitmap:= fBmpUp;
  34. if Enabled and fHiLight and not fBmpDownHiLight.Empty then Bitmap:= fBmpDownHiLight;
  35. end else
  36. begin
  37. Bitmap:= fBmpUp;
  38. if Enabled and fHiLight and not fBmpUpHiLight.Empty then Bitmap:= fBmpUpHiLight;
  39. end;
  40. FCanvas.Draw(ClientRect.Left, ClientRect.Top, Bitmap);
  41. end;

Adjunto código del control, imagen y aplicación de ejemplo.


Saludos.

Archivos adjuntos


  • 3

#2 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 05 junio 2015 - 07:58

Gracias Escafandra por tus magníficos aportes.

 

Saludos.


  • 0

#3 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.156 mensajes
  • LocationMéxico

Escrito 05 junio 2015 - 08:32

Excelente amigo, un gran aporte y que bueno que ha decidido "liberarlo".  :ap:

 

Saludos


  • 0

#4 escafandra

escafandra

    Advanced Member

  • Moderadores
  • PipPipPip
  • 3.955 mensajes
  • LocationMadrid - España

Escrito 06 junio 2015 - 10:10

Para los amantes de hacerlo en C++ esta es la versión:
 

cpp
  1. void __fastcall SkinControl(TWinControl* Control, Graphics::TBitmap *bmp)
  2. {
  3. bmp->HandleType = bmDIB;
  4. bmp->PixelFormat = pf32bit;
  5. Control->SetBounds(Control->Left, Control->Top, bmp->Width, bmp->Height);
  6.  
  7. DWORD TransparentColor = static_cast<DWORD*>(bmp->ScanLine[bmp->Height-1])[0];
  8. HRGN rgn, rgnTemp;
  9.  
  10. rgn = CreateRectRgn(0, 0, 0, 0);
  11.  
  12. for(int y=0; y<bmp->Height; ++y){
  13. DWORD *pixel = static_cast<DWORD*>(bmp->ScanLine[y]);
  14. for(int x=0, ini = 0; x<bmp->Width; ++x){
  15. if(pixel[x] != TransparentColor){
  16. rgnTemp = CreateRectRgn(ini, y, x, y+1);
  17. CombineRgn(rgn, rgn, rgnTemp, RGN_OR);
  18. DeleteObject(rgnTemp);
  19. ini = x;
  20. } else ini++;
  21. }
  22. }
  23. SetWindowRgn(Control->Handle, rgn, true);
  24. DeleteObject(rgn);
  25. }


El cambio gráfico entre los estados:

cpp
  1. void __fastcall TSkinButton::CNDrawItem(TWMDrawItem& Message)
  2. {
  3. FCanvas->Handle = Message.DrawItemStruct->hDC;
  4. FCanvas->Refresh();
  5.  
  6. if(ComponentState.Contains(csDesigning)){
  7. if(fBmpUp->Empty)
  8. fBmpUp->LoadFromResourceName((int)HInstance, "SKINBUTTON");
  9. ActivateSkin();
  10. FCanvas->Draw(ClientRect.left, ClientRect.top, fBmpUp);
  11. return;
  12. }
  13.  
  14. ActivateSkin();
  15.  
  16. bool Push = Message.DrawItemStruct->itemState & ODS_SELECTED;
  17.  
  18. if(Enabled){
  19. if(Push && !fAllowUp){
  20. fDown ^= true;
  21. }
  22. else if(fAllowUp){
  23. fDown = Push;
  24. }
  25. }
  26. FBitmap = fBmpUp;
  27. if(fDown){ // El botón está pulsado
  28. if(!fBmpDown->Empty) FBitmap = fBmpDown;
  29. if(Enabled && fHiLight && !fBmpDownHiLight->Empty) FBitmap = fBmpDownHiLight;
  30. }else{
  31. FBitmap = fBmpUp;
  32. if(Enabled && fHiLight && !fBmpUpHiLight->Empty) FBitmap = fBmpUpHiLight;
  33. }
  34.  
  35. FCanvas->StretchDraw(ClientRect, FBitmap);
  36. }

Archivos adjuntos


  • 1