delphi 使窗体内的窗体在单击时捕获焦点

jmp7cifd  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(202)

在 Delphi 中,你可以通过改变TForm.Parent属性在另一个窗体中创建一个窗体。
有两种方法可以在另一个窗体中创建窗体

正规形式(fsNormal

下面是一个在表单中创建表单的示例

with TForm.Create(Self) do
    begin
      Parent := Self;
      Caption := 'Test 1';

      Width := 350;
      Height := 200;

      Show;
    end;

字符串
问题是它们在与它们交互时不能正常工作。捕获焦点只能通过单击标题栏或使用Form.SetFocus来实现,它们包含的控件也是如此。表单将出现在表单可能包含的任何TWinControls或TGraphicControl之上。


的数据

MDI Forms('fsMDICild')

正确的方法是使用MDI表单。像这样:

Form.Style := fsMDIForm;

  with TForm.Create(Self) do
    begin
      Parent := Self;
      Caption := 'Test 1';

      Width := 350;
      Height := 200;

      FormStyle := fsMDIChild;
      Show;
    end;

  with TForm.Create(Self) do
    begin
      Parent := Self;
      Caption := 'Test 2';

      Width := 350;
      Height := 200;

      FormStyle := fsMDIChild;
      Show;
    end;


然后表单将正常运行。像这样:

问题是

MDI表单将完美地为我的用例工作,如果不是2个问题:

  1. fsMDIForm边界,称为“ClientEdge”
    1.窗体内的控件显示在MDI窗体的上方
    第一个问题可以通过覆盖ClientWndProc轻松解决。过程如下:
procedure ShowMDIClientEdge(ClientHandle: THandle; ShowEdge: Boolean);
var
  Style: NativeInt;
begin
  if ClientHandle <> 0 then
  begin
    Style := GetWindowLong(ClientHandle, GWL_EXSTYLE);
    if ShowEdge then
      if Style and WS_EX_CLIENTEDGE = 0 then
        Style := Style or WS_EX_CLIENTEDGE
      else
        Exit
    else if Style and WS_EX_CLIENTEDGE <> 0 then
      Style := Style and not WS_EX_CLIENTEDGE
    else
      Exit;
    SetWindowLong(ClientHandle, GWL_EXSTYLE, Style);
    SetWindowPos(ClientHandle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or SWP_NOACTIVATE or
      SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER);
  end;
end;

procedure TForm1.ClientWndProc(var Message: TMessage);
begin
  if Message.Msg = $3F then
    begin
      ShowMDIClientEdge(ClientHandle, false);
      Exit;
    end;

  inherited;
end;


但是第二个问题是MDI表单出现在我认为的组件下面,这是无法解决的。这使得fsNormal方法更有吸引力,如果表单能够正常工作并捕获焦点的话。
简而言之,我需要一个表单在另一个表单中,它可以:

  • 保持在客户端区域内,因此它不能离开或被绘制到客户端之外
  • 出现在窗体内的控件上方
  • 专注

那么为什么fsNormal表单无法捕获焦点呢?

htrmnn0y

htrmnn0y1#

我首先使用Athens创建了fsNormal设置,然后使用Alexandria进行了测试。
子窗体OnCreate过程我刚刚添加了代码,其中Form2 parent设置为Form1。

procedure TForm2.FormCreate(Sender: TObject);
begin
  Parent := Form1;
end;

字符串
在Alexandria上关注表单在标题栏之外的地方点击的问题可以通过将其放在OnMouseDown事件的前面来解决。D12不再有这个问题。

procedure TForm2.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  BringtoFront;
end;


一个恼人的问题仍然存在,那就是当你直接移动窗体的标题栏,它将保持在其他子窗体下,直到你点击它.但我解决了这个问题在windows事件WMMoving通过添加BringToFront在它.你也提到子窗体不应该走出Form1边界,它也可以很容易地解决在WMMoving事件.

procedure TForm2.WMMoving( var msg : TWMMoving );
  var
    moveArea : TRect;
  begin
    BringtoFront;
    moveArea := Form1.BoundsRect;

    with msg.DragRect^ do
    begin
      if Left < moveArea.Left
      then
        OffsetRect( msg.DragRect^, moveArea.Left - Left, 0 );

      if Top < moveArea.Top
      then
        OffsetRect( msg.DragRect^, 0, moveArea.Top - Top );

      if Right > moveArea.Right
      then
        OffsetRect( msg.DragRect^, moveArea.Right - Right, 0 );

      if Bottom > moveArea.Bottom
      then
        OffsetRect( msg.DragRect^, 0, moveArea.Bottom - Bottom );
    end;
    inherited;
end;


当使用windows事件时,你也需要将其添加到Form类中。

procedure WMMoving( var msg : TWMMoving ); message WM_MOVING;


例如,当在窗体内部单击按钮时,子窗体没有将其更改为顶部,而不是窗体本身仍然存在。一个选项是当鼠标进入窗体时,将窗体置于前面。

procedure TForm2.FormMouseEnter(Sender: TObject);
begin
  SetFocus;
  BringtoFront;
end;


这些工作在D11和D12,我没有任何旧版本的测试。
这个旧的组件还在工作。
https://torry.net/components/forms/other/ttopmost
我希望这将有助于你推进你的项目。

相关问题