Witam i mam nadzieję, że znajdzie się paru zwolenników, którzy są gotowi pomóc :)
Otóż, chcę uzyskać taki efektowny balon.
CEL:
W chwili obecnej zastosowałem taki oto sposób.
Kod odpowiedzialny tworzenie komponentu:
{
BalloonHint MultiLine
}
unit Balloon;
interface
uses
Forms, Classes, Controls, StdCtrls, ExtCtrls, Windows, Graphics,
Messages, SysUtils, Dialogs;
type
TBalonTekst = array[1..11] of record
Temat: string[70];
Tresc: string[25];
Stan: string[10];
Typ: string[11];
end;
type
TBalon = class(TCustomForm)
private
procedure FormPaint(Sender: TObject);
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure OnChange(Sender: TObject);
procedure WndProc(var message: TMessage); override;
public
BalonCzas: Byte;
BalonLeft: SmallInt;
BalonTop: SmallInt;
constructor CreateNew(AOwner: TComponent; Dummy: Integer = 0); override;
destructor Destroy; override;
procedure ShowBalon;
procedure HideBalon;
end;
implementation
procedure TBalon.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := (Params.Style and not WS_CAPTION) or WS_POPUP;
Params.ExStyle := Params.ExStyle or WS_EX_TOOLWINDOW or WS_EX_NOACTIVATE or WS_EX_TOPMOST;
Params.WndParent := GetDesktopWindow;
end;
procedure TBalon.OnChange(Sender: TObject);
begin
SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
end;
procedure TBalon.WndProc(var message: TMessage);
begin
if (message.Msg = WM_SIZE) and (message.WParam = SIZE_MINIMIZED) then Show;
inherited;
end;
constructor TBalon.CreateNew(AOwner: TComponent; Dummy: Integer = 0);
begin
inherited;
BorderStyle := bsNone;
AlphaBlend := False;
AlphaBlendValue := 230;
FormStyle := fsStayOnTop;
OnPaint := FormPaint;
Font.Name := 'Tahoma';
end;
destructor TBalon.Destroy;
begin
inherited;
end;
Następnie kod odpowiedzialny za rozmycie i ściemnianie
{Odpowiada za wizualizację ściemniania}
function IntToByte(i: Integer): Byte;
begin
if i > 255 then Result := 255
else
if i < 0 then Result := 0
else Result := i;
end;
{Ściemnienie}
procedure Darkness(Bitmap: TBitmap; Amount: SmallInt);
var
W: ^Byte;
H, V: Integer;
begin
Bitmap.PixelFormat := pf24bit;
for V := 0 to Bitmap.Height-1 do
begin
W := Bitmap.ScanLine[V];
for H := 0 to Bitmap.Width*3-1 do
begin
W^ := IntToByte(W^ - (W^ * Amount) div 255);
Inc(W);
end;
end;
end;
{Rozmycie}
procedure Blur(var Bitmap: TBitmap);
var
TL, TC, TR, BL, BC, BR, LL, LC, LR: ^TRGBTriple;
H, V: Integer;
begin
Bitmap.PixelFormat := pf24bit;
for V := 1 to Bitmap.Height-2 do
begin
TL := Bitmap.ScanLine[V - 1];
TC := TL; // to samo Scanline Bitmap.ScanLine[V - 1]; tylko oszczędniej
TR := TL;
BL := Bitmap.ScanLine[V];
BC := BL;
BR := BL;
LL := Bitmap.ScanLine[V + 1];
LC := LL;
LR := LL;
Inc(TC);
Inc(TR, 2);
Inc(BC);
Inc(BR, 2);
Inc(LC);
Inc(LR, 2);
for H := 1 to Bitmap.Width-2 do
begin
//Wyciągam srednią z 9 sąsiadujących pixeli
BC.rgbtRed := (BC.rgbtRed + BL.rgbtRed + BR.rgbtRed + TC.rgbtRed + TL.rgbtRed + TR.rgbtRed + LL.rgbtRed + LC.rgbtRed + LR.rgbtRed) div 9;
BC.rgbtGreen := (BC.rgbtGreen + BL.rgbtGreen + BR.rgbtGreen + TC.rgbtGreen + TL.rgbtGreen + TR.rgbtGreen + LL.rgbtGreen + LC.rgbtGreen + LR.rgbtGreen) div 9;
BC.rgbtBlue := (BC.rgbtBlue + BL.rgbtBlue + BR.rgbtBlue + TC.rgbtBlue + TL.rgbtBlue + TR.rgbtBlue + LL.rgbtBlue + LC.rgbtBlue + LR.rgbtBlue) div 9;
//Zwiększam wskaźniki biorąc następne 9 pixeli
Inc(TL);
Inc(TC);
Inc(TR);
Inc(BL);
Inc(BC);
Inc(BR);
Inc(LL);
Inc(LC);
Inc(LR);
end;
end;
end;
Następnie procedura Paint
procedure TBalon.FormPaint(Sender: TObject);
var
TempRegion: HRGN;
Dc: HDC;
SourceRect: TRect;
FBackground: TBitmap;
begin
{Kolor tła}
Color := $001F1F1F; {czarny}
{Obwódka balonika - biała}
with Canvas.Brush Do
begin
Color := clWhite;
Style := bsSolid;
end;
{Malowanie obwódki}
TempRegion := CreateRectRgn(0, 0, 2, 2);
GetWindowRgn(Handle, TempRegion);
FrameRgn(Canvas.Handle, TempRegion, Canvas.Brush.Handle, 3, 3);
DeleteObject(TempRegion);
{Obwódka balonika - ciemna}
with Canvas.Brush Do
begin
Color := $001F1F1F;
Style := bsSolid;
end;
{Malowanie obwódki}
TempRegion := CreateRectRgn(0, 0, 2, 2);
GetWindowRgn(Handle, TempRegion);
FrameRgn(Canvas.Handle, TempRegion, Canvas.Brush.Handle, 1, 1);
DeleteObject(TempRegion);
{Pobranie screenshota balonika}
FBackground := TBitmap.Create;
with Fbackground do
begin
Width := Balon.Width;
Height := Balon.Height;
end;
SourceRect.TopLeft := ClientToScreen(ClientRect.TopLeft);
SourceRect.BottomRight := ClientToScreen(ClientRect.BottomRight);
{Operacje na screenshocie, rozmycie/ściemnienie}
Dc := CreateDC('DISPLAY', nil, nil, nil);
try
Canvas.Handle := Dc;
Fbackground.Canvas.CopyRect(ClientRect, Canvas, SourceRect);
{Rozmycie}
Blur(Fbackground);
{Ściemnienie}
//Darkness(Fbackground, 70);
finally
DeleteDC(Dc);
end;
{TEMP START}
if Fbackground = nil then ShowMessage('cos nie tak')
else Fbackground.SaveToFile('zrzut.bmp');
{TEMP END}
{Malowanie przetworzonego screenshota na baloniku}
Dc := CreateDC('DISPLAY', nil, nil, nil);
try
Canvas.Handle := Dc;
Canvas.Draw(Left, Top, Fbackground);
finally
FBackground.Free;
DeleteDC(Dc);
end;
end;
I na końcu już samo wyświetlenie balonika
procedure TBalon.ShowBalon;
var
FormRegion, ArrowRegion: HRGN;
Arrow: array [0..2] Of TPoint;
begin
{Szerokość i wysokość balonika}
ClientHeight := 150;
ClientWidth := 300;
{Położenie balonika}
Left := BalonLeft - ClientWidth - 5;
Top := BalonTop - ClientHeight;
{Kształt balonika}
FormRegion := CreateRoundRectRgn(0, 0, ClientWidth, ClientHeight - 24, 16, 16);
{Strzałka wychodząca u dołu balonika}
Arrow[0] := Point((Width div 2) - 25, ClientHeight - 25);
Arrow[1] := Point(Width div 2, ClientHeight);
Arrow[2] := Point((Width div 2) + 25, ClientHeight - 25);
ArrowRegion := CreatePolygonRgn(Arrow, 3, WINDING);
{Operacje na wyglądzie balonika}
CombineRgn(FormRegion, FormRegion, ArrowRegion, RGN_OR);
DeleteObject(ArrowRegion);
SetWindowRgn(Handle, FormRegion, True);
{Pokazanie balonika}
Visible := False;
ShowWindow(Handle, SW_SHOWNOACTIVATE);
Visible := True;
end;
procedure TBalon.HideBalon;
begin
if Visible then Visible := False;
end;
end.
Samo utworzenie balonika bez rozmycia wygląda tak:
Ale chcąc uzyskać efekt doCELowy, musze rozmyć całość... udało mi się to w ten sposób:
Jak widać rozmycie wyszło na całym zrzucie... bo pozostało jeszcze nałożenie tego zrzutu na balonik tak, aby wszystko poza krawędziami usunąć.
DO ZROBIENIA:
- nałożenie rozmycia na balonik tak, aby to co poza balonikiem nie było brane pod uwagę (jak widać na w/w zrzucie)
- cień pod balonikiem
Ktoś chętny aby pomóc ? :)