2

我尝试创建一个弹出 Treeview 的自定义 Combobox 控件。一切看起来都很好。但是当我尝试向该控件添加运行时调整大小功能时,弹出窗口(Treeview)只是移动并且不会改变它的大小。

任何建议将不胜感激。

弹出窗口的片段:

创建时

ControlStyle := ControlStyle + [csNoDesignVisible, csReplicatable, csDoubleClicks];

在创建参数

begin
  inherited CreateParams(Params);
  with Params do
  begin
    Style := Style or WS_POPUP or WS_VSCROLL or WS_BORDER;
    ExStyle := WS_EX_TOOLWINDOW;
    AddBiDiModeExStyle(ExStyle);
    //WindowClass.Style := CS_SAVEBITS; {this would prevent ondoubleclick event}
  end;

鼠标移动:

var
  ARect, RR: TRect;
  DragStyle: TDragStyle;
  Procedure SetDragStyle(ds:TDragStyle; c:TCursor);
  begin
    FDragStyle:=ds;
    Cursor:=c;
  end;
begin
  inherited;
  FMouseMoveSelected := GetNodeAt(x, y);
  if FDragged then begin
    case FDragStyle of
       dsSizeLeft :begin
                      SetWindowPos(Handle, HWND_TOP, Left+(x-FDragPos.X), Top, Width, Height,
                        SWP_NOACTIVATE or SWP_SHOWWINDOW);
                      //Left:=Left+(x-FDragPos.X); {alternate code that doesn't work either}
                   end;
    end;
    FDragPos:=Point(x,y);
  end else begin
    SetDragStyle(dsMove,crDefault);
    ARect := GetClientRect;
    RR:=ARect;
    InflateRect(RR,-2,-2);
    if (x>=0) and (x<=Width) and (y>=0) and (y<=Height) and (not PtInRect(RR,Point(x,y))) then begin
      if (x<=RR.Left) then begin
        //if (y<=RR.Top) then SetDragStyle(dsSizeTopLeft,crSizeNWSE)else
        if (y>=RR.Bottom) then SetDragStyle(dsSizeBottomLeft,crSizeNESW)
        else SetDragStyle(dsSizeLeft,crSizeWE); 
      end else if (x>=RR.Right) then begin
        //if (y<=RR.Top) then SetDragStyle(dsSizeTopRight,crSizeNESW) else
        if (y>=RR.Bottom) then SetDragStyle(dsSizeBottomRight,crSizeNWSE)
        else SetDragStyle(dsSizeRight,crSizeWE);
      end else begin
        //if (y<=RR.Top) then SetDragStyle(dsSizeTop,crSizeNS) else
        if (y>=RR.Bottom) then SetDragStyle(dsSizeBottom,crSizeNS)
        else SetDragStyle(dsMove,crDefault);
      end;
    end;
  end;
end;
end;

鼠标按下时

begin
  inherited;
  if FDragStyle<>dsMove then begin
    FDragPos:=point(x,y);
    FDragged:=true;
  end;
end;

鼠标上移

begin
  inherited;
  FDragged:=false;
end;
4

1 回答 1

4

您在SetWindowPos通话中将客户端坐标与屏幕坐标混合。那是因为您正在浮动一个不应该浮动的窗口,而 VCL 对此一无所知。当您引用它Left时,VCL 返回一个相对于其父级的坐标,可能是表单。也不要更改在拖动过程中开始拖动时保存的点(即 FDragPos):

procedure TPanel.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  ARect, RR: TRect;
  DragStyle: TDragStyle;

  Procedure SetDragStyle(ds:TDragStyle; c:TCursor);
  begin
    FDragStyle:=ds;
    Cursor:=c;
  end;

  var
    DragOffset: Integer;
begin
  inherited;
  FMouseMoveSelected := GetNodeAt(x, y);
  if FDragged then begin
    case FDragStyle of
       dsSizeLeft:
         begin
            DragOffset := X - FDragPos.X;
            winapi.windows.GetWindowRect(Handle, ARect);
            SetWindowPos(Handle, HWND_TOP,
                                  ARect.Left + DragOffset,
                                  ARect.Top,
                                  ARect.Right - ARect.Left - DragOffset,
                                  ARect.Bottom - ARect.Top,
                                  SWP_NOACTIVATE or SWP_SHOWWINDOW);
            //Left:=Left+(x-FDragPos.X); {alternate code that doesn't work either}
         end;
    end;
//    FDragPos:=Point(x,y);  // do not change drag origin while you're dragging
  end else begin
    ..
于 2012-05-05T20:43:53.363 回答