- 在做一个下来窗口的时候,一般使用PopupEdit来实现,不过使用PopupEdit有一个缺点,那就是PopupEdit的下拉内容一出现那么编辑框就不能编辑了,为了解决这个问题,
可以自己使用buttonEdit来模拟PopupEdit的操作,只有当点击下拉按钮的时候下拉框(也就是一个窗体)才会出现。
- 大体思路,点击下拉按钮,出现一个新的窗体(ShowModal的形式),这个窗体的位置在buttonEdit的下面,点击其他的地方(非窗口中的内容)这个窗口会关闭。
- 难点:1. 窗体的位置在ButtonEdit的下面。2. 当点击其他位置的时候这个窗口关闭。
- 窗口的位置: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;
- 当点击其他位置的时候,这个窗口要关闭,那么肯定要重写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;