• 在做一个下来窗口的时候,一般使用PopupEdit来实现,不过使用PopupEdit有一个缺点,那就是PopupEdit的下拉内容一出现那么编辑框就不能编辑了,为了解决这个问题,
    可以自己使用buttonEdit来模拟PopupEdit的操作,只有当点击下拉按钮的时候下拉框(也就是一个窗体)才会出现。
  • 大体思路,点击下拉按钮,出现一个新的窗体(ShowModal的形式),这个窗体的位置在buttonEdit的下面,点击其他的地方(非窗口中的内容)这个窗口会关闭。
  • 难点:1. 窗体的位置在ButtonEdit的下面。2. 当点击其他位置的时候这个窗口关闭。
  1. 窗口的位置:1. 获取ButtonEdit的位置坐标,将这个坐标转换为屏幕坐标。
var
  EditorOrigin: TPoint;
  BtnEdt: TcxButtonEdit;
begin
  EditorOrigin.Y := BtnEdt.Height;
  EditorOrigin.X := 0;
  EditorOrigin := BtnEdt.ClientToScreen(EditorOrigin);  
  ShowDialog(EditorOrigin.X, EditorOrigin.Y);
end;
  1. 当点击其他位置的时候,这个窗口要关闭,那么肯定要重写Application.OnMessage; 当这个窗口不在active的时候 ModalResult := mrCancel;
procedure CMMOUSEENTER(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
procedure WMACTIVATE(var Msg: TWMActivate); message WM_ACTIVATE;
procedure OnMessage(var Msg: TMsg; var Handled: Boolean);
function ShowModal: Integer; override;

function ShowDialog(X, Y: Integer): Boolean;
begin
  Result := False;
  with TfrmDialog.Create(nil) do
  try
    Left := X;
    Top := Y;
    FOldOnMsg := Application.OnMessage;
    Application.OnMessage := OnMessage;
    ShowModal;
    Application.OnMessage := FOldOnMsg;
    if (ModalResult = mrOk) or (ModalResult = mrCancel) then
    begin
      Result := True;
      // do something
    end;
  finally
    Free;
  end;
end;

procedure TfrmDialog.CMMOUSEENTER(var Message: TMessage);
begin
// ReleaseCapture();
end;

procedure TfrmDialog.CMMouseLeave(var Message: TMessage);
begin
// SetCaptureControl(tlFlValue);
end;

procedure TfrmDialog.WMACTIVATE(var Msg: TWMActivate);
begin
  if Msg.Active = WA_INACTIVE then
  begin
    ModalResult := mrCancel;
  end;
  inherited;
end;

function TfrmDialog.ShowModal: Integer;
var
  // WindowList: TTaskWindowList;
  LSaveFocusState: TFocusState;
  // SaveCursor: TCursor;
  // SaveCount: Integer;
  // ActiveWindow: HWnd;
begin
  LSaveFocusState := nil;
  CancelDrag;
  if GetCapture <> 0 then
    SendMessage(GetCapture, WM_CANCELMODE, 0, 0);
  ReleaseCapture;
  Application.ModalStarted;
  try
    { RecreateWnd could change the active window }
    // ActiveWindow := GetActiveWindow;
    Include(FFormState, fsModal);
    if (PopupMode = pmNone) and (Application.ModalPopupMode <> pmNone) then
    begin
      RecreateWnd;
      HandleNeeded;
      { The active window might have become invalid, refresh it }
      // if (ActiveWindow = 0) or not IsWindow(ActiveWindow) then
      // ActiveWindow := GetActiveWindow;
    end;
    Screen.SaveFocusedList.Insert(0, Screen.FocusedForm);
    Screen.FocusedForm := Self;
    // SaveCursor := Screen.Cursor;
    Screen.Cursor := crDefault;
    // SaveCount := Screen.CursorCount;
    try
      Show;
      try
        SendMessage(Handle, CM_ACTIVATE, 0, 0);
        ModalResult := 0;
        repeat
          Application.HandleMessage;
          if Application.Terminated then
            ModalResult := mrCancel
          else
            if ModalResult <> 0 then
            CloseModal;
        until ModalResult <> 0;
        Result := ModalResult;
        SendMessage(Handle, CM_DEACTIVATE, 0, 0);
        // if GetActiveWindow <> Handle then ActiveWindow := 0;
      finally
        Hide;
      end;
    finally
      if Screen.SaveFocusedList.Count > 0 then
      begin
        Screen.FocusedForm := TCustomForm(Screen.SaveFocusedList.First);
        Screen.SaveFocusedList.Remove(Screen.FocusedForm);
      end
      else
        Screen.FocusedForm := nil;
      RestoreFocusState(LSaveFocusState);
      Exclude(FFormState, fsModal);
    end;
  finally
    Application.ModalFinished;
  end;
end;

procedure TfrmDialog.OnMessage(var Msg: TMsg;
  var Handled: Boolean);
begin
  if Msg.message in [WM_NCLBUTTONDOWN, WM_NCRBUTTONDOWN] then
    Handled := True
  else
    if Assigned(FOldOnMsg) then
      FOldOnMsg(Msg, Handled);
end;
posted on 2020-12-28 10:22  liannngwei  阅读(185)  评论(0编辑  收藏  举报