Subscribe:

Ads 468x60px

Loading

Kamis, 07 Juli 2011

Creating Shaped Forms

Cool Bitmap shaped forms the easy way

Hey! Bored with rectangular windows? HERE'S THE CODE to make any shape you want based on a bitmap picture. How to do it:
1. First, make or choose any background bitmap you want your form to have. Then fill areas you want to go transparent with a distinct color (In this example, it is white).   NOTE: The bitmap's size must be the actual size you want on your form. No stretching in Delphi will work.

2. In Delphi, add a TImage(Image1) component on the form. Choose your bitmap and put the component where you want it. Autosize must be true. Other visual components must be on top of the "visible" part of the picture so that they will be seen.

3. Add the following code (...I mean short code) to your FormCreate procedure. I know I should have made a component for it so that no code would be needed.  But just to show you how, I guess this would suffice.

procedure TForm1.FormCreate(Sender: TObject);
const
  // Image Color to be made transparent
  MASKCOLOR = clWhite;

  // Cutting adjustments
  ADJ_TOP = 22;{TitleBar}
  ADJ_BOTTOM = 22 ;{TitleBar}
  ADJ_LEFT = 3;{Border}
  ADJ_RIGHT = 3;{Border}
var
  ShowRegion,CutRegion: HRgn;
  y,x1,x2:integer;
  PixelColor:TColor;
begin

  ShowRegion:=CreateRectRgn(Image1.Left+ADJ_LEFT,Image1.Top+ADJ_TOP,
    Image1.Left+Image1.Width+ADJ_RIGHT,Image1.Top+Image1.Height+ADJ_BOTTOM);

  // Cut the parts whose color is equal to MASKCOLOR by rows
  for y:=0 to Image1.Picture.Bitmap.Height-1 do
    begin
      x1:=0; // starting point of cutting
      x2:=0; // end point of cutting
      repeat
        PixelColor:=Image1.Picture.Bitmap.Canvas.Pixels[x2,y];
        // the above will return -1 if x2 reached beyond the image
        if (PixelColor=MaskColor) then
          Inc(x2)
        else
          begin
            //do following if pixel reached beyond image or if color of pixel is not MaskColor
            if x1 <> x2 then
              begin
                // Create the region to be cut. The region will be one line of pixels/a pixel with color of                   // MaskColor
                CutRegion:=CreateRectRgn(
                X1+Image1.Left+ADJ_LEFT ,
                Y+Image1.Top+ADJ_TOP,
                X2+Image1.Left+ADJ_RIGHT ,
                Y+Image1.Top+ADJ_TOP+1);

                try
                  CombineRgn(ShowRegion,ShowRegion,CutRegion,RGN_DIFF);
                  // RGN_DIFF will get the difference of ShowRegion
                finally
                  DeleteObject(CutRegion);
                end;
              end;

            Inc(x2);
            x1:=x2;
          end;
      until PixelColor=-1;
    end;

  // Set the window to have the above defined region
  SetWindowRgn(Form1.Handle,ShowRegion,True);
  // NOTE : Do not free close/delete ShowRegion because it will become owned
  // by the operating system

  // You can manually disable the showing of the whole
  //form while dragging, with the following line but
  // just leave it since it is dependent on your
  // windows settings. Some people may want to have their
  // windows show its contents while dragging.

  // SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, 0, nil, 0); {Disable drag showing}
  // SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, 1, nil, 0); {Enable drag showing}
end;

NOW FOR THE FORM DRAGGING PART

1. Add this line to the private declarations of your Form:
procedure WMNCHitTest(var Msg: TWMNCHitTest); message wm_NCHitTest;
2. In the implementation part. Add the following (assuming your Form name is Form1):
procedure TForm1.WMNCHitTest(var Msg: TWMNCHitTest);
begin
  inherited;
  if Msg.Result = htClient then
    Msg.Result := htCaption;
end;

Also, add a button to close the form because the title bar cannot be seen. That's all!



=============================================================


This article comes thanks to Gerard Oei who provided the Delphi source code.
We have already done a tutorial on how to create non-rectangular windows. This tutorial shows how to create a form that is shaped around a bitmap. Like the previous tutorial it uses the SetWindowRGN function. The clever part here is how the region is created.

Shaping the Form

I will not explain in detail how the code works because I think it will be easier to read the code and let the comments explain what is happening.
As an overview on the form you should place a TImage and set its picture property to be the image that you would like the form to be shaped around. At design time it should look like the following image:
Delphi 7
The main part of the code can be found in the function CreateRegion which uses the API functions CreateRectRGN and CombineRGN to great affect. CreateRegion is then called from the form's constructor to shape the form accordingly.

The Sample Code

What follows is the Delphi code for shaping the window. You can also download the code at the bottom of this tutorial.
function TForm1.CreateRegion(Bmp: TBitmap): THandle; 
var
  X, Y, StartX:Integer;
  Excl: THandle;  Row: PRGBArray;
  TransparentColor: TRGBTriple;begin
  // Change the format so we know how to compare 
  // the colors 
  Bmp.PixelFormat := pf24Bit;
    
  // Create a region of the whole bitmap 
  // later we will take the transparent   
  // bits away  Result := CreateRectRGN(0, 0, Bmp.Width, Bmp.Height);

  // Loop down the bitmap   
  for Y := 0 to Bmp.Height - 1 do
  begin
    // Get the current row of pixels    Row := Bmp.Scanline[Y];

    // If its the first get the transparent    // color, it must be the top left pixel    if Y = 0 then
    begin
      TransparentColor := Row[0];
    end;

    // Reset StartX (-1) to indicate we have    // not found a transparent area yet    StartX := -1;

    // Loop across the row    for X := 0 to Bmp.Width do
    begin

      // Check for transparency by comparing the color      if(X <> Bmp.Width) and
        (Row[X].rgbtRed = TransparentColor.rgbtRed) and
        (Row[X].rgbtGreen = TransparentColor.rgbtGreen) and
        (Row[X].rgbtBlue = TransparentColor.rgbtBlue) then
      begin
        // We have (X <> Bmp.Width) in the clause so that        // when we go past the end of the row we we can        // exclude the remaining transparent area (if any)        // If its transparent and the previous wasn't        // remember were the transparency started        if StartX = -1 then
        begin
          StartX := X;
        end;
      end
      else
      begin
        // Its not transparent        if StartX > -1 then
        begin
          // If previous pixels were transparent we          // can now exclude the from the region          Excl := CreateRectRGN(StartX, Y, X, Y + 1);
          try
            // Remove the exclusion from our original region            CombineRGN(Result, Result, Excl, RGN_DIFF);

            // Reset StartX so we can start searching            // for the next transparent area            StartX := -1;
          finally
            DeleteObject(Excl);
          end;
     end;
      end;
    end;
  end; 
end;
    
procedure TForm1.FormCreate(Sender: TObject); 
var
  Bmp: TBitmap;
begin
  Bmp := TBitmap.Create;
  try
    // We use a TImage to hold the bitmap so that 
    // we can see how the form will look at design    // time    Bmp.Assign(Image1.Picture);    FRegion := CreateRegion(Bmp);    SetWindowRGN(Handle, FRegion, True);
  finally
    Bmp.Free;  end; 
end;

Conclusion

When the application is run the form should now take the shape of the bitmap, as shown in the following screen shot
Once again I would like to say a big thank you to Gerard Oei for providing the code to this article. You can download the source code here.

 Source : http://www.delphi-central.com/BitmapShapedForm.aspx

0 komentar:

Posting Komentar