Mega Code Archive

 
Categories / Delphi / VCL
 

Selectionbox component

Title: Selectionbox component Question: How to make a selectionbox Answer: {------------------------------------------------------------------------ Written for: DELPHI 3.0 or higher This selection box can be used or modified freely. Usage ----- Place the selection box exactly over an TImage component. In this way you are able to select a certain region (rectangle) of the image and copy it, and paste it in the same image or as a new image. New Properties -------------- * LineStyle lsDash (same as Delphi psDash) lsSingle (same as Delphi psSolid) lsDouble (two psSolid lines) lsDot (same as Delphi psDot) The selection lines are drawn in Delphi's pmXor mode. This is done because I didn't find an other fast way to clear (make transparent) the canvas, while changing the size of the selection box. You can draw the selectionbox in a certain color but then you have to remove the previous box (with refresh) every time you change the size of the selection box. This will give a lot of flickering. * X1 -- Top of selectionbox * X2 -- Bottom of selectionbox * Y1 -- Left of selectionbox * Y2 -- Right of selectionbox Coordinates of the box on the TImage. (Read and write.) * Selmode smNone -- once the selectionbox is drawn, it can not be resized or moved smMove -- you are able to move the complete selectionbox smDrag -- you are able to resize the selctionbox smBoth -- smMove + smDrag * Cadre This is the sensitivity width of the cadre. If you place the mouse over the border of the selection box, the mouse will change in crSizeNS or crSizeWE. When you make Cadre = 1 only when the mouse is 1 pixel away from the border of the selectionbox, it will change in crSizeNS or crSizeWE. Events ------ * SelectionReady A selection box is ready and visible. * NothingSelected A selection box is not visible, there is nothing selected. * SelectionChanges The selectionbox is resized or moved You can use this event to display the selection size during a change of selection Procedures/Functons ------------------- * Reset A selection box is not visible. All necessary variables are reset. * SelectionboxRefresh The selection box is redrawn. Known bugs ---------- 1. When moving the selectionbox it is possible to move a part of the selection box outside the border of the paintbox. 2. When drawing a selectionbox it is possible to draw the selectionbox outside the paintbox. After entering the paintbox again, you will notice that the selectionbox is still "sticked to the cursor" even if you have released the mouse button (outside the paintbox). Both bugs are a bit inconveniant but not harmfull. Writer name: Maarten de Haan Email: M.deHaan@inn.nl ------------------------------------------------------------------------} Unit SelectionBox; Interface Uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; {$R MYCUR1.RES} {No crSize was found in Delphi 3...} Const crMove = 1; // move cursor: with four arrows N, S, E and W crSelect = 2; // select cursor: cross like a plus sign with a box to // indicate a selectionbox Type TSelectedState = (ssSelected,ssUnSelected); // internal TMouseState = (msMouseDown,msMouseUp); // interal} TLineStyle = (lsDash,lsSingle,lsDot,lsDouble); // external TSelMode = (smNone,smMove,smDrag,smBoth); // external TCurrentMode = (cmNone,cmMoving,cmDragging); // internal TDragLine =(dlNone,dlLeft,dlTop,dlRight,dlBottom); // internal TSelectionBox = class(TPaintBox) Private { Private declarations } fX1,fX2,fY1,fY2 : Integer; // internal coordinates ffX1,ffX2,ffY1,ffY2 : Integer; // external coordinates // always: ffX2 ffX1 and ffY2 ffY1 fNew : Boolean; // internal variable fRect : TRect; // rect var (not used) fCadre : Integer; // sensitivity cadre width for changing // the mouse fSelectedState : TSelectedState;// state of selection fMouseState : TMouseState; // mouse state (up or down) fLineStyle : TLineStyle; // line style (lsDash,lsSingle,lsDot,lsDouble) fSelMode : TSelMode; // mode (smNone,smMove,smDrag,smBoth) fCurrentMode : TCurrentMode; // current mode (cmNone,cmMoving,cmDragging) fYOld,fXOld : Integer; // old values of mouse position fColor : TColor; // remove from object inspector fDragMode : TDragMode; // remove from object inspector fDragLine : TDragLine; // which line to drag (dlNone,dlLeft,dlTop,dlRight,dlBottom) fSelectionReady : TNotifyEvent; // notify when there is a selection fNothingSelected : TNotifyEvent; // notify when there is no selection fSelectionChanges : TNotifyEvent; // notify when the selectionbox changes Procedure MouseDownMessage(var Msg : TMessage); message WM_LBUTTONDOWN; // left mouse button down Procedure MouseMoveMessage(var Msg : TMessage); message WM_MOUSEMOVE; // mouse move Procedure MouseUpMessage(var Msg : TMessage); message WM_LBUTTONUP; // left mouse button up Procedure fSetCadre(Value : Integer); // cadre width Procedure fCheckCoordinates; // make ffX2 ffX1 and ffY2 ffY1 Procedure fSetX1(Value : Integer); // Set X1 Procedure fSetY1(Value : Integer); // Set Y1 Procedure fSetX2(Value : Integer); // Set X2 Procedure fSetY2(Value : Integer); // Set Y2 Protected { Protected declarations } Constructor Create(AOwner : TComponent); override; Procedure DrawSelectionbox; // drawing of the selection box Procedure SelectionReady; dynamic; // add new event Procedure NothingSelected; dynamic; // add new event Procedure SelectionChanges; dynamic; // add new event Public Procedure Reset; // Reset the selection box Procedure SelectionBoxRefresh; // Redraw the selection box { Public declarations } Published { Published declarations } Property LineStyle : TLineStyle read fLineStyle write fLineStyle; // line style Property X1 : Integer read ffX1 write fSetX1; // X1 Property Y1 : Integer read ffY1 write fSetY1; // Y1 Property X2 : Integer read ffX2 write fSetX2; // X2 Property Y2 : Integer read ffY2 write fSetY2; // Y2 Property SelMode : TSelMode read fSelMode write fSelMode; // mode Property Cadre : Integer read fCadre write fSetCadre; // cadre width Property OnSelectionReady : TNotifyEvent read fSelectionReady write fSelectionReady; // event Property OnNothingSelected : TNotifyEvent read fNothingSelected write fNothingSelected; // event Property OnSelectionChanges : TNotifyEvent read fSelectionChanges write fSelectionChanges; // event Property Color : TColor // remove from object inspector read fColor; Property DragMode : TDragMode // remove from object inspector read fDragMode; End; Procedure Register; // hello Implementation {----------------------------------------------------------------------} Procedure TSelectionBox.SelectionBoxRefresh; Begin Refresh; {clear} fCheckCoordinates; DrawSelectionBox; {redraw with old coordinates} fNew := True; End; {----------------------------------------------------------------------} Procedure TSelectionBox.fSetX1(Value : Integer); Begin If (Value = 0) then Begin Refresh; {clear} fX1 := Value; DrawSelectionBox; fNew := True; End; End; {----------------------------------------------------------------------} Procedure TSelectionBox.fSetX2(Value : Integer); Begin If (Value = 0) then Begin Refresh; {clear} fX2 := Value; DrawSelectionBox; fNew := True; End; End; {----------------------------------------------------------------------} Procedure TSelectionBox.fSetY1(Value : Integer); Begin If (Value = 0) then Begin Refresh; {clear} fY1 := Value; DrawSelectionBox; fNew := True; End; End; {----------------------------------------------------------------------} Procedure TSelectionBox.fSetY2(Value : Integer); Begin If Value = 0 then Begin Refresh; {clear} fY2 := Value; DrawSelectionBox; fNew := True; End; End; {----------------------------------------------------------------------} Procedure TSelectionBox.fCheckCoordinates; Begin ffX1 := fX1; ffX2 := fX2; ffY1 := fY1; ffY2 := fY2; // Change coordinates for the outside, if X1 X2 If fX1 fX2 then Begin ffX1 := fX2; ffX2 := fX1; End; // of if // Change coordinates for the outside, if Y1 Y2 If fY1 fY2 then Begin ffY1 := fY2; ffY2 := fY1; End; // of if End; {----------------------------------------------------------------------} Procedure TSelectionBox.SelectionChanges; Begin if Assigned(fSelectionChanges) then fSelectionChanges(Self); End; {----------------------------------------------------------------------} Procedure TSelectionBox.SelectionReady; Begin if Assigned(fSelectionReady) then fSelectionReady(Self); End; {----------------------------------------------------------------------} Procedure TSelectionBox.NothingSelected; Begin if Assigned(fNothingSelected) then fNothingSelected(Self); End; {----------------------------------------------------------------------} Procedure TSelectionBox.Reset; Begin {Reset the selection box} Refresh; {clear} {Initialize} fX1 := 0; fX2 := 0; fY1 := 0; fY2 := 0; ffX1 := 0; ffX2 := 0; ffY1 := 0; ffY2 := 0; If fSelectedState = ssSelected then Begin fSelectedState := ssUnSelected; End; fNew := True; NothingSelected; End; {----------------------------------------------------------------------} Procedure TSelectionBox.fSetCadre(Value : Integer); Begin If (Value 0) and (Value Begin fCadre := Value; End; // of if End; // of procedure {----------------------------------------------------------------------} Procedure TSelectionBox.MouseDownMessage(var Msg : TMessage); Var X,Y : Integer; Begin X := Msg.lParamLo; Y := Msg.lParamHi; fMouseState := msMouseDown; // mouse is down SelectionChanges; If (fSelMode = smNone) then Begin DrawSelectionBox; fX1 := X; fY1 := Y; fCurrentMode := cmNone; fNew := True; End // of if else Begin // fSelMode smNone If (fCurrentMode = cmMoving) or (fCurrentMode = cmDragging) then Begin fXOld := X; fYOld := Y; End; // of if If (fCurrentMode = cmNone) then Begin DrawSelectionBox; fX1 := X; fY1 := Y; fNew := True; End; // of if End; // of else End; // of proc {----------------------------------------------------------------------} Procedure TSelectionBox.MouseMoveMessage(var Msg : TMessage); Var X,Y : Integer; DX,DY : Integer; Bo1,Bo2 : Boolean; Begin X := Msg.lParamLo; // get mouse x pos Y := Msg.lParamHi; // get mouse y pos fCheckCoordinates; // Init Bo1 and Bo2 Bo1 := False; Bo2 := False; //------------------------------MOUSE IS UP---------- If fMouseState = msMouseUp then If (fX1 fX2) and (fY1 fY2) then SelectionReady; {Dragging, mouse is up} If (fMouseState = msMouseUp) then If ((fSelMode = smDrag) or (fSelMode = smBoth)) then Begin If (Abs(X - fX1) If (Y = ffY1 + fCadre) and (Y Begin Cursor := crSizeWE; Bo1 := True; fDragLine := dlLeft; fCurrentMode := cmDragging; End; // of if If (Abs(X - fX2) If (Y = ffY1 + fCadre) and (Y Begin Cursor := crSizeWE; Bo1 := True; fDragLine := dlRight; fCurrentMode := cmDragging; End; // of if If (Abs(Y - fY1) If (X = ffX1 + fCadre) and (X Begin Cursor := crSizeNS; Bo1 := True; fDragLine := dlTop; fCurrentMode := cmDragging; End; // of if If (Abs(Y - fY2) If (X = ffX1 + fCadre) and (X Begin Cursor := crSizeNS; Bo1 := True; fDragLine := dlBottom; fCurrentMode := cmDragging; End; // of if If Bo1 = False then Begin fDragLine := dlNone; fCurrentMode := cmNone; End; // of if End; // of if // Moving, mouse is up If (fMouseState = msMouseUp) then If (fNew = True) and ((fSelMode = smMove) or (fSelMode = smBoth)) then Begin If (X = ffX1 + fCadre) and (X (Y = ffY1 + fCadre) and (Y Begin Cursor := crMove; fCurrentMode := cmMoving; Bo2 := True; End; // of if End; // of if // Change cursor shape when dragging or moving If Bo1 = True then fCurrentMode := cmDragging; If Bo2 = True then fCurrentMode := cmMoving; //------------------------------MOUSE IS DOWN-------- // Moving the selection area, when mouse is down If (fMouseState = msMouseDown) then Begin If ((fSelMode = smMove) or (fSelMode = smBoth)) then If (fCurrentMode = cmMoving) then Begin fCurrentMode := cmMoving; DrawSelectionBox; DX := fXOld - X; DY := fYOld - Y; fX1 := fX1 - DX; fY1 := fY1 - DY; fX2 := fX2 - DX; fY2 := fY2 - DY; DrawSelectionBox; fXOld := X; fYOld := Y; Cursor := crMove; Bo1 := True; End; // of if End; // No moving and no dragging, when the mouse is down If (fMouseState = msMouseDown) then Begin If (fCurrentMode = cmNone) then Begin If fNew = False then DrawSelectionBox; // clear previous box while moving the mouse fX2 := Msg.lParamLo; // get mouse x2 fY2 := Msg.lParamHi; // get mouse y2 DrawSelectionBox; // draw new selection box Bo1 := False; Bo2 := False; fNew := False; End; // of if End; // Dragging the selection area, when mouse is down If (fMouseState = msMouseDown) then Begin If ((fSelMode = smDrag) or (fSelMode = smBoth)) then If (fCurrentMode = cmDragging) then If fDragLine dlNone then Begin fCurrentMode := cmDragging; DrawSelectionBox; DX := fXOld - X; DY := fYOld - Y; If fDragLine = dlLeft then Begin fX1 := fX1 - DX; Cursor := crSizeWE; End; // of if If fDragLine = dlRight then Begin fX2 := fX2 - DX; Cursor := crSizeWE; End; // of if If fDragLine = dlTop then Begin fY1 := fY1 - DY; Cursor := crSizeNS; End; // of if If fDragLine = dlBottom then Begin fY2 := fY2 - DY; Cursor := crSizeNS; End; // of if DrawSelectionbox; fXOld := X; fYOld := Y; Bo2 := True; End; // of if End; If (Bo1 = False) and (Bo2 = False) then Cursor := crSelect; End; // of procedure {----------------------------------------------------------------------} Procedure TSelectionBox.MouseUpMessage(var Msg : TMessage); Var X,Y : Integer; Begin fMouseState := msMouseUp; // end of drawing selection box fCurrentMode := cmNone; // clear current mode fDragLine := dlNone; // no line to drag Cursor := crSelect; // select cursor fNew := True; X := Msg.lParamLo; Y := Msg.lParamHi; If (X = fX1) and (Y = fY1) then Begin // mouse did not move, just clicked, so clear the selection box fX2 := fX1; fY2 := fY1; If fSelectedState = ssSelected then Begin fSelectedState := ssUnSelected; NothingSelected; End; End; // of if End; // of procedure {----------------------------------------------------------------------} Procedure TSelectionBox.DrawSelectionbox; Begin SelectionChanges; fCheckCoordinates; Canvas.Pen.Color := clWhite; // must be white Canvas.Pen.Mode := pmXor; // xor mask Canvas.Pen.Style := psSolid; // default Case fLineStyle of lsSingle,lsDouble : Canvas.Pen.Style := psSolid; // solid lsDot : Canvas.Pen.Style := psDot; // dot lsDash : Canvas.Pen.Style := psDash; // dash End; // of Case If (fX1 fX2) or (fY1 fY2) then Begin Canvas.MoveTo(fX1,fY1); // move to x1,y1 Canvas.LineTo(fX2,fY1); // draw from x1,y1 to x2,y1 Canvas.LineTo(fX2,fY2); // draw from x2,y1 to x2,y2 Canvas.LineTo(fX1,fY2); // draw from x2,y2 to x1,y2 Canvas.LineTo(fX1,fY1); // draw from x1,y2 to x1,y1 {double lines, thicker} If fLineStyle = lsDouble then Begin Canvas.MoveTo(fX1 - 1,fY1 - 1); // draw from x1 - 1,y1 - 1 to x2 + 1,y1 - 1 Canvas.LineTo(fX2 + 1,fY1 - 1); // draw from x2 + 1,y1 - 1 to x2 + 1,y2 + 1 Canvas.LineTo(fX2 + 1,fY2 + 1); // draw from x2 + 1,y2 + 1 to x1 - 1,y2 + 1 Canvas.LineTo(fX1 - 1,fY2 + 1); // draw from x1 - 1,y2 + 1 to x1 - 1,y1 - 1 Canvas.LineTo(fX1 - 1,fY1 - 1); End; End; If (fX1 fX2) and (fY1 fY2) then If fSelectedState = ssUnSelected then Begin fSelectedState := ssSelected; End; If (fX1 = fX2) or (fY1 = fY2) then If fSelectedState = ssSelected then Begin fSelectedState := ssUnSelected; End; End; // of procedure {----------------------------------------------------------------------} Constructor TSelectionbox.Create(AOwner : TComponent); Begin inherited Create(AOwner); // create component // initialize fx,fy fX1 := 0; fY1 := 0; fX2 := 0; fY2 := 0; // initialize ffx,ffy ffX1 := 0; ffX2 := 0; ffY1 := 0; ffY2 := 0; // initialize variables fNew := True; fRect := Rect(fX1,fY1,fX2,fY2); // not used fMouseState := msMouseUp; // mouse is up fLineStyle := lsSingle; // linestyle solid/single Canvas.Pen.Style := psSolid; // linestyle solid/single fSelMode := smNone; // no moving or dragging fCurrentMode := cmNone; // no current mode yet fCadre := 3; // set cadre width Inherited Color := clBtnFace; // remove from obj insp Inherited Dragmode := dmManual; // remove from obj insp Screen.Cursors[crMove] := LoadCursor(HInstance,'MOVE'); //A cursor with cross NESW {!! The cursor type crSize was not found in Delphi3 !! Although it should be there !!} Screen.Cursors[crSelect] := LoadCursor(HInstance,'SELECT'); //A cursor like a plus sign and a (small) rectangle to indicate a //selectionbox fSelectedState := ssUnSelected; {Add new cursor} End; // of procedure {----------------------------------------------------------------------} Procedure Register; Begin RegisterComponents('Samples', [TSelectionBox]); End; // of procedure register {----------------------------------------------------------------------} End. // of unit {======================================================================}