0

Мне нужно нарисовать произвольный прямоугольник и реализовать его растяжения, т.е. щёлкнули мышью по одной стороне, переместили курсор и сторона потялась за ним. Программу написал, но она работает, только если окно с рисунком полностью развернуть, знаю в чем ошибка (несоответствие координат рабочей области и экрана), но не могу никак исправить. Помогите, пожалуйста.

program Win1;

uses
  Windows,
  Messages;

var
  WndClass: TWndClass;
  szAppName: PChar;
  WinHandle: HWnd;
  Msg: TMsg;
  Pen: HPen;
  x1,y1,x2,y2: Integer;
  b1,b2,b3,b4,i,k,k1,i1: Integer;
  a1:Integer=100;
  a2:Integer=100;
  a3:Integer=550;
  a4:Integer=300;

function MyWndProc (hWnd: HWND; Msg: UINT; wParam:WPARAM;
  lParam: LPARAM) : LRESULT; stdcall;

var
  ps: TPaintStruct;
  Context: HDC;
  Font: HFont;
 gpoint: tpoint;

begin
case Msg of
 WM_MOUSEMOVE :
   begin  // Перемещаем левую сторону
     if  k=1
       then begin
         if  (wParam= MK_LBUTTON)
           then begin
                  Context := GetDC (hWnd) ;
                  GetCursorPos(gpoint);

                  x2 := gpoint.x;
                  y2 := gpoint.y;SelectObject (Context, GetStockObject (WHITE_PEN));
                    if x1<a3
                      then Rectangle(Context, a1+b1-5, a2, a3, a4)
                      else Rectangle(Context, a1+b1+5, a2, a3, a4);
                       b1:=x2-x1;
                       b2:=y2-y1;
                      SelectObject (Context, GetStockObject (BLACK_PEN)) ;
                      Rectangle(Context, a1+b1, a2, a3, a4);
                end;
             ReleaseDC (hWnd, context) ;
             result:= 0;
           end;

    .............. и.д. (правую, верхнюю, нижнюю)

  WM_PAINT:
    begin

      Context := BeginPaint(hWnd, ps);
      try
        SelectObject(Context, Pen);
        Rectangle(Context, a1, a2, a3, a4);
      finally
        EndPaint(hWnd, ps);
        Result := 0;
      end;
    end;

 WM_LBUTTONDOWN : // захватываем левую сторону
    begin
      SetCapture(hwnd);
      GetCursorPos(gpoint);
     x1 := gpoint.x;
     y1 := gpoint.y;   
         if a2<a4
            then begin
                 if  (x1>(a1-5)) and (x1<a1+5) and (y1>(a2+5))  and (y1<(a4-5))
                   then k:=1;
                 end;
                 //if x1= pt[0].x
                 //then k:=1;

          if a2>a4
            then begin
                   if  (x1>(a1-5)) and (x1<(a1+5)) and (y1<(a2-5))  and (y1>(a4+5))
                     then k:=1;
                 end;  (и.д. ............)
 WM_LBUTTONUP :
    begin
      ReleaseCapture();
      k:=0;
      k1:=0;
      i:=0;
      i1:=0;
        if  (x1>(a1-5)) and (x1<(a1+5)) and (y1>(a2+5)) and (y1<(a4-5))
             or  (x1>(a1-5)) and (x1<(a1+5)) and (y1<(a2-5))  and (y1>(a4+5))
          then a1:=a1+b1;
(.................)

создаём окно...........

1 ответ 1

4

Меня лично пугают вещи вроде (x1 > a1 - 5) and (y1 < a2 - 5), поэтому опишу способ, как бы я решал данную задачу.


У вас есть некоторый прямоугольник, который задается 4 параметрами - x, y, width, height, и, очевидно, есть объект (или просто набор переменных), где эти значения хранятся.

Вам нужно понять, какой именно параметр менять в зависимости от того, где был сделан щелчок кнопкой мыши, для сохранения этого следует использовать аналог enum в Delphi:

type
  TRectangleChangingDirection = (ChangingX, ChangingY, ChangingWidth, ChangingHeight);

Дальше последовательность действий очевидна:

  • WM_LBUTTONDOWN: Определить, какой именно параметр прямоугольника будет изменяться и записать это значение в переменную типа TRectangleChangingDirection. Также изначальное положение курсора, т.к именно от него будет отсчитываться изменение параметров прямоугольника, назовем эту переменную rectangleChangeStartCursorPosition.

  • WM_MOUSEMOVE: Получить вектор cursorDifference = currentPosition - rectangleChangeStartCursorPosition. Из него, в зависимости от изменяемого параметра в прямоугольнике взять координату x или y и прибавить ее к этому самому изменяемому параметру прямоугольника. В зависимости от желаемого поведения, здесь можно, например, поставить ограничения, что, скажем, прямоугольник не может иметь отрицательную ширину и т.п. Записать измененное значение в параметры прямоугольника.

  • WM_BUTTONUP: Ничего делать не нужно, т.к изменения уже были записаны в параметры прямоугольника.

  • WM_PAINT: Отрисовать прямоугольник по текущим сохраненным параметрам.


Если вы, например, хотите допустить возможность отменять изменения прямоугольника (скажем, по кнопке ESC), то необходимо создавать 2 набора параметров (x, y, width, height) - до начала изменения и во время изменения и, в зависимости от действия пользователя, применять изменения или, наоборот, откатывать их к изначальному состоянию. Получается такое тривиальное применение Transaction Pattern с соответствующим rollback'ом.

Ваш ответ

By clicking “Отправить ответ”, you agree to our terms of service and acknowledge you have read our privacy policy.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками или задайте свой вопрос.