delphi – 为Image创建一个特殊的视觉选择工具
我想创建一种特殊的选择,其中图像变暗,在用户选择的部分中,显示真实的图像.你可以看到一个例子:
我发现了两种实现方法: >实现显示黑暗图像的控件. 可以,有人告诉我实现这个的正确方向.我认为方法1很难实现,因为它会引起很多闪烁.除非我实现了一种只通过InvalidateRect函数重绘已更改部分的方法. 这是我实现的TScreenEmul类的代码,直到现在.它有效,但它有闪烁. unit ScreenEmul; interface uses Classes,Types,Windows,Messages,Graphics,Controls,SysUtils,Dialogs,ExtCtrls; const PixelCountMax = 32768; type PRGBTripleArray = ^TRGBTripleArray; TRGBTripleArray = array[0..PixelCountMax-1] of TRGBTriple; TScreenEmul = class(TCustomControl) private LastRect,DrawRect: TRect; DrawStart: TPoint; MouseDown: Boolean; Backup,Darken: TBitmap; FBitmap: TBitmap; procedure BitmapChange(Sender: TObject); procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN; procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE; procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP; procedure WMEraseBkgnd(var Message: TWMEraseBkgnd ); message WM_ERASEBKGND; procedure WMPaint(var Message: TWMPaint); message WM_PAINT; procedure DarkenBitmap(B: TBitmap); procedure RestoreImage; procedure CalculateDrawRect(X,Y: Integer); procedure SetBitmap(const Value: TBitmap); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property Bitmap: TBitmap read FBitmap write SetBitmap; end; implementation { TScreenEmul } function AlphaBlend(Color1,Color2: TRGBTriple; Alpha: Byte): TRGBTriple; overload; var rPrimary : Real; // Primary (Color1) Intensity rSecondary: Real;// Secondary (Color2) Intensity begin rPrimary:=((Alpha+1)/$100); rSecondary:=(($100-Alpha)/$100); with Result do begin rgbtBlue := Trunc(Color1.rgbtBlue * rPrimary + Color2.rgbtBlue * rSecondary); rgbtGreen := Trunc(Color1.rgbtGreen * rPrimary + Color2.rgbtGreen * rSecondary); rgbtRed := Trunc(Color1.rgbtRed * rPrimary + Color2.rgbtRed * rSecondary); end; end; procedure TScreenEmul.BitmapChange(Sender: TObject); begin FreeAndNil(Backup); Backup := TBitmap.Create; Backup.Assign(FBitmap); DarkenBitmap(FBitmap); Darken := TBitmap.Create; Darken.Assign(FBitmap); end; procedure TScreenEmul.CalculateDrawRect(X,Y: Integer); begin if X >= DrawStart.X then begin if DrawRect.Left <> DrawStart.X then DrawRect.Left := DrawStart.X; DrawRect.Right := X end else begin if DrawRect.Right <> DrawStart.X then DrawRect.Right := DrawStart.X; DrawRect.Left := X; end; if Y >= DrawStart.Y then begin if DrawRect.Top <> DrawStart.Y then DrawRect.Top := DrawStart.Y; DrawRect.Bottom := Y; end else begin if DrawRect.Bottom <> DrawStart.Y then DrawRect.Bottom := DrawStart.Y; DrawRect.Top := Y; end; end; constructor TScreenEmul.Create(AOwner: TComponent); begin inherited; MouseDown := False; FBitmap := TBitmap.Create; FBitmap.OnChange := BitmapChange; DoubleBuffered := True; end; procedure TScreenEmul.DarkenBitmap(B: TBitmap); var I,J: Integer; Row: PRGBTripleArray; rgbBlack: tagRGBTRIPLE; begin rgbBlack.rgbtBlue := 0; rgbBlack.rgbtGreen := 0; rgbBlack.rgbtRed := 0; for I := 0 to B.Height - 1 do begin Row := B.ScanLine[I]; for J := 0 to B.Width - 1 do Row[J] := AlphaBlend(Row[J],rgbBlack,150); end; end; destructor TScreenEmul.Destroy; begin FBitmap.Free; inherited; end; procedure TScreenEmul.RestoreImage; begin BitBlt(FBitmap.Canvas.Handle,LastRect.Left,LastRect.Top,RectWidth(LastRect),RectHeight(LastRect),Darken.Canvas.Handle,SRCCOPY); end; procedure TScreenEmul.SetBitmap(const Value: TBitmap); begin FBitmap := Value; FBitmap.OnChange := BitmapChange; end; procedure TScreenEmul.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin Message.Result := LResult(False); end; procedure TScreenEmul.WMLButtonDown(var Message: TWMLButtonDown); begin MouseDown := True; with DrawRect do begin Left := Message.XPos; Top := Message.YPos; Right := Left; Bottom := Top; end; DrawStart.X := DrawRect.Top; DrawStart.Y := DrawRect.Left; end; procedure TScreenEmul.WMLButtonUp(var Message: TWMLButtonUp); begin MouseDown := False; RestoreImage; InvalidateRect(Self.Handle,DrawRect,False); end; procedure TScreenEmul.WMMouseMove(var Message: TWMMouseMove); begin if not MouseDown then Exit; CalculateDrawRect(Message.XPos,Message.YPos); RestoreImage; BitBlt( FBitmap.Canvas.Handle,DrawRect.Left,DrawRect.Top,RectWidth(DrawRect),RectHeight(DrawRect),Backup.Canvas.Handle,SRCCOPY); InvalidateRect(Self.Handle,False); LastRect := DrawRect; end; procedure TScreenEmul.WMPaint(var Message: TWMPaint); var B: TBitmap; Rct: TRect; X,Y: Integer; FullRepaint: Boolean; begin inherited; FullRepaint := GetUpdateRect(Self.Handle,Rct,False); if not FullRepaint then begin Canvas.Draw(0,FBitmap); end else begin B := TBitmap.Create; B.SetSize(RectWidth(Rct),RectHeight(Rct)); FBitmap.Canvas.CopyRect(Rect(0,B.Width,B.Height),B.Canvas,Rct); Canvas.Draw(0,B); FreeAndNil(B); end; end; end. 使用此类: var ScreenEmul: TScreenEmul; begin ScreenEmul := TScreenEmul.Create(Self); ScreenEmul.Parent := Self; ScreenEmul.Align := alClient; ScreenEmul.Bitmap.LoadFromFile('C:img13.bmp'); 解决方法
我解决了这个问题.我回答记录的问题:
1- WMEraseBkgnd应返回True以防止绘制背景.我错误地归还了假. 2-我继承了WMPaint方法,这是不正确的.我还将更新的Rect复制到新的Bitmap中,然后将位图绘制到画布中,这对绘制过程来说很慢.这是完整的固定源代码: unit ScreenEmul; interface uses Classes,Darken: TBitmap; FBitmap: TBitmap; procedure BitmapChange(Sender: TObject); procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN; procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE; procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP; procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; procedure WMPaint(var Message: TWMPaint); message WM_PAINT; procedure DarkenBitmap(B: TBitmap); procedure RestoreImage; procedure CalculateDrawRect(X,SRCCOPY); end; procedure TScreenEmul.SetBitmap(const Value: TBitmap); begin FBitmap := Value; FBitmap.OnChange := BitmapChange; end; procedure TScreenEmul.WMEraseBkgnd(var Message: TWMEraseBkgnd); begin Message.Result := LResult(True); end; procedure TScreenEmul.WMLButtonDown(var Message: TWMLButtonDown); begin MouseDown := True; with DrawRect do begin Left := Message.XPos; Top := Message.YPos; Right := Left; Bottom := Top; end; DrawStart.X := DrawRect.Top; DrawStart.Y := DrawRect.Left; end; procedure TScreenEmul.WMLButtonUp(var Message: TWMLButtonUp); begin MouseDown := False; RestoreImage; InvalidateRect(Self.Handle,False); LastRect := DrawRect; end; procedure TScreenEmul.WMPaint(var Message: TWMPaint); var Rct: TRect; FullRepaint: Boolean; begin FullRepaint := GetUpdateRect(Self.Handle,False); if not FullRepaint then Canvas.Draw(0,FBitmap) else BitBlt(Canvas.Handle,Rct.Left,Rct.Top,RectWidth(Rct),RectHeight(Rct),FBitmap.Canvas.Handle,SRCCOPY); end; end. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |