Визуальное построение эллипсов, прямоугольников ...
Пример позволяет рисовать эллипсы, прямоугольники, линии, кнопки с помощью мыши. Может пригодиться как часть программы по созданию редактора графики.
Платформа: Windows
Автор: Nastase Eodor
'2007 Nastase Eodor 'nastase_eodor@yahoo.com 'some graphical test #INCLUDE "Windows.bi" #INCLUDE "Win/CommCtrl.bi" Enum TShapeKind skLine,skRectangle,skEllipse,skButton End Enum Type TShape Private: FKind As TShapeKind FColor As Integer FBrush As HBRUSH FPenSize As Integer FPenStyle As Integer FBrushStyle As Integer FBrushHatched As Boolean Public: Collection As Any Ptr TopMost As Boolean SPoint As Point EPoint As Point Declare Property Kind As TShapeKind Declare Property Kind(Value As TShapeKind) Declare Property Color As Integer Declare Property Color(Value As Integer) Declare Sub Paint(Dc As HDC) Declare Sub Move(x As Integer,y As Integer) Declare Sub BringToFront Declare Operator Cast As Any Ptr Declare Constructor OnMouseDown As Sub(Byref Shape As TShape,B As Integer,x As Integer,y As Integer) OnMouseUp As Sub(Byref Shape As TShape,B As Integer,x As Integer,y As Integer) OnMouseMove As Sub(Byref Shape As TShape,x As Integer,y As Integer) End Type Type TShapes Parent As HWND Count As Integer Items As TShape Ptr Ptr Declare Sub Add(Shape As TShape Ptr) Declare Sub Remove(Shape As TShape Ptr) Declare Sub Exchange(Index1 As Integer,Index2 As Integer) Declare Function IndexOf(Shape As TShape Ptr) As Integer Declare Destructor End Type Property TShape.Kind As TShapeKind Return FKind End Property Property TShape.Kind(Value As TShapeKind) If Value <> FKind Then FKind = Value End If End Property Property TShape.Color As Integer Return FColor End Property Property TShape.Color(Value As Integer) Static As TShapes Ptr SL Dim As RECT R = Type(SPoint.x,SPoint.y,EPoint.x,EPoint.y) SL = Cast(TShapes Ptr,Collection) If Value <> FColor Then FColor = Value If FBrush Then DeleteObject FBrush FBrush = CreateSolidBrush(FColor) If SL Then RedrawWindow (SL->Parent,@R,0,RDW_ERASE Or RDW_INVALIDATE) End If End Property Sub TShape.Paint(Dc As HDC) Select Case Kind Case skRectangle Dim As HBRUSH oldBrush oldBrush = SelectObject(Dc,FBrush) Rectangle Dc,SPoint.x,SPoint.y,EPoint.x,EPoint.y SelectObject(Dc,oldBrush) Case skEllipse Dim As HBRUSH oldBrush oldBrush = SelectObject(Dc,FBrush) Ellipse Dc,SPoint.x,SPoint.y,EPoint.x,EPoint.y SelectObject(Dc,oldBrush) Case skButton Dim As HBRUSH oldBrush Dim As RECT R = Type(SPoint.x,SPoint.y,EPoint.x,EPoint.y) oldBrush = SelectObject(Dc,FBrush) DrawFrameControl(DC,@R,DFC_BUTTON,DFCS_BUTTONPUSH Or DFCS_ADJUSTRECT) SelectObject(Dc,oldBrush) Case skLine MoveToEx Dc,SPoint.x,SPoint.y,0 LineTo Dc,EPoint.x,EPoint.y End Select End Sub Sub TShape.Move(x As Integer,y As Integer) Static As TShapes SL SL = *Cast(TShapes Ptr,Collection) SPoint.x += x SPoint.y += y EPoint.x += x EPoint.y += y RedrawWindow SL.Parent,0,0,RDW_ERASE Or RDW_INVALIDATE End Sub Sub TShape.BringToFront Dim As Integer i Static As TShapes Ptr SL SL = Cast(TShapes Ptr,Collection) For i = 0 To SL->Count -1 SL->Items[i]->TopMost = 0 Next i SL->Items[SL->IndexOF(@This)]->TopMost = 1 If SL Then RedrawWindow SL->Parent,0,0,RDW_ERASE Or RDW_INVALIDATE End Sub Operator TShape.Cast As Any Ptr Return @This End Operator Constructor TShape FColor = &HFFFFFF FBRush = CreateSolidBrush(FColor) End Constructor Sub TShapes.Add(Shape As TShape Ptr) Count += 1 Items = Reallocate(Items,Sizeof(TShape)*Count) Items[Count -1] = Shape Items[Count -1]->Collection = @This ReDrawWindow Parent,0,0,RDW_INVALIDATE Or RDW_ERASE End Sub Sub TShapes.Remove(Shape As TShape Ptr) Dim As Integer i,Index Dim As TShape Ptr S Index = IndexOF(Shape) If Index <> -1 Then For i = Index + 1 To Count -1 S = Items[i -1] Items[i] = S Next i Count -= 1 Items = Reallocate(Items,Sizeof(TShape)*Count) End If End Sub Function TShapes.IndexOf(Shape As TShape Ptr) As Integer Dim As Integer i For i = 0 To Count -1 If Items[i] = Shape Then Return i Next i Return -1 End Function Sub TShapes.Exchange(Index1 As Integer,Index2 As Integer) Dim As TShape Ptr It It = Items[Index1] Items[Index1] = Items[Index2] Items[Index2] = It ReDrawWindow Parent,0,0,RDW_INVALIDATE Or RDW_ERASE End Sub Destructor TShapes If Items Then Deallocate Items End Destructor Type TForm Private: M As MSG Instance As HINSTANCE FText As String FLeft As Integer FTop As Integer FWidth As Integer FHeight As Integer FClientWidth As Integer FClientHeight As Integer Declare Sub DoCreate Declare Sub DoPaint Declare Sub DoCommand(Code As Integer,ID As Integer,FWindow As HWND) Declare Sub DoMouseDown(button As Integer,x As Integer,y As Integer,Shift As Integer) Declare Sub DoMouseUp(button As Integer,x As Integer,y As Integer,Shift As Integer) Declare Sub DoMouseMove(x As Integer,y As Integer,Shift As Integer) Declare Sub DoKeyDown(Key As Integer,Shift As Integer) Declare Sub DoKeyUp(Key As Integer,Shift As Integer) Declare Sub DoKeyPress(Key As Byte,Shift As Integer) Declare Static Function DefWndProc(FWindow As HWND,Msg As UINT,wParam As WPARAM,lParam As LPARAM) As LRESULT Declare Sub WndProc(FWindow As HWND,Msg As UINT,wParam As WPARAM,lParam As LPARAM) Declare Sub CreateWnd Public: MouseCapture As Boolean ShapeCount As Integer Shapes As TShapes Handle As HWND MainMenu As HMENU Declare Property Text As String Declare Property Text(Value As String) Declare Property Left As Integer Declare Property Left(Value As Integer) Declare Property Top As Integer Declare Property Top(Value As Integer) Declare Property Width As Integer Declare Property Width(Value As Integer) Declare Property Height As Integer Declare Property Height(Value As Integer) Declare Property ClientWidth As Integer Declare Property ClientHeight As Integer Declare Sub Run Declare Sub Terminate Declare Constructor Declare Destructor OnCommand As Sub(Byref Sender As TForm,Code As Integer,ID As Integer,FWindow As HWND) OnMouseDown As Sub(Byref Sender As TForm,button As Integer,x As Integer,y As Integer,Shift As Integer) OnMouseMove As Sub(Byref Sender As TForm,x As Integer,y As Integer,Shift As Integer) OnMouseUp As Sub(Byref Sender As TForm,button As Integer,x As Integer,y As Integer,Shift As Integer) End Type Property TForm.Text As String Dim As String Buff Dim As Integer L If Handle Then L = GetWindowTextLength(Handle) +1 Buff = String(L,0) GetWindowText(Handle,Buff,L) Else Return FText End If End Property Property TForm.Text(Value As String) FText = Value If Handle Then SetWindowText Handle,FText End Property Property TForm.Left As Integer Return FLeft End Property Property TForm.Left(Value As Integer) FLeft = Value If Handle Then MoveWindow Handle,FLeft,FTop,FWidth,FHeight,True End Property Property TForm.Top As Integer Return FTop End Property Property TForm.Top(Value As Integer) FTop = Value If Handle Then MoveWindow Handle,FLeft,FTop,FWidth,FHeight,True End Property Property TForm.Width As Integer Return FWidth End Property Property TForm.Width(Value As Integer) FWidth = Value If Handle Then MoveWindow Handle,FLeft,FTop,FWidth,FHeight,True End Property Property TForm.Height As Integer Return FHeight End Property Property TForm.Height(Value As Integer) FHeight = Value If Handle Then MoveWindow Handle,FLeft,FTop,FWidth,FHeight,True End Property Property TForm.ClientWidth As Integer Dim As Rect R GetClientRect Handle,@R FClientWidth = R.Right Return FClientWidth End Property Property TForm.ClientHeight As Integer Dim As Rect R GetClientRect Handle,@R FClientHeight = R.Bottom Return FClientHeight End Property Sub TForm.DoCreate MainMenu = CreateMenu DrawMenuBar Handle SetMenu Handle,MainMenu End Sub Sub TForm.DoCommand(Code As Integer,ID As Integer,FWindow As HWND) If OnCommand Then OnCommand(This,Code,Id,FWindow) End Sub Sub TForm.DoMouseDown(button As Integer,x As Integer,y As Integer,Shift As Integer) Dim As Point P Dim As Rect R Dim As Integer i If MouseCapture = 0 Then P = Type(x,y) For i = Shapes.Count -1 To 0 Step -1 R = Type(Shapes.Items[i]->SPoint.x,Shapes.Items[i]->SPoint.Y,Shapes.Items[i]->EPoint.x,Shapes.Items[i]->EPoint.Y) If PtInRect(@R,P) Then 'or pointinpolygon or ... If Shapes.Items[i]->OnMouseDown Then Shapes.Items[i]->OnMouseDown(*Shapes.Items[i],button,P.x-Shapes.Items[i]->SPoint.x,P.y-Shapes.Items[i]->SPoint.y) Exit Sub End If Next i End If If OnMouseDown Then OnMouseDown(This,button,x,y,Shift) End Sub Sub TForm.DoMouseUp(button As Integer,x As Integer,y As Integer,Shift As Integer) Dim As Point P Dim As Rect R Dim As Integer i If MouseCapture = 0 Then P = Type(x,y) For i = Shapes.Count -1 To 0 Step -1 R = Type(Shapes.Items[i]->SPoint.x,Shapes.Items[i]->SPoint.Y,Shapes.Items[i]->EPoint.x,Shapes.Items[i]->EPoint.Y) If PtInRect(@R,P) Then 'or pointinpolygon or ... If Shapes.Items[i]->OnMouseUp Then Shapes.Items[i]->OnMouseUp(*Shapes.Items[i],button,P.x-Shapes.Items[i]->SPoint.x,P.y-Shapes.Items[i]->SPoint.y) Exit Sub End If Next i End If If OnMouseUp Then OnMouseUp(This,button,x,y,Shift) End Sub Sub TForm.DoMouseMove(x As Integer,y As Integer,Shift As Integer) Dim As Point P Dim As Rect R Dim As Integer i If MouseCapture = 0 Then P = Type(x,y) For i = Shapes.Count -1 To 0 Step -1 R = Type(Shapes.Items[i]->SPoint.x,Shapes.Items[i]->SPoint.Y,Shapes.Items[i]->EPoint.x,Shapes.Items[i]->EPoint.Y) If PtInRect(@R,P) Then 'or pointinpolygon or ... If Shapes.Items[i]->OnMouseMove Then Shapes.Items[i]->OnMouseMove(*Shapes.Items[i],P.x-Shapes.Items[i]->SPoint.x,P.y-Shapes.Items[i]->SPoint.y) Exit Sub End If Next i End If If OnMouseMove Then OnMouseMove(This,x,y,Shift) End Sub Sub TForm.DoKeyDown(Key As Integer,Shift As Integer) End Sub Sub TForm.DoKeyUp(Key As Integer,Shift As Integer) End Sub Sub TForm.DoKeyPress(Key As Byte,Shift As Integer) End Sub Sub TForm.DoPaint Dim As Integer i Dim As Rect R Dim As PAINTSTRUCT Ps Dim As HDC Dc,MemDC Dim As HBITMAP Bmp Dim As TShape Ptr ST GetClientRect Handle,@R Dc = BeginPaint(Handle,@Ps) MemDC = CreateCompatibleDC(DC) Bmp = CreateCompatibleBitmap(DC,R.Right,R.Bottom) SelectObject(MemDc,Bmp) SendMessage(Handle,WM_ERASEBKGND, Cint(MemDC), Cint(MemDC)) For i = 0 To Shapes.Count -1 If *(Shapes.Items[i]).TopMost Then ST = Shapes.Items[i] If *(Shapes.Items[i]).TopMost = 0 Then *(Shapes.Items[i]).Paint(memDc) Next i If ST Then ST->Paint(memDc) BitBlt(DC, 0, 0, R.Right, R.Bottom, MemDC, 0, 0, SRCCOPY) DeleteObject(Bmp) DeleteDC(MemDC) EndPaint Handle, @Ps End Sub Sub TForm.WndProc(FWindow As HWND,Msg As UINT,wParam As WPARAM,lParam As LPARAM) Select Case Msg Case WM_PAINT DoPaint Case WM_CLOSE PostQuitMessage 0 Case WM_COMMAND DoCommand(Hiword(wParam),Loword(wParam),Cptr(HWND,lParam)) Case WM_LBUTTONDOWN DoMouseDown(0,Loword(lParam),Hiword(lParam),wParam And &HFFFF) Case WM_RBUTTONDOWN DoMouseDown(1,Loword(lParam),Hiword(lParam),wParam And &HFFFF) Case WM_MBUTTONDOWN DoMouseDown(2,Loword(lParam),Hiword(lParam),wParam And &HFFFF) Case WM_LBUTTONUP DoMouseUp(0,Loword(lParam),Hiword(lParam),wParam And &HFFFF) Case WM_RBUTTONUP DoMouseUp(1,Loword(lParam),Hiword(lParam),wParam And &HFFFF) Case WM_MBUTTONUP DoMouseUp(2,Loword(lParam),Hiword(lParam),wParam And &HFFFF) Case WM_MOUSEMOVE DoMouseMove(Loword(lParam),Hiword(lParam),wParam And &HFFFF) End Select End Sub Function TForm.DefWndProc(FWindow As HWND,Msg As UINT,wParam As WPARAM,lParam As LPARAM) As LRESULT Dim As TForm Ptr F F = Cast(TForm Ptr,GetWindowLong(FWindow,GWL_USERDATA)) If F Then F->WndProc(FWindow,Msg,wParam,lParam) Return DefWindowProc(FWindow,Msg,wParam,lParam) End Function Sub TForm.CreateWnd Handle = CreateWindowEx(0,_ "TForm",_ "Form",_ WS_OVERLAPPEDWINDOW Or WS_CLIPSIBLINGS Or WS_CLIPCHILDREN Or WS_VISIBLE ,_ FLeft,_ FTop,_ FWidth,_ FHeight,_ 0,_ 0,_ Instance,_ 0) If Handle Then SetWindowLong Handle,GWL_USERDATA, Cint(@This) End If End Sub Sub TForm.Run While GetMessage(@M,0,0,0) DispatchMessage @M TranslateMessage @M Wend End End Sub Sub TForm.Terminate PostQuitMessage 0 End End Sub Constructor TForm Dim As WNDCLASS Wc InitCommonControls Instance = GetModuleHandle(NULL) If GetClassInfo(Instance,"TForm",@Wc) = 0 Then Wc.hInstance = GetModuleHandle(NULL) Wc.hbrBackground = Cast(HBRUSH,16) Wc.hCursor = LoadCursor(NULL,IDC_ARROW) Wc.lpszClassName = Strptr("TForm") Wc.lpfnWndProc = @DefWndProc RegisterClass(@Wc) End If FWidth = 700 FHeight = 500 CreateWnd DoCreate Shapes.Parent = Handle End Constructor Destructor TForm UnregisterClass "TForm", GetModuleHandle(NULL) If Handle Then DestroyWindow Handle End Destructor ''''''''Sample Declare Sub ShapeMouseDown(Sender As TShape,b As Integer,x As Integer,y As Integer) Declare Sub ShapeMouseMove(Sender As TShape,x As Integer,y As Integer) Declare Sub ShapeMouseUp(Sender As TShape,x As Integer,y As Integer) Declare Sub FormCommand(Sender As TForm,Code As Integer,ID As Integer,FWindow As HWND) Declare Sub FormMouseDown(Sender As TForm,b As Integer,x As Integer,y As Integer,Shift As Integer) Declare Sub FormMouseMove(Sender As TForm,x As Integer,y As Integer,Shift As Integer) Declare Sub FormMouseUp(Sender As TForm,b As Integer,x As Integer,y As Integer,Shift As Integer) Dim Shared As TShape Ptr Shape Dim Shared As TForm Form Form.OnCommand = @FormCommand Form.OnMouseDown = @FormMouseDown Form.OnMouseMove = @FormMouseMove Form.OnMouseUp = @FormMouseUp Dim Shared As Boolean Down,CanDraw Dim Shared As Integer Bx,By,Ex,Ey Dim As HMENU File File = CreatePopupMenu AppendMenu Form.MainMenu,MF_POPUP Or MF_STRING,Cint(File),"File" AppendMenu File,MF_STRING ,100,"Rectangle" AppendMenu File,MF_STRING,101,"Ellipse" AppendMenu File,MF_STRING,102,"Button" AppendMenu File,MF_STRING,103,"Line" AppendMenu File,MF_SEPARATOR,-1,"-" AppendMenu File,MF_STRING,104,"Move" AppendMenu File,MF_STRING,105,"Resize" AppendMenu File,MF_SEPARATOR,-1,"-" AppendMenu File,MF_STRING,106,"Exit" DrawMenuBar Form.Handle Form.Run Sub DrawBox(Form As TForm,x1 As Integer,y1 As Integer,x2 As Integer,y2 As Integer) Dim As HDC Dc Dim As HBRUSH B,oldB Dc = GetDCEx(Form.Handle,0,DCX_PARENTCLIP Or DCX_CACHE) B = GetStockObject(NULL_BRUSH) oldB = SelectObject(Dc,B) SetROP2 Dc,R2_NOT Rectangle Dc,x1,y1,x2,y2 SelectObject(Dc,oldB) ReleaseDC Form.Handle,Dc End Sub Sub FormCommand(Sender As TForm,Code As Integer,ID As Integer,FWindow As HWND) CheckMenuRadioItem(Sender.MainMenu,100,103,ID,MF_BYCOMMAND) Select Case ID Case 100 Shape = Allocate(Sizeof(TShape)) Shape->Kind = skRectangle CanDraw = 1 Case 101 Shape = Allocate(Sizeof(TShape)) Shape->Kind = skEllipse CanDraw = 1 Case 102 Shape = Allocate(Sizeof(TShape)) Shape->Kind = skButton CanDraw = 1 Case 103 Shape = Allocate(Sizeof(TShape)) Shape->Kind = skLine CanDraw = 1 End Select End Sub Sub FormMouseDown(Sender As TForm,b As Integer,x As Integer,y As Integer,Shift As Integer) Bx = x By = y Ex = x Ey = y If CanDraw Then Down = 1 Sender.MouseCapture = 1 Else Sender.MouseCapture = 0 End If End Sub Sub FormMouseMove(Sender As TForm,x As Integer,y As Integer,Shift As Integer) If Down Then DrawBox Form,Bx,By,Ex,Ey DrawBox Form,Bx,By,x,y End If Ex = x Ey = y End Sub Sub FormMouseUp(Sender As TForm,b As Integer,x As Integer,y As Integer,Shift As Integer) Down = 0 If CanDraw Then CanDraw = 0 DrawBox Form,Bx,By,Ex,Ey Shape->SPoint = Type(Bx,By) Shape->EPoint = Type(Ex,Ey) Shape->OnMouseDown = @ShapeMouseDown Shape->OnMouseMove = @ShapeMouseMove Sender.Shapes.Add Shape Sender.MouseCapture = 0 End If CheckMenuRadioItem(Sender.MainMenu,100,103,-1,MF_BYCOMMAND) Ex = Bx Ey = By End Sub Sub ShapeMouseMove(Sender As TShape,x As Integer,y As Integer) Form.Text = "Simple Graphic " & "Shape = " & Str(@sender)+" X = " & Str(x) & " Y = " & Str(y) End Sub Sub ShapeMouseDown(Sender As TShape,b As Integer,x As Integer,y As Integer) MessageBox Form.Handle,"Shape MouseDown "& "Shape = " & Str(@sender)," X = " & Str(x) & " Y = " & Str(y),0 Sender.BringToFront End Sub