|
Graphic
Convert .ICO to .BMP
Get a DC for a Control
Using icons on a SpeedButton
BMP rotation
Lasso control
TOutline icons
Drawing Graphs
TGraphicComponent child
Converting Icons to Glyphs
Delphi Graphics
Image resizing and displaying
How to dim the colors of a glyph in a button
How Can I Make These Graphics Faster?
Make mouse snap to grid while drawing
Graph to clipboard
Icons loaded and converted for TBitBtn no white
Transparent Forms and Bitmaps
From Sizes on different platforms
Fast way to Clear a TCanvas
Assign a palette to a bitmap
Transparent bitmap brush
Removing TBitMap from TBitBtn
One draw directly onto the screen (not the form)
Bitmap Transparency
Convert .ICO to .BMP
Question
Is there a fairly simple (and on-the-fly) way to convert a .ico to a .bmp (as in getting a speedbutton to display an icon)?
Answer
A:
procedure TIconShow.FileListBox1Click(Sender: TObject);
var
MyIcon: TIcon;
MyBitMap : TBitmap;
begin
MyIcon := TIcon.Create;
MyBitMap := TBitmap.Create;
try
{ get the file name and the icon associated with it}
strFileName := FileListBox1.Items[FileListBox1.ItemIndex];
StrPCopy(cStrFileName, strFileName);
MyIcon.Handle := ExtractIcon(hInstance, cStrFileName, 0);
{ draw the icon onto the bitmap for the speed button }
SpeedButton1.Glyph := MyBitMap;
SpeedButton1.Glyph.Width := MyIcon.Width;
SpeedButton1.Glyph.Height := MyIcon.Height;
SpeedButton1.Glyph.Canvas.Draw(0,0, MyIcon);
SpeedButton1.Hint := strFileName;
finally
MyIcon.Free;
MyBitMap.Free;
end;
end;
Get a DC for a Control
Question
How to get a DC for delphi VCL? I am trying to use the API function StretchBlt which requires a destDC and a sourceDC.
How do I tell windows to use my TImage or TShape for this purpose?
Answer
A:
{Bitmap in a TImage}
HDC:=Image1.PICTURE.bitmap.canvas.handle;
A DC is anything with a Canvas.handle.
Using icons on a SpeedButton
Question
Probably need a way to extract the application icon into a physical .ICO
file and convert it to a .BMP file.
Answer
A:
You can cheat a little and just copyrect the Icon into the Bitmap of a
Speed button.
var
imgIcon: TIcon;
imgRect: TRect;
begin
imgIcon := TIcon.Create;
imgIcon.Handle := ExtractIcon( 'EXEFILENAME' );
with SpeedButton1.Glyph do begin
Width := imgIcon.Width;
Height := imgIcon.Height;
imgRect := Rect( 0, 0, Width, Height );
Canvas.CopyRect( imgRect, imgIcon.Canvas, imgRect );
end;
BMP rotation
Question
I want to rotate BMPs (rotate to any arbitrary angle around its center of mass)
on form with Delphi code.
Answer
A:
I can think of a brute force method, but its efficiency might be
questionable, don't try it without a co-processor!
Do a pixel-by-pixel mapping from a source bitmap to a target bitmap (using
the Canvas.Pixels property). For each pixel do a rectangular-polar
coordinate conversion, add the angle offset to the polar coordinate, then
convert back to rectangular and place the pixel at these new coordinates in
the target bitmap. You may also have to dither in a few missing pixels
depending on the accuracy / rounding of your arithmatic.
The X, Y transformation you would need would be as follows:
X,Y = old pixel coordinates
X1,Y1 = new pixel coordinates
T = rotation angle (in radians)
R, A - intermediate values representing the polar coordinates
R = Sqrt(Sqr(X) + Sqr(Y));
A = Arctan(Y/X);
X1 = R * Cos(A+T);
Y1 = R * Sin(A+T);
I really hope there is a better way of doing it, but if you can't find
anything else, this may be worth a try. I'm happy it will work, but may be
rather slow.
A:
>Do a pixel-by-pixel mapping from a source bitmap to a target bitmap (using
>the Canvas.Pixels property).
This is a good start -- but try thinking of it the other way around. Do a
pixel-by-pixel mapping from the target bitmap to the source bitmap, so
you're thinking about where the pixels are coming from, rather than where
they are going.
Here is a formula for rotation about the origin:
x, y = coordinates in the target bitmap
t = angle
u, v = coordinates in the source bitmap
x = u * cos(t) - v * sin(t)
y = v * cos(t) + u * sin(t)
Now, if I've solved these equations right for u and v, here's what they
would be (no guarantees, that's why I've included the originals!):
x * cos(t) + y
u = --------------------
sqr(cos(t)) + sin(t)
v = y * cos(t) - x
--------------------
sqr(cos(t)) + sin(t)
So, assuming you know the angle of rotation, you might calculate the
constants cos(t) and 1/sqr(cos(t))+sin(t) just before your loop; it might
look something like this (some adjustment and clipping needed):
ct := cos(t);
ccst := 1/sqr(cos(t))+sin(t);
for x := 0 to width do
for y := 0 to height do
dest.pixels[x,y] := source.pixels[Round((x * ct + y) * ccst),
Round((y * ct - x) * ccst)];
If you wanted to speed it up, and didn't care about accumulated round-off
error, you could realize that since you're moving a pixel at a time, the
distance between pixels in the u,v map is constant as you move across the
row, and again as you move down the column. I'll use the calculated
variables above as shorthand. Just plug in (x,y) = (1,0) and (x,y) = (0,1)
in the equation above to get:
duCol := ct * ccst;
dvCol := -ccst;
duRow := ccst;
dvRow := ct * ccst;
uStart := 0;
vStart := 0;
for x := 0 to width do
begin
u := uStart;
v := vStart;
for y := 0 to height do
begin
dest.pixels[x,y] := source.pixels[Round(u), Round(v)];
u := u + rowdu;
v := v + rowdv;
end;
uStart := uStart + duCol;
vStart := vStart + dvCol;
end;
All code provided as-is and without warranty!
If you're adventurous and want to try rotation around an arbitrary point,
try solving these for u and v:
Xp, Yp (X-sub-p, Y-sub-p) is the pivot point
others defined as above
x = Xp + (u - Xp) * cos(t) - (y - Yp) * sin(t)
y = Yp + (y - Yp) * cos(t) - (x - Xp) * sin(t)
A:
The original equations:
x = u * cos(t) - v * sin(t)
y = v * cos(t) + u * sin(t)
are correct but when I solve for u and v, I get this:
x * cos(t) + y * sin(t)
u = -----------------------
sqr(cos(t)) + sqr(sin(t))
y * cos(t) - x * sin(t)
v = ------------------------
sqr(cos(t)) + sqr(sin(t))
Lasso control
Question
Does anybody know how to implement a lasso (selecting many controls by
dragging the mouse over them) in Delphi?
Answer
A:
Here's a possible approach...
1. In the OnMouseDown event for the form that you are 'lasso-ing' controls on:
bMarquee := True; { set a boolean so that you can
differentiate between decisions that
might have to be made during other
mouse events }
ptOrigin := Point( X, Y ); { get the starting point of the marquee }
ptMove := Point( X, Y ); { initialize the stopping point }
set the pen and brush attributes here or by calling a common procedure
that can be reused elsewhere in the Unit.
Pen.Color := clBlack;
Pen.Width := 1;
Pen.Style := psDash;
Brush.Style := bsClear;
then draw the marquee rect
DrawMarquee(ptOrigin, ptMove, pmNotXor );
2. In the OnMouseMove event for the form...
if bMarquee = True then begin
DrawMarquee(ptOrigin, ptMove, pmNotXor );
DrawMarquee(ptOrigin, Point( X, Y ), pmNotXor );
ptMove := Point( X, Y );
Canvas.Pen.Mode := pmCopy;
end;
3. In the OnMouseUp event for the form...
if bMarquee = True then begin
bMarquee := False;
DrawMarquee(ptOrigin, Point( X, Y ), pmNotXor );
ptMove := Point( X, Y );
{ check for any intersections between the marquee frame and controls }
- call the procedure that will highlight ( focus ) the desired controls
end;
The DrawMarquee procedure...
procedure myForm.DrawMarquee( mStart, mStop : TPoint; AMode : TPenMode);
begin
Canvas.Pen.Mode := AMode;
Canvas.Rectangle( mStart.X, mStart.Y, mStop.X, mStop.Y );
end;
TOutline icons
Question
Is it possible to individually specify the icons displayed in a TOutline
component?
Answer
A:
It is possible, but its not necessarily easy. To do it you need to use an
"Owner Draw" outline. In the Outline's OnDrawItem event you'll need to
paint your bitmap and then the text. That parts pretty easy, but you have
to deal with indention, drawing the tree, etc. Plus there are a couple of
bugs/unexpected behaviors that get in the way.
Here's a snippet of code from an OnDrawItem handler that draws a bitmap
followed by the outline item text. The code for handling the bitmap could
probably be improved because I haven't had much experience with Windows
graphics. In case its not obvious olnOutline is my outline and bmpBitMap is
the bitmap.
{Get outline index. The DrawItem Index param is simply the number of the row
being dran and does not take into account collapsed nodes }
lIndex := GetItem(Rect.Left, Rect.Top);
Offset := 2; {Determines spacing between bitmap and text}
with olnOutline do
begin
with Canvas do
begin
{Indent the bitmap based on the Level of the OutlineNode}
Inc(Rect.Left, Offset + (ItemHeight * (Items[lIndex].Level -1)));
{Copy the bitmap }
BrushCopy(Bounds(Rect.Left, Rect.Top, bmpBitMap.Width, bmpBitMap.Height),
bmpBitMap, Bounds(0, 0, bmpBitMap.Height, bmpBitMap.Width),
bmpBitMap.TransparentColor);
{Draw the text to the right of the bitmap}
Inc(Rect.Left,bmpBitMap.Width + Offset);
TextOut(Rect.Left, Rect.Top, Items[lIndex].Text);
end; {with Canvas}
end; {with Outline}
Notes:
This snippet is from a larger block of code and I tried to trim out the
uneccesary junk, but it won't work without a little modification.
There is a problem with Outline's redrawing if you change the width of the
Outline at runtime. I think it only happens when the horizontal scrollbar
is disabled. Anyway, the problem is that the Rect passed to the OnDrawItem
event is the width before you resized the Outline. You could get around
this by using the Outline's width to set the right side of the Rect rather
than using the value supplied by Delphi.
This code DOES NOT draw the tree. I kept thinking I'd steal the code from
the VCL source, but it wasn't needed for this application so I never go to
it. Really wish the tree drawing routine was accessible, but it's not.
Drawing Graphs
Question
I tryed to use ChartFX to plot a function but I have not found
a lot of documentation on it. Does anybody know where I can get
more information? Do you have an example where you plot a trigo
function between 0 and 2*Pi?
Answer
A:
You could use a TCanvas object to draw the function yourself.
A TImage component would be good to use, as it's bitmap contains
a canvas that you can draw on.
eg: (Create a new form, add an Image and a Button. Attach this code
to the button)
var
x,l: Integer;
y,a: Double;
begin
Image1.Picture.Bitmap := TBitmap.Create;
Image1.Picture.Bitmap.Width := Image1.Width;
Image1.Picture.Bitmap.Height := Image1.Height; {These three lines could
go in Form1.Create instead}
l := Image1.Picture.Bitmap.Width;
for x := 0 to l do
begin
a := (x/l) * 2 * Pi; {Convert position on X to angle between 0 & 2Pi}
y := Sin(a); {Your function would go here}
y := y * (Image1.Picture.Bitmap.Height / 2); {Scale Y so it fits}
y := y * -1; {Invert Y, the screen top is 0 !}
y := y + (Image1.Picture.Bitmap.Height / 2); {Add offset for middle 0}
Image1.Picture.Bitmap.Canvas.Pixels[Trunc(x), Trunc(y)] := clBlack;
end;
end;
A:
I've found the best way is to draw directly onto the canvas. Preferably in a
separate procedure taking a TCanvas and a TRect as parameters. That way you
can pass your window's canvas and client rect as parameters for drawing on
screen and the printer's canvas and a rect comprising of the area where
you wan't it to be positioned to print. Look at the canvasses methods to
get the available drawing routines.
A:
You could use a TCanvas object to draw the function yourself.
A TImage component would be good to use, as it's bitmap contains
a canvas that you can draw on.
eg: (Create a new form, add an Image and a Button. Attach this code
to the button)
var
x,l: Integer;
y,a: Double;
begin
Image1.Picture.Bitmap := TBitmap.Create;
Image1.Picture.Bitmap.Width := Image1.Width;
Image1.Picture.Bitmap.Height := Image1.Height; {These three lines could
go in Form1.Create instead}
l := Image1.Picture.Bitmap.Width;
for x := 0 to l do
begin
a := (x/l) * 2 * Pi; {Convert position on X to angle between 0 & 2Pi}
y := Sin(a); {Your function would go here}
y := y * (Image1.Picture.Bitmap.Height / 2); {Scale Y so it fits}
y := y * -1; {Invert Y, the screen top is 0 !}
y := y + (Image1.Picture.Bitmap.Height / 2); {Add offset for middle 0}
Image1.Picture.Bitmap.Canvas.Pixels[Trunc(x), Trunc(y)] := clBlack;
end;
end;
TGraphicComponent child
Question
But, as you may already know, my question is: How can i manage to get the
MouseDown event occur *only* when my routine - that checks for this (the
point being into the shape) - returns TRUE to the points given?
Answer
A:
You can't. However, you can restrict any event handlers attached to it, and
you can make sure that click doesn't get called. I take it you want an
OnClick event that takes into account your triangular shape? Not a problem.
Oh, and just to address one of your other replies, it's not neccesary to
trap the windows messages, as TGraphicControl already does trap most (or all,
not sure) of them.
Now, I'm sure there's a couple of ways to do this, and this is the way I'd
do do it, and it will work, but keep in mind I have no VCL source so this is
probably a bit awkward.
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer)
; override;
procedure TThing.MouseDown...
begin
{Not the mouse coordinates in some private property}
inherited MouseDown...
end;
procedure TThing.Click
begin
if YourHitTest(X,Y) then
inherited Click;
end;
I'm a bit dubious about that last procedure, but it will work. I'm sure
there's some better documented people here who can come up with a more
elegant solution.
Converting Icons to Glyphs
Question
I need to convert Icons(.ICO) into Bitmaps(.BMP) for use in Glyphs at
run-time. I have seen an application to do this but it didn't come with
source code. Does anyone know an easy way to do this? I would prefer a
short code segment but a VCL component would also be an option.
Answer
This is a small example with how to load an icon contained in a
file EXE in a Glyph of an SpeedButton and as cleaning the Glyph.
Sorry but the commentaries of the code source are in Spanish.
*****************************************
unit Procs;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, StdCtrls, Buttons, ExtCtrls, ShellAPI;
procedure LlenaBoton(boton: TSpeedButton; Programa: string);
procedure LimpiaBoton(boton: TSpeedButton);
var
{Botones de programas}
Pic: TPicture;
Fname : String;
TempFile: array[0..255] of Char;
Icon : TIcon;
implementation
uses ttotro;
procedure LlenaBoton(boton: TSpeedButton; Programa: string);
var
NumFiles, NameLength : integer;
nIconsInFile : word;
rBoton : TRect;
oBitmap : TBitmap;
oBitmap2: TBitmap;
NombreBitmap: string;
begin
try
screen.cursor := crHourglass;
{Extrae el Icono}
Icon := TIcon.Create;
StrPCopy(TempFile, Programa);
Icon.Handle := ExtractIcon(HInstance, TempFile, 0);
{Crea una instancia de TPicture}
Pic := TPicture.Create;
{Asigna el icon.handle a la propiedad Pic.icon}
Pic.Icon := Icon;
{Configura el tamano del bitmap como el del icono y el del segundo
bitmap con el tamano del boton}
oBitmap := TBitMap.create;
oBitmap2 := TBitMap.create;
oBitmap2.Width := Icon.Width;
oBitmap2.Height := Icon.Height;
oBitmap.Width := boton.Width-4;
oBitmap.Height := boton.Height-4;
{ Dibuja el icono en el bitmap }
oBitmap2.Canvas.Draw( 0, 0, Pic.Graphic );
rBoton.left := 1;
rBoton.Top := 1;
rBoton.right:= boton.Width-6;
rBoton.Bottom := boton.Height-6;
oBitmap.Canvas.StretchDraw(rBoton, oBitmap2);
Boton.Hint := Programa;
NombreBitmap := Copy(programa, 1, Length(programa)-3)+'BMP';
{Salva el bitmap en un fichero}
If Not FileExists(NombreBitmap) Then
begin
oBitmap.SaveToFile(ExtractFilePath(Application.ExeName)+ExtractFileName(NombreBitmap));
Boton.Glyph := oBitmap;
end
else
{Carga el BMP en el boton}
Boton.Glyph.LoadFromFile(ExtractFilePath(Application.ExeName)+ExtractFileName(NombreBitmap));
finally
Icon.Free;
oBitmap.Free;
oBitmap2.Free;
screen.cursor := crDefault;
end; {main begin}
end; {llenaboton}
procedure LimpiaBoton(boton: TSpeedButton);
var
oBitmap : TBitmap;
rBoton : TRect;
begin
try
{Configuara el tamano del bitmap como el del icono y el del segundo
bitmap con el tamano del boton}
oBitmap := TBitMap.create;
oBitmap.Width := boton.Width-4;
oBitmap.Height := boton.Height-4;
Boton.Glyph := oBitmap;
finally
oBitmap.Free;
end; {main begin}
end; {limpiaboton}
end.
Delphi Graphics
Question
I have a project to develop a small video format....
I've done some tests with Delphi and it takes approx. 4 seconds for it
to fill a 250 x 250 bitmap, one pixel at a time...this is obviously
too slow...there has to be other ways to do it.
Answer
If you are simply trying to display one image in a resonable amount
of time, create a TBitmap object, play around with it, and then when
you are ready to display it to the screen, call
Image.Canvas.Draw(0, 0, Bitmap) to copy it and draw it to the screen.
You see, the main time consumer is the painting of the screen, not in
the setting of the Image's attributes. As a result, you want to set the
pixel's colors in a non-visible object (the TBitmap you created), and
then display the whole Bitmap at once. Here is some code for a form
with a single Image component on it:
procedure TForm1.FormPaint(Sender: TObject);
Var
TmpX, TmpY : Byte;
MyImage : TBitmap;
begin
Form1.Width := 260; Form1.Height := 260;
Image1.Width := 250; Image1.Height := 250;
Image1.top := 5; Image1.width := 5;
MyImage := TBitmap.Create;
MyImage.Width := 250; MyImage.Height := 250;
FOR TmpX := 0 TO 249 DO
FOR TmpY := 0 TO 249 DO
MyImage.Canvas.Pixels[TmpX,TmpY] :=
RGB(TmpX, 250 - TmpY, (TmpX + TmpY DIV 2));
Image1.Canvas.Draw(0, 0, MyImage);
MyImage.Free;
end;
If you want to do really fast graphics, look into the GDI (API)
functions and/or the WinG functions given out by Microsoft. These
are a bit tedious to learn and use, and they are outside of Delphi's
domain.
Image resizing and displaying
Question
I've placed a TImage in a ScrollBox, and in my paint routine I have it
adjust the size of the Image component based on a zoom factor, then paint
the Image.
The scroll box reacts correctly to the changes in size, however the TImage
only paints the area corresponding to my 100% size when going to bigger zoom
factors (i.e. 200%). So my image is chopped off, but like I said, the
scrollbox is doing everything correctly. I've checked the height and width
properties of the image at run time, and everything is fine there, so I
can't understand what's happening.
Answer
A:
The size of the bitmap you have attached to the picture.graphic property
matters also. If you size the image contorl to say 320x200, but the bitmap
is only sized to 160x100 then all you'll be left with is that gray area
around the picture, unless you have the stretch property set to true.
Here's a quick way around this.
procedure TForm.ZoomImage;
var Bitmap: TBitmap;
DstRect: TRect;
begin
{ Here you want to set up a new bitmap with the proper proportions for your
zoom factor and draw the image you want zoomed into it. }
Bitmap := TBitmap.Create;
Bitmap.Width := { insert your zoomed width here }
Bitmap.Height := { insert your zoomed height here}
Bitmap.Canvas.StretchDraw(Bitmap.Canvas.ClipRect,{insert the image you
you want zoomed here});
{ Here you assign the new bitmap to the graphic property of the image box.
The image box will automatically dispose of the resources used by its
prior image. }
Image1.Picture.Graphic := Bitmap;
Image1.Invalidate;
end;
That should work, or at least give you an idea of how to implement what you
want. I just wrote this OTTOMH so no flames if I forgot something please.
Keep in mind that you don't need to do this in the onPaint event. I also
like the fact that the image box is smart enough to dispose of the old
bitmap when you assign it a new one. Incidently I think if you use the
Assign method instead of implicity assigning the bitmap you'll end up with a
copy of the new bitmap instead of actually having the image box use the one
just created.. You'll have to dispose of the new one then at the end of the
procedure.
A:
The solution to problem was to adjust the TImage.Picture.Bitmap.Width and
the TImage.Picture.Bitmap.Height properties.
How to dim the colors of a glyph in a button
Question
However, for various reasons, I can't create the 2,3,4 glyphs in a bitmap.
I just need to use the 1 glyph in 1 bitmap and dim the color at run-time
- maybe using some calculations to reduce the color value..... or something.
Answer
A:
The best way is still to create more than one glyph in a bitmap, if
you're stuck on this one, try loading one of the provided sample
button glyphs into image editor, to see how it's done...
I presume though, that you probably have a TBitmap that you
dynamically assign to the bitmap at runtime. To generate a dimmed
glyph, you could draw black pixels on every alternate square, like
those on a chessboard. I think this is the way that 95 generates it's
dimmed screen when asking if a shutdown is needed. Your code to draw
a pixel onto the glyph would probably look something like this:
BitBtn1.Glyph.Canvas.Pixels[0,0] := clBlack;
and in a loop:
for i := 1 to BitBtn1.Height do
for j := 1 to BitBtn1.Width do
begin
if (Trunc(j/2)*2) = j then BitBtn1.Glyph.Canvas.Pixels[j,
Trunc(Frac(i/2)*2)] := clBlack;
end;
How Can I Make These Graphics Faster?
Question
How might I only draw to a specific part of the screen and only have that
portion repainted, instead of the entire bitmap repainted? Just having a
16 x 16 portion of the bitmap would be speed demons quicker than repainting
the entire 416 x 216 bitmap...
Answer
A:
Here is a VCL-only method of doing it; see if this
helps. The BitBlt is handled by CopyRect.
var
BitMap : TBitmap;
procedure TForm1.FormCreate(Sender: TObject);
begin
Bitmap := TBitmap.Create;
Bitmap.Width := 400;
Bitmap.Height := 400;
PaintBox1.Width := 200;
PaintBox1.Height := 200;
With Bitmap.Canvas do
begin
Pen.Color := clNavy;
Ellipse(0,0,399,399);
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
Bitmap.Free;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Limit : Word;
I : Word;
PBBottom, PBRight : Word;
begin
PBBottom := PaintBox1.Height - 1;
PBRight := PaintBox1.Width - 1;
Limit := Bitmap.Width - PaintBox1.Width;
For I := 0 to Limit do
PaintBox1.Canvas.CopyRect(Rect(0,0,PBRight,PBBottom),
Bitmap.Canvas, Rect(I,0,I+PBRight,PBBottom));
end;
Make mouse snap to grid while drawing
Question
Can anyone tell me where to start....
How do make "snap to grid" -procedure for OnMouseMove -event (or for any
event)(like in programs like Designer, AutoCAD etc.)
Answer
A:
1. Declare two variables to hold the user-desired grid sizes:
nGridWidth : Integer;
nGridHeight : Integer;
2. If bSnapToGrid then
2a. calculate the closest point in the grid to the current
x, y in the OnMouseUp event handler.
3. Place the drawing component (left, top) at this position.
Give the user a method for setting their own grid preferences.
Graph to clipboard
Question
I'm having a problem trying to copy a graph to the clipboard. I have the
following code:
TGraph1.refresh;
TGraph1.CopyBitmap := 0;
The problem is that the graph is distorted with a portion of another window
from a different program. Is there a way to verify when the bitmap is
copied. It appears not to do the actual copy until there's some kind of
screen change.
Answer
A:
According to the online help, the CopyBitMap is a method of Chart control. I've
never used it. I have a routine to copy a bitmap to clipboard though. Actually
it copies the whole contents of a Window to the clipboard, memos and all !
Var
Image : TImage;
BitMap : TBitmap;
Begin
Image:=TImage.Create(Self);
BitMap:=TBitMap.Create;
BitMap.Width:=ClientWidth;
BitMap.Height:=ClientHeight;
BitBlt(BitMap.Canvas.Handle, 0, 0, ClientWidth, ClientHeight, GetDC(Handle),
0, 0, SRCCOPY);
Image.Picture.Graphic:=BitMap;
Clipboard.Assign(Image.Picture);
BitMap.Free;
Image.Free
End;
No guarantees about efficiency, pictures, graphics, & bitmaps still confuse me,
but it works ! If you only want a bitmap from a window, you change the
GetDC(Handle) to Bitmap.Handle.
Icons loaded and converted for TBitBtn no white
Question
I don't think this is the problem - as I said if I load it into an image, it
works - the transparent parts are - and the white parts are white - when I
put them on a button though, all white becomes transparent!
Answer
A:
If you load an icon into a TImage, it "understands" icons and displays
transparency info accordingly. Icons actually contain two bitmaps, one
containing the normal color info, with white areas to represent where
transparency should go; then a second "mask" bitmap that also has white for
the transparent areas, and black for the colored areas. When the two are
"xored" together with the background, the white on white areas show the
background through, the color (including white) on black areas show the color
of the icon; (you can also get "inverted background" areas in an icon by
having areas that are black in the colored bitmap but are white on the mask).
When you convert the icon to a bitmap, the transparency info is lost
because bitmaps don't have the built-in capacity for storing this extra
mask bitmap that is used to make transparent parts. I'd guess the icons
you're using are generally "free standing" objects with transparent
backgrounds, that means that the color bitmap is surrounded in white.
So, when you load one into a TBitbutton or TSpeedbutton's glyph
property, the lowerleft corner color (which will be white in these
cases) now gets interpreted as transparent, giving the effect you
describe.
The solution is to convert the icon to a bitmap and save it as a .BMP
file, then edit it with ImageEdit, Resource Workshop, or even PaintBrush
and use an otherwise unused color as the lower left pixel and anywhere
else you WANT to be transparent. Otherwise, I have some code that
extracts the color and mask bitmaps from an icon, you could then use
these to write out a bitmap that has the appropritate pixels set to an
unused color, though finding that unused color might be a bit tedious
programatically; hmmm, I'm smelling a utility here, I may have to get to
work on this.
Transparent Forms and Bitmaps
Question
Anyone know how to make a form transparent? Also make a bitmap
background transparent in Delphi?
Answer
A:
Here's a nice routine to draw a transparent bitmap onto another.
{This procedure will draw a source bitmap onto a target bitmap,
leaving information from the taget to shine through where the
pixels in the source are of the specified transparent color.
t = The target canvas to be drawn onto
x,y = The position on the target where source is drawn
s = The source bitmap
TrCol = The color that will become transparent in the source bmp
NOTE: Don't forget to repaint the target, eg Image1.Invalidate}
procedure DrawTransparent(t: TCanvas; x,y: Integer; s: TBitmap; TrCol: TColor);
var
bmpXOR, bmpAND, bmpINVAND, bmpTarget: TBitmap;
oldcol: Longint;
begin
try
bmpAND := TBitmap.Create; bmpAND.Width := s.Width; bmpAND.Height := s.Height; bmpAND.Monochrome := True;
oldcol := SetBkColor(s.Canvas.Handle, ColorToRGB(TrCol));
BitBlt(bmpAND.Canvas.Handle, 0,0,s.Width,s.Height, s.Canvas.Handle, 0,0, SRCCOPY);
SetBkColor(s.Canvas.Handle, oldcol);
bmpINVAND := TBitmap.Create; bmpINVAND.Width := s.Width; bmpINVAND.Height := s.Height; bmpINVAND.Monochrome := True;
BitBlt(bmpINVAND.Canvas.Handle, 0,0,s.Width,s.Height, bmpAND.Canvas.Handle, 0,0, NOTSRCCOPY);
bmpXOR := TBitmap.Create; bmpXOR.Width := s.Width; bmpXOR.Height := s.Height;
BitBlt(bmpXOR.Canvas.Handle, 0,0,s.Width,s.Height, s.Canvas.Handle, 0,0, SRCCOPY);
BitBlt(bmpXOR.Canvas.Handle, 0,0,s.Width,s.Height, bmpINVAND.Canvas.Handle, 0,0, SRCAND);
bmpTarget := TBitmap.Create; bmpTarget.Width := s.Width; bmpTarget.Height := s.Height;
BitBlt(bmpTarget.Canvas.Handle, 0,0,s.Width,s.Height, t.Handle, x,y, SRCCOPY);
BitBlt(bmpTarget.Canvas.Handle, 0,0,s.Width,s.Height, bmpAND.Canvas.Handle, 0,0, SRCAND);
BitBlt(bmpTarget.Canvas.Handle, 0,0,s.Width,s.Height, bmpXOR.Canvas.Handle, 0,0, SRCINVERT);
BitBlt(t.Handle, x,y,s.Width,s.Height, bmpTarget.Canvas.Handle, 0,0, SRCCOPY);
finally
bmpXOR.Free;
bmpAND.Free;
bmpINVAND.Free;
bmpTarget.Free;
end;{End of TRY section}
end;
From Sizes on different platforms
Question
I am trying to make my app work on screen sizes eg. 640x480 &
1024x768 I have tried changing the pixels per inch property but
it doesn't seem to work.
Answer
A:
The following should help make your forms look correct at different
resolutions:
a.) Set Autoscroll to' FALSE'. True means don't change the form's frame size
at run time.
b.) Set the font to a TrueType like Arial, don't leave it at the default
'SYSTEM''
c.) Set Position to something other than poDesigned, this will leave it where
you left it on your 1280x780 screen which maybe barely visible at 640x480.
d.) Change Pitch property of the font from DEFAULT to VARIABLE
e.) DON'T CHANGE THE PixelsPerInch PROPERTY.
f.) Set the Scaled Property to TRUE. This scales the forms to the value of
the PixelsPerInch property.
Fast way to Clear a TCanvas
Question
Is there a TCanvas.Clear, or, what is the best way to clear a TCanvas?
Answer
A:
InValidateRect(Canvas.handle,NIL,True);
A:
If you are using a Form's canvas try
InValidateRect(form1.handle,NIL,True);
instead.
(or the components handle)
A:
This will clear a canvas:
canvas.fillrect(canvas.cliprect) ;
Assign a palette to a bitmap
Question
I use a resource file to load (256 colour) bitmaps into my application.
At 65.000 colours this is no problem. When i switch my screen to 256 colours
the palette of the bitmap becomes very weird.
If i place a timage component on the form and do a loadfromfile then the
palette is correct.
So the problem is that the palette won't update when i draw an image
with ' canvas.draw(0,0,bitmap1) ' where bitmap1 is a tbitmap.
Does anybody on the list know a answer to this problem!?
Answer
A:
If you are drawing on a TImage....
First you need to use the Image1.Picture.bitmap not the Image.Canvas.
The reason is the the Image1.Picture.Bitmap has a palette -Timage doesn't.
Then you need to assign the palette. For example:
//Set Width and Height before using Image1.Picture Bitmap's Canvas
var
Bitmap: TBitmap;
begin
Bitmap:=TBitmap.Create;
Bitmap.LoadfromFile({'Whatever.bmp'});
With Image2.Picture.bitmap do
Begin
Width:=Bitmap.Width;
height:=Bitmap.Height;
Palette:=Bitmap.Palette;
Canvas.draw(0,0,bitmap);
Refresh;
end;
end;
If you are drawing on the Form's Canvas ...
Canvas.Draw(0,0,Bitmap);
SelectPalette(Form1.Canvas.handle,Bitmap.Palette,True);
RealizePalette(Form1.Canvas.Handle);
Transparent bitmap brush
Question
Answer
A:
The following unit draws two bitmaps on a form. One is used
as the background, and the second one as the foreground. The
foreground bitmap is displayed as a "transparent" bitmap.
Read the comments for a complete (well sort of) explanation.
{ Purpose: Display a transparent bitmap loaded from a file
Author: Michael Vincze (vincze@ti.com)
Date: 04/20/95
Usage: Create a blank form, named Form1, compile and run.
Limits: This unit has been tested for both 16 and 256 color bitmaps.
It is assumed that the lower left pixel of the bitmap represents
the transparent color.
Notes: If this file is to be used for any purpose please leave
this header intact and give credit to the author if used for
any purpose.
Please contact the author if any improvements are made.
The author stakes no claim for this programs usefullness
or purpose.
Version: 1.00 04/20/95 Initial creation
}
unit Tbmpu;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, ExtCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
ImageForeGround: TImage;
ImageBackGround: TImage;
public
{ Public declarations }
end;
procedure DrawTransparentBitmap (ahdc: HDC;
Image: TImage;
xStart, yStart: Word);
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure DrawTransparentBitmap (ahdc: HDC;
Image: TImage;
xStart, yStart: Word);
var
TransparentColor: TColor;
cColor : TColorRef;
bmAndBack,
bmAndObject,
bmAndMem,
bmSave,
bmBackOld,
bmObjectOld,
bmMemOld,
bmSaveOld : HBitmap;
hdcMem,
hdcBack,
hdcObject,
hdcTemp,
hdcSave : HDC;
ptSize : TPoint;
begin
{ set the transparent color to be the lower left pixel of the bitmap
}
TransparentColor := Image.Picture.Bitmap.Canvas.Pixels[0,
Image.Height - 1];
TransparentColor := TransparentColor or $02000000;
hdcTemp := CreateCompatibleDC (ahdc);
SelectObject (hdcTemp, Image.Picture.Bitmap.Handle); { select the bitmap }
{ convert bitmap dimensions from device to logical points
}
ptSize.x := Image.Width;
ptSize.y := Image.Height;
DPtoLP (hdcTemp, ptSize, 1); { convert from device logical points }
{ create some DCs to hold temporary data
}
hdcBack := CreateCompatibleDC(ahdc);
hdcObject := CreateCompatibleDC(ahdc);
hdcMem := CreateCompatibleDC(ahdc);
hdcSave := CreateCompatibleDC(ahdc);
{ create a bitmap for each DC
}
{ monochrome DC
}
bmAndBack := CreateBitmap (ptSize.x, ptSize.y, 1, 1, nil);
bmAndObject := CreateBitmap (ptSize.x, ptSize.y, 1, 1, nil);
bmAndMem := CreateCompatibleBitmap (ahdc, ptSize.x, ptSize.y);
bmSave := CreateCompatibleBitmap (ahdc, ptSize.x, ptSize.y);
{ each DC must select a bitmap object to store pixel data
}
bmBackOld := SelectObject (hdcBack, bmAndBack);
bmObjectOld := SelectObject (hdcObject, bmAndObject);
bmMemOld := SelectObject (hdcMem, bmAndMem);
bmSaveOld := SelectObject (hdcSave, bmSave);
{ set proper mapping mode
}
SetMapMode (hdcTemp, GetMapMode (ahdc));
{ save the bitmap sent here, because it will be overwritten
}
BitBlt (hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
{ set the background color of the source DC to the color.
contained in the parts of the bitmap that should be transparent
}
cColor := SetBkColor (hdcTemp, TransparentColor);
{ create the object mask for the bitmap by performing a BitBlt()
from the source bitmap to a monochrome bitmap
}
BitBlt (hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
{ set the background color of the source DC back to the original color
}
SetBkColor (hdcTemp, cColor);
{ create the inverse of the object mask
}
BitBlt (hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
{ copy the background of the main DC to the destination
}
BitBlt (hdcMem, 0, 0, ptSize.x, ptSize.y, ahdc, xStart, yStart, SRCCOPY);
{ mask out the places where the bitmap will be placed
}
BitBlt (hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
{ mask out the transparent colored pixels on the bitmap
}
BitBlt (hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
{ XOR the bitmap with the background on the destination DC
}
BitBlt (hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
{ copy the destination to the screen
}
BitBlt (ahdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
{ place the original bitmap back into the bitmap sent here
}
BitBlt (hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
{ delete the memory bitmaps
}
DeleteObject (SelectObject (hdcBack, bmBackOld));
DeleteObject (SelectObject (hdcObject, bmObjectOld));
DeleteObject (SelectObject (hdcMem, bmMemOld));
DeleteObject (SelectObject (hdcSave, bmSaveOld));
{ delete the memory DCs
}
DeleteDC (hdcMem);
DeleteDC (hdcBack);
DeleteDC (hdcObject);
DeleteDC (hdcSave);
DeleteDC (hdcTemp);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
{ create image controls for two bitmaps and set their parents
}
ImageForeGround := TImage.Create (Form1);
ImageForeGround.Parent := Form1;
ImageBackGround := TImage.Create (Form1);
ImageBackGround.Parent := Form1;
{ load images
}
ImageBackGround.Picture.LoadFromFile ('c:\delphi\images\splash\16color\earth.bmp');
ImageForeGround.Picture.LoadFromFile ('c:\delphi\images\splash\16color\athena.bmp');
{ set background image size to its bitmap dimensions
}
with ImageBackGround do
begin
Left := 0;
Top := 0;
Width := Picture.Width;
Height := Picture.Height;
end;
{ set the foreground image size centered in the background image
}
with ImageForeGround do
begin
Left := (ImageBackGround.Picture.Width - Picture.Width) div 2;
Top := (ImageBackGround.Picture.Height - Picture.Height) div 2;
Width := Picture.Width;
Height := Picture.Height;
end;
{ do not show the transparent bitmap as it will be displayed (BitBlt()ed)
by the DrawTransparentBitmap() function
}
ImageForeGround.Visible := False;
{ draw the tranparent bitmap
note how the DC of the foreground is used in the function below
}
DrawTransparentBitmap (ImageBackGround.Picture.Bitmap.Canvas.Handle, {HDC}
ImageForeGround, {TImage}
ImageForeGround.Left, {X}
ImageForeGround.Top {Y} );
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
{ free images
}
ImageForeGround.Free;
ImageBackGround.Free;
end;
end.
Removing TBitMap from TBitBtn
Question
Is there a way to remove a bitmap from a TBitBtn?
Answer
I would try this:
Glyph.free;
Glyph := nil;
At the point where you want to get rid of the bitmap. Not sure it works,
but worth a try.
One draw directly onto the screen (not the form)
Question
Copying the pre-screensaver screen contents to the maximized screensaver-
form, and then slowly changing the contents of the form, creating the
illusion that the screen itself is changing.
The problem then is: how can I read the pixels of the displayed (complete)
screen directly?
Answer
A:
Create a form, drop a TImage control to the form, make it a decent size,
and drop a button on it. DblClick the button and add the following code.
Var
ScreenDC : HDC;
begin
ScreenDC:=CreateDC('DISPLAY',nil,nil,nil);
BitBlt(Image1.Canvas.Handle, 0,0, Image1.Width, Image1.Height,
ScreenDC, 0,0, SRCCOPY);
Image1.Refresh;
DeleteDC(ScreenDC);
end;
That will copy the desktop into the Image Control. Play around with the
0,0 near the ScreenDC to move the TopLeft of the image to want to
capture. Move your form around and click the button, Look up BitBlt in
the help file it might explain some things.
You could just as easily create a memory bitmap
Var
ScreenDC : HDC;
fBitmap : TBitmap;
begin
fBitmap := TBitmap.Create;
fBitmap.Width := 100;
fBitmap.Height := 100;
ScreenDC:=CreateDC('DISPLAY',nil,nil,nil);
BitBlt(FBitmap.Canvas.Handle, 0,0, FBitmap.Width, FBitmap.Height,
ScreenDC, 0,0, SRCCOPY);
{ You now have a copy of the screen from (0,0,100,100) in the
fBitmap, you now can }
{ do what you want to it, merge it with another bitmap?, or anything
else you want to. }
{ Clean Up }
DeleteDC(ScreenDC);
fBitmap.Free
end;
Bitmap Transparency
Question
I was wondering if anyone knows the steps in achieving a transparent bitmap
effect? Someone told me that I had to deal with 2 bitmaps, a mask and
something else, but I have no clue how that works.
Answer
You do need two copies of the bitmap. The mask and the image. The mask is
nothing more than a bitmap with two colors. Black for the areas you want to
show and white for transparent areas. For Windows 3.1 this can be a
monochrome bitmap to keep the size down. For Win95 a monochrome will not
work under all circumstances so it should have the same depth as the picture
you are going to show.
The picture you want to display has to have the transparent areas done in
color 0. Putting the picture on the screen is the same method used under
DOS. The mask is ANDed to the screen, then the picture is ORed or XORed to
the same place.
Below is the Delphi code to do this using two TBitmaps.
Canvas.CopyMode := cmSrcAnd;
Canvas.CopyRect(TitleRect, BMask.Canvas, TitleRect);
{fill the hole with the picture}
Canvas.CopyMode := cmSrcPaint;
Canvas.CopyRect(TitleRect, BTitle.Canvas, TitleRect);
|