📄 mainfrm.pas
字号:
unit MainFrm;
interface
uses
SysUtils, Windows, Messages, Classes, Graphics, Controls,
Forms, Dialogs, Buttons, ExtCtrls, ColorGrd, StdCtrls, Menus, ComCtrls;
const
crMove = 1;
type
TDrawType = (dtLineDraw, dtRectangle, dtEllipse, dtRoundRect,
dtClipRect, dtCrooked);
TMainForm = class(TForm)
sbxMain: TScrollBox;
imgDrawingPad: TImage;
pnlToolBar: TPanel;
sbLine: TSpeedButton;
sbRectangle: TSpeedButton;
sbEllipse: TSpeedButton;
sbRoundRect: TSpeedButton;
pnlColors: TPanel;
cgDrawingColors: TColorGrid;
pnlFgBgBorder: TPanel;
pnlFgBgInner: TPanel;
Bevel1: TBevel;
mmMain: TMainMenu;
mmiFile: TMenuItem;
mmiExit: TMenuItem;
N2: TMenuItem;
mmiSaveAs: TMenuItem;
mmiSaveFile: TMenuItem;
mmiOpenFile: TMenuItem;
mmiNewFile: TMenuItem;
mmiEdit: TMenuItem;
mmiPaste: TMenuItem;
mmiCopy: TMenuItem;
mmiCut: TMenuItem;
sbRectSelect: TSpeedButton;
SaveDialog: TSaveDialog;
OpenDialog: TOpenDialog;
stbMain: TStatusBar;
pbPasteBox: TPaintBox;
sbFreeForm: TSpeedButton;
RgGrpFillOptions: TRadioGroup;
cbxBorder: TCheckBox;
mmiHelp: TMenuItem;
mmiAbout: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure sbLineClick(Sender: TObject);
procedure imgDrawingPadMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure imgDrawingPadMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure imgDrawingPadMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure cgDrawingColorsChange(Sender: TObject);
procedure mmiExitClick(Sender: TObject);
procedure mmiSaveFileClick(Sender: TObject);
procedure mmiSaveAsClick(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure mmiNewFileClick(Sender: TObject);
procedure mmiOpenFileClick(Sender: TObject);
procedure mmiEditClick(Sender: TObject);
procedure mmiCutClick(Sender: TObject);
procedure mmiCopyClick(Sender: TObject);
procedure mmiPasteClick(Sender: TObject);
procedure pbPasteBoxMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure pbPasteBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure pbPasteBoxMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure pbPasteBoxPaint(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure RgGrpFillOptionsClick(Sender: TObject);
public
{ Public declarations }
MouseOrg: TPoint; // 用于保存鼠标信息
NextPoint: TPoint; // 用于保存鼠标信息
Drawing: Boolean;
DrawType: TDrawType; // 用于保存绘画类型信息
FillSelected,
BorderSelected: Boolean;
EraseClipRect: Boolean;
Modified: Boolean;
FileName: String;
OldClipViewHwnd: Hwnd;
{ Paste Image variables }
PBoxMoving: Boolean;
PBoxMouseOrg: TPoint;
PasteBitMap: TBitmap;
Pasted: Boolean;
LastDot: TPoint;
procedure DrawToImage(TL, BR: TPoint; PenMode: TPenMode);
{ This procedure paints the image specified by the DrawType field
to imgDrawingPad }
procedure SetDrawingStyle;
{ This procedure sets various Pen/Brush styles based on values
specified by the form's controls. The Panels and color grid is
used to set these values }
procedure CopyPasteBoxToImage;
{ This procedure copies the data pasted from the Windows clipboard
onto the main image component imgDrawingPad }
procedure WMDrawClipBoard(var Msg: TWMDrawClipBoard);
message WM_DRAWCLIPBOARD;
{ This message handler captures the WM_DRAWCLIPBOARD messages
which is sent to all windows that have been added to the clipboard
viewer chain. An application can add itself to the clipboard viewer
chain by using the SetClipBoardViewer() Win32 API function as
is done in FormCreate() }
procedure CopyCut(Cut: Boolean);
{ This method copies a portion of the main image, imgDrawingPad, to the
Window's clipboard. }
end;
var
MainForm: TMainForm;
implementation
uses ClipBrd, Math;
{$R *.DFM}
procedure TMainForm.FormCreate(Sender: TObject);
{ This method sets the form's field to their default values. It then
creates a bitmap for the imgDrawingPad. This is the image on which
drawing is done. Finally, it adds this application as part of the
Windows clipboard viewer chain by using the SetClipBoardViewer()
function. This makes enables the form to get WM_DRAWCLIPBOARD messages
which are sent to all windows in the clipboard viewer chain whenever
the clipboard data is modified. }
begin
Screen.Cursors[crMove] := LoadCursor(hInstance, 'MOVE');
FillSelected := False;
BorderSelected := True;
Modified := False;
FileName := '';
Pasted := False;
pbPasteBox.Enabled := False;
// Create a bitmap for imgDrawingPad and set its boundaries
with imgDrawingPad do
begin
SetBounds(0, 0, 600, 400);
Picture.Graphic := TBitMap.Create;
Picture.Graphic.Width := 600;
Picture.Graphic.Height := 400;
end;
// Now create a bitmap image to hold pasted data
PasteBitmap := TBitmap.Create;
pbPasteBox.BringToFront;
{ Add the form to the Windows clipboard viewer chain. Save the handle
of the next window in the chain so that it may be restored by the
ChangeClipboardChange() Win32 API function in this form's
FormDestroy() method. }
OldClipViewHwnd := SetClipBoardViewer(Handle);
end;
procedure TMainForm.WMDrawClipBoard(var Msg: TWMDrawClipBoard);
begin
{ This method will be called whenever the clipboard data
has changed. Because the main form was added to the clipboard
viewer chain, it will receive the WM_DRAWCLIPBOARD message
indicating that the clipboard's data was changed. }
inherited;
{ Make sure that the data contained on the clipboard is actually
bitmap data. }
if ClipBoard.HasFormat(CF_BITMAP) then
mmiPaste.Enabled := True
else
mmiPaste.Enabled := False;
Msg.Result := 0;
end;
procedure TMainForm.DrawToImage(TL, BR: TPoint; PenMode: TPenMode);
{ 该过程用于执行指定的绘画操作,绘画操作由DrawType决定}
begin
with imgDrawingPad.Canvas do //在画布上绘画
begin
Pen.Mode := PenMode; //指定笔模式
case DrawType of
dtLineDraw: //画直线
begin
MoveTo(TL.X, TL.Y);
LineTo(BR.X, BR.Y);
end;
dtRectangle: //画矩形
Rectangle(TL.X, TL.Y, BR.X, BR.Y);
dtEllipse: //画椭圆
Ellipse(TL.X, TL.Y, BR.X, BR.Y);
dtRoundRect: //画圆角矩形
RoundRect(TL.X, TL.Y, BR.X, BR.Y,
(TL.X - BR.X) div 2, (TL.Y - BR.Y) div 2);
dtClipRect: //画剪裁区域
Rectangle(TL.X, TL.Y, BR.X, BR.Y);
end;
end;
end;
procedure TMainForm.CopyPasteBoxToImage;
{ 这个过程复制从剪贴板粘贴到 imgDrawingPad
This method copies the image pasted from the Windows clipboard onto
imgDrawingPad. It first erases any bounding rectangle drawn by PaintBox
component, pbPasteBox. It then copies the data from pbPasteBox onto
imgDrawingPad at the location where pbPasteBox has been dragged
over imgDrawingPad. The reason we don't copy the contents of
pbPasteBox's canvas and use PasteBitmap's canvas instead, is because
when a portion of pbPasteBox is dragged out of the viewable area,
Windows does not paint the portion pbPasteBox not visible. Therefore,
it is necessary to the pasted bitmap from the off-screen bitmap }
var
SrcRect, DestRect: TRect;
begin
// 首先,擦除由pbPasteBox绘制的矩形
with pbPasteBox do
begin
Canvas.Pen.Mode := pmNotXOR;
Canvas.Pen.Style := psDot;
Canvas.Brush.Style := bsClear;
Canvas.Rectangle(0, 0, Width, Height);
DestRect := Rect(Left, Top, Left+Width, Top+Height);
SrcRect := Rect(0, 0, Width, Height);
end;
{ Here we must use the PasteBitmap instead of the pbPasteBox because
pbPasteBox will clip anything outside if the viewable area. }
imgDrawingPad.Canvas.CopyRect(DestRect, PasteBitmap.Canvas, SrcRect);
pbPasteBox.Visible := false;
pbPasteBox.Enabled := false;
Pasted := False; // 完成粘贴操作
end;
procedure TMainForm.imgDrawingPadMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
Modified := True;
// Erase the clipping rectangle if one has been drawn
if (DrawType = dtClipRect) and EraseClipRect then
DrawToImage(MouseOrg, NextPoint, pmNotXOR)
else if (DrawType = dtClipRect) then
EraseClipRect := True; // Re-enable cliprect erasing
{ If an bitmap was pasted from the clipboard, copy it to the
image and remove the PaintBox. }
if Pasted then
CopyPasteBoxToImage;
Drawing := True;
// Save the mouse information
MouseOrg := Point(X, Y);
NextPoint := MouseOrg;
LastDot := NextPoint; // Lastdot is updated as the mouse moves
imgDrawingPad.Canvas.MoveTo(X, Y);
stbMain.Panels[0].Text := Format('原始鼠标位置坐标: (%d, %d)', [X, Y]);
end;
procedure TMainForm.imgDrawingPadMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
{ This method determines the drawing operation to be performed and
either performs free form line drawing, or calls the
DrawToImage method which draws the specified shape }
begin
if Drawing then
begin
if DrawType = dtCrooked then
begin
imgDrawingPad.Canvas.MoveTo(LastDot.X, LastDot.Y);
imgDrawingPad.Canvas.LineTo(X, Y);
LastDot := Point(X,Y);
end
else begin
DrawToImage(MouseOrg, NextPoint, pmNotXor);
NextPoint := Point(X, Y);
DrawToImage(MouseOrg, NextPoint, pmNotXor)
end;
end;
// 以当前鼠标位置更新状态条
stbMain.Panels[1].Text := Format('当前鼠标位置坐标: (%d, %d)', [X, Y]);
end;
procedure TMainForm.imgDrawingPadMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Drawing then
{ Prevent the clipping rectangle from destroying the images already
on the image }
if not (DrawType = dtClipRect) then
DrawToImage(MouseOrg, Point(X, Y), pmCopy);
Drawing := False;
end;
procedure TMainForm.sbLineClick(Sender: TObject);
begin
// First erase the cliprect if current drawing type
if DrawType = dtClipRect then
DrawToImage(MouseOrg, NextPoint, pmNotXOR);
{ Now set the DrawType field to that specified by the TSpeedButton
invoking this method. The TSpeedButton's Tag values match a
specific TDrawType value which is why the typecasting below
successfully assigns a valid TDrawType value to the DrawType field. }
if Sender is TSpeedButton then
DrawType := TDrawType(TSpeedButton(Sender).Tag);
// Now make sure the dtClipRect style doesn't erase previous drawings
if DrawType = dtClipRect then begin
EraseClipRect := False;
end;
// Set the drawing style
SetDrawingStyle;
end;
procedure TMainForm.cgDrawingColorsChange(Sender: TObject);
{ This method draws the rectangle representing fill and border colors
to indicate the users selection of both colors. pnlFgBgInner and
pnlFgBgBorder are TPanels arranged one on to of the other for the
desired effect }
begin
pnlFgBgBorder.Color := cgDrawingColors.ForeGroundColor;
pnlFgBgInner.Color := cgDrawingColors.BackGroundColor;
SetDrawingStyle;
end;
procedure TMainForm.SetDrawingStyle;
{ This method sets the various drawing styles based on the selections
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -