unit EDBImage; {$I compilers.inc} { TEDBImage 1.4 (Enhaced TDBImage): by Sebastián Mayorá - Argentina - DelphiHelper@yahoo.com.ar Please read EDBImage.txt or readme.txt for more information } interface uses DBCtrls {TDataLink}, Windows {HPalette}, db {TField}, graphics, classes {TStream}, Controls {TCustomControl}, Forms {TBorderStyle}, Messages {TMessage}; type //Evento para cargar imágenes personalizadas desde el stream guardado TLoadCustomImageEvent = procedure (var B: TGraphic; Stream: TStream)of object; TEDBImage = class(TCustomControl) private FDataLink: TFieldDataLink; FPicture: TPicture; FBorderStyle: TBorderStyle; FAutoDisplay: Boolean; FStretch: Boolean; FCenter: Boolean; FPictureLoaded: Boolean; FQuickDraw: Boolean; fOnLoadCustomImage: TLoadCustomImageEvent; procedure DataChange(Sender: TObject); function GetDataField: string; function GetDataSource: TDataSource; function GetField: TField; function GetReadOnly: Boolean; procedure PictureChanged(Sender: TObject); procedure SetAutoDisplay(Value: Boolean); procedure SetBorderStyle(Value: TBorderStyle); procedure SetCenter(Value: Boolean); procedure SetDataField(const Value: string); procedure SetDataSource(Value: TDataSource); procedure SetPicture(Value: TPicture); procedure SetReadOnly(Value: Boolean); procedure SetStretch(Value: Boolean); procedure UpdateData(Sender: TObject); procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK; procedure CMEnter(var Message: TCMEnter); message CM_ENTER; procedure CMExit(var Message: TCMExit); message CM_EXIT; procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED; procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN; procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK; procedure WMCut(var Message: TMessage); message WM_CUT; procedure WMCopy(var Message: TMessage); message WM_COPY; procedure WMPaste(var Message: TMessage); message WM_PASTE; procedure WMSize(var Message: TMessage); message WM_SIZE; protected Memoria: TmemoryStream; procedure CreateParams(var Params: TCreateParams); override; function GetPalette: HPALETTE; override; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: Char); override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure Paint; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure CopyToClipboard; procedure CutToClipboard; function ExecuteAction(Action: TBasicAction): Boolean; override; procedure LoadPicture; procedure PasteFromClipboard; function UpdateAction(Action: TBasicAction): Boolean; override; property Field: TField read GetField; property Picture: TPicture read FPicture write SetPicture; procedure LoadFromFile(const FileName: string);{v1.3} procedure SaveToFile(const FileName: string); {v1.3} published property Align; property Anchors; property AutoDisplay: Boolean read FAutoDisplay write SetAutoDisplay default True; property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle; property Center: Boolean read FCenter write SetCenter default True; property Color; property Constraints; property Ctl3D; property DataField: string read GetDataField write SetDataField; property DataSource: TDataSource read GetDataSource write SetDataSource; property DragCursor; property DragKind; property DragMode; property Enabled; property Font; property ParentColor default False; property ParentCtl3D; property ParentFont; property ParentShowHint; property PopupMenu; property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False; property QuickDraw: Boolean read FQuickDraw write FQuickDraw default True; property ShowHint; property Stretch: Boolean read FStretch write SetStretch default False; property TabOrder; property TabStop default True; property Visible; property OnClick; {$IFDEF DELPHI_5_UP} property OnContextPopup; {$ENDIF} property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDock; property OnEndDrag; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnStartDock; property OnStartDrag; property OnLoadCustomImage :TLoadCustomImageEvent read fOnLoadCustomImage write fOnLoadCustomImage; end; implementation uses clipbrd, JPeg; constructor TEDBImage.Create(AOwner: TComponent); begin inherited Create(AOwner); ControlStyle := ControlStyle + [csOpaque, csReplicatable]; if not NewStyleControls then ControlStyle := ControlStyle + [csFramed]; Width := 105; Height := 105; TabStop := True; ParentColor := False; FPicture := TPicture.Create; FPicture.OnChange := PictureChanged; FBorderStyle := bsSingle; FAutoDisplay := True; FCenter := True; FDataLink := TFieldDataLink.Create; FDataLink.Control := Self; FDataLink.OnDataChange := DataChange; FDataLink.OnUpdateData := UpdateData; FQuickDraw := True; Memoria := TmemoryStream.Create; end; destructor TEDBImage.Destroy; begin FPicture.Free; FDataLink.Free; FDataLink := nil; Memoria.Free; inherited Destroy; end; function TEDBImage.GetDataSource: TDataSource; begin Result := FDataLink.DataSource; end; procedure TEDBImage.SetDataSource(Value: TDataSource); begin if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then FDataLink.DataSource := Value; if Value <> nil then Value.FreeNotification(Self); end; function TEDBImage.GetDataField: string; begin Result := FDataLink.FieldName; end; procedure TEDBImage.SetDataField(const Value: string); begin FDataLink.FieldName := Value; end; function TEDBImage.GetReadOnly: Boolean; begin Result := FDataLink.ReadOnly; end; procedure TEDBImage.SetReadOnly(Value: Boolean); begin FDataLink.ReadOnly := Value; end; function TEDBImage.GetField: TField; begin Result := FDataLink.Field; end; function TEDBImage.GetPalette: HPALETTE; begin Result := 0; if FPicture.Graphic <> nil then Result := FPicture.Graphic.Palette; {TGraphic has a property Pallete read GetPalette. and GetPalette is Virtual Desendants re-implements GetPalette so I don't need ask what kind of Graphic is stored} end; procedure TEDBImage.SetAutoDisplay(Value: Boolean); begin if FAutoDisplay <> Value then begin FAutoDisplay := Value; if Value then LoadPicture; end; end; procedure TEDBImage.SetBorderStyle(Value: TBorderStyle); begin if FBorderStyle <> Value then begin FBorderStyle := Value; RecreateWnd; end; end; procedure TEDBImage.SetCenter(Value: Boolean); begin if FCenter <> Value then begin FCenter := Value; Invalidate; end; end; procedure TEDBImage.SetPicture(Value: TPicture); begin FPicture.Assign(Value); end; procedure TEDBImage.SetStretch(Value: Boolean); begin if FStretch <> Value then begin FStretch := Value; Invalidate; end; end; procedure TEDBImage.Paint; var Size: TSize; R: TRect; S: string; DrawPict: TPicture; Form: TCustomForm; Pal: HPalette; begin with Canvas do begin Brush.Style := bsSolid; Brush.Color := Color; FillRect(ClientRect); if FPictureLoaded or (csPaintCopy in ControlState) then begin DrawPict := TPicture.Create; Pal := 0; try if (csPaintCopy in ControlState) and Assigned(FDataLink.Field) and FDataLink.Field.IsBlob then begin DrawPict.Assign(FDataLink.Field); if DrawPict.Graphic is TBitmap then DrawPict.Bitmap.IgnorePalette := QuickDraw; end else begin DrawPict.Assign(Picture); if Focused and (DrawPict.Graphic <> nil) and (DrawPict.Graphic.Palette <> 0) then begin { Control has focus, so realize the bitmap palette in foreground } Pal := SelectPalette(Handle, DrawPict.Graphic.Palette, False); RealizePalette(Handle); end; end; if Stretch then if (DrawPict.Graphic = nil) or DrawPict.Graphic.Empty then FillRect(ClientRect) else StretchDraw(ClientRect, DrawPict.Graphic) else begin SetRect(R, 0, 0, DrawPict.Width, DrawPict.Height); if Center then OffsetRect(R, (ClientWidth - DrawPict.Width) div 2, (ClientHeight - DrawPict.Height) div 2); StretchDraw(R, DrawPict.Graphic); ExcludeClipRect(Handle, R.Left, R.Top, R.Right, R.Bottom); FillRect(ClientRect); SelectClipRgn(Handle, 0); end; finally if Pal <> 0 then SelectPalette(Handle, Pal, True); DrawPict.Free; end; end else begin Font := Self.Font; if FDataLink.Field <> nil then S := FDataLink.Field.DisplayLabel else S := Name; S := '(' + S + ')'; Size := TextExtent(S); R := ClientRect; TextRect(R, (R.Right - Size.cx) div 2, (R.Bottom - Size.cy) div 2, S); end; Form := GetParentForm(Self); if (Form <> nil) and (Form.ActiveControl = Self) and not (csDesigning in ComponentState) and not (csPaintCopy in ControlState) then begin Brush.Color := clWindowFrame; FrameRect(ClientRect); end; end; end; procedure TEDBImage.PictureChanged(Sender: TObject); begin if FPictureLoaded then FDataLink.Modified; FPictureLoaded := True; Invalidate; end; procedure TEDBImage.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) and (FDataLink <> nil) and (AComponent = DataSource) then DataSource := nil; end; procedure TEDBImage.LoadPicture; var B: TGraphic; Buf: word; begin with fDatalink do if (Field = nil) or not Field.IsBlob or Field.IsNull then begin Picture.Assign(Nil); Exit; end; if not FPictureLoaded and (not Assigned(FDataLink.Field) or FDataLink.Field.IsBlob) then try Memoria.Clear; TBlobField(Field).SaveToStream(Memoria); Memoria.Position :=0; B:= nil; if Memoria.Size > SizeOf(buf) then begin Memoria.read(buf, SizeOf(buf)); case buf of $0000 : B := TIcon.Create; $0001 : begin Picture.Assign(FDataLink.Field); Exit; end; $4D42 : B := TBitmap.Create; $CDD7 : B := TMetafile.Create; $D8FF : B := TJPEGImage.Create; end; end; Memoria.Position := 0; if B <> nil then try B.LoadFromStream(Memoria); except B:= nil; end; //if the stored image is not ico, bmp, wmf, emf, jpg, jpeg //or I cant load it then fire the event if (b = nil) and Assigned(fonloadCustomImage) then try memoria.Position := 0; fOnLoadCustomImage(B, Memoria); except B:= nil; end; Picture.Assign(B);//B can be NIL, no problem with that finally B.Free; Memoria.Clear; end; end; procedure TEDBImage.DataChange(Sender: TObject); begin Picture.Graphic := nil; FPictureLoaded := False; if FAutoDisplay then LoadPicture; end; procedure TEDBImage.UpdateData(Sender: TObject); var MS: TMemoryStream; begin if (Picture.Graphic is TBitmap) then FDataLink.Field.Assign(Picture.Graphic) else begin MS := TMemoryStream.Create; try try Ms.Clear; Picture.Graphic.SaveToStream(MS); Ms.Position := 0; TBlobField(Fdatalink.field).LoadFromStream(MS); except FDataLink.Field.Clear; end; finally Ms.Free; end; end; end; procedure TEDBImage.CopyToClipboard; var TempBMP: tbitmap; begin if Picture.Graphic <> nil then if Picture.Graphic is TICon then begin Tempbmp := Tbitmap.Create; tempbmp.Width := Picture.graphic.width; tempbmp.Height:= Picture.graphic.Height; tempbmp.Canvas.Draw(0,0, Picture.Graphic); clipboard.Assign(tempBmp); tempbmp.Free; end else Clipboard.Assign(Picture); end; procedure TEDBImage.CutToClipboard; begin if Picture.Graphic <> nil then if FDataLink.Edit then begin CopyToClipboard; Picture.Graphic := nil; PictureChanged(Self); end; end; procedure TEDBImage.PasteFromClipboard; begin if fDatalink.edit then if ClipBoard.HasFormat(CF_BITMAP) then Picture.Bitmap.Assign(Clipboard) else if ClipBoard.HasFormat(CF_METAFILEPICT)or ClipBoard.HasFormat(CF_ENHMETAFILE) then picture.Metafile.Assign(ClipBoard) else if ClipBoard.hasformat(Cf_picture) then picture.Assign(ClipBoard); PictureChanged(Self); end; procedure TEDBImage.CreateParams(var Params: TCreateParams); begin inherited CreateParams(Params); with Params do begin if FBorderStyle = bsSingle then if NewStyleControls and Ctl3D then ExStyle := ExStyle or WS_EX_CLIENTEDGE else Style := Style or WS_BORDER; WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW); end; end; procedure TEDBImage.KeyDown(var Key: Word; Shift: TShiftState); begin inherited KeyDown(Key, Shift); case Key of VK_INSERT: if ssShift in Shift then PasteFromClipBoard else if ssCtrl in Shift then CopyToClipBoard; VK_DELETE: if ssShift in Shift then CutToClipBoard; end; end; procedure TEDBImage.KeyPress(var Key: Char); begin inherited KeyPress(Key); case Key of ^X: CutToClipBoard; ^C: CopyToClipBoard; ^V: PasteFromClipBoard; #13: LoadPicture; #27: FDataLink.Reset; end; end; procedure TEDBImage.CMGetDataLink(var Message: TMessage); begin Message.Result := Integer(FDataLink); end; procedure TEDBImage.CMEnter(var Message: TCMEnter); begin Invalidate; { Draw the focus marker } inherited; end; procedure TEDBImage.CMExit(var Message: TCMExit); begin try FDataLink.UpdateRecord; except SetFocus; raise; end; Invalidate; { Erase the focus marker } inherited; end; procedure TEDBImage.CMTextChanged(var Message: TMessage); begin inherited; if not FPictureLoaded then Invalidate; end; procedure TEDBImage.WMLButtonDown(var Message: TWMLButtonDown); begin if TabStop and CanFocus then SetFocus; inherited; end; procedure TEDBImage.WMLButtonDblClk(var Message: TWMLButtonDblClk); begin LoadPicture; inherited; end; procedure TEDBImage.WMCut(var Message: TMessage); begin CutToClipboard; end; procedure TEDBImage.WMCopy(var Message: TMessage); begin CopyToClipboard; end; procedure TEDBImage.WMPaste(var Message: TMessage); begin PasteFromClipboard; end; procedure TEDBImage.WMSize(var Message: TMessage); begin inherited; Invalidate; end; function TEDBImage.ExecuteAction(Action: TBasicAction): Boolean; begin Result := inherited ExecuteAction(Action) or (FDataLink <> nil) and FDataLink.ExecuteAction(Action); end; function TEDBImage.UpdateAction(Action: TBasicAction): Boolean; begin Result := inherited UpdateAction(Action) or (FDataLink <> nil) and FDataLink.UpdateAction(Action); end; procedure TEDBImage.LoadFromFile(const FileName: string); begin if Assigned(fDatalink.Field) and fDatalink.Field.IsBlob and fDatalink.Edit then begin TBlobField(fDatalink.Field).LoadFromFile(FileName); PictureChanged(Self); end; end; procedure TEDBImage.SaveToFile(const FileName: string); begin if FPictureLoaded and Assigned(FDataLink.Field) and FDataLink.Field.IsBlob then TBlobField(fDatalink.Field).SaveToFile(FileName); end; end.