salvadordf / WebView4Delphi

WebView4Delphi is an open source project created by Salvador Díaz Fau to embed Chromium-based browsers in applications made with Delphi or Lazarus/FPC for Windows.
https://www.briskbard.com/forum/
MIT License
282 stars 59 forks source link

Issue when change parent of form #13

Closed amancini closed 2 years ago

amancini commented 2 years ago

Hello,

if you change the parent of the form that hosts the WVBroser, you go to create an inconsistency in the CoreWebView2Controller interface which is invisible and without parent.

i also tried re-assigning the parentWindow and resetting the visibility but it doesn't work.

I think it's a Microsoft bug, do you know any workarounds?

you can easily reproduce the problem through the tabbedBrowser demo unit that I modified and attached

best regards TabbedBrowserChange.zip

salvadordf commented 2 years ago

Try setting TWVBrowser.ParentWindow to a THandle of another control before reparenting the form.

Let's say you hay 2 forms : FormA and FormB.

If you want to reparent FormA and it has a browser then you have to follow these steps :

I tested this method with a beta version of BriskBard and it works.

amancini commented 2 years ago

at the moment i found this solution

maybe it can be useful to you

private
    FRestoreHandle       : Boolean;
    aFormTmp               : TForm;

procedure TFormBrowserEDGE.WndProc(var Message: TMessage);
begin
  inherited;
  if csDestroying in Self.ComponentState then Exit;
  if (csRecreating in ControlState) then
    ChangeParent
  else if FRestoreHandle then
    RestoreParent;

end;

procedure TFormBrowserEDGE.ChangeParent;
begin
  if csDestroying in Self.ComponentState then Exit;
  if ( WVBrowser1 <> nil) and (WVBrowser1.Initialized) then
  begin
    if not Assigned(aFormTmp) then
    begin
      aFormTmp        := TForm.Create(nil);
    end;
    if aFormTmp.Handle <> WVBrowser1.ParentWindow then
      WVBrowser1.ParentWindow := aFormTmp.Handle;
    FRestoreHandle := True;
  end;
end;

procedure TFormBrowserEDGE.RestoreParent;
begin
  if csDestroying in Self.ComponentState then Exit;

  if ( WVBrowser1 <> nil ) and FRestoreHandle and WVBrowser1.Initialized then
  begin
    if WVBrowser1.ParentWindow <> WVWindowParent1.Handle then
    begin
      WVBrowser1.ParentWindow := WVWindowParent1.Handle;
      WVBrowser1.NotifyParentWindowPositionChanged;
      WVWindowParent1.UpdateSize;
    end;
    FRestoreHandle := False;
    if Assigned(aFormTmp) then
      FreeAndNil(aFormTmp);
  end;
end;

Procedure TFormBrowserEDGE.FormDestroy
begin
    if Assigned(aFormTmp) then
      FreeAndNil(aFormTmp);
end;
roknjohn commented 1 year ago

I think I understand the steps here. But let me pose another scenario:

The architecture of my application consists of a MainForm with a MainPanel, and many various ChildForms, each with a with ChildPanel. The ChildForms are always hidden, but at any point in time, one and only one of the ChildPanels is parented to the MainPanel, e.g. ChildFormA.ChildPanel.Parent := MainForm.MainPanel. As a child panel is switched out, their original parent is restored, e.g. ChildFormA.ChildPanel.Parent := ChildFormA; This gives a "midi" style effect and works great.

I also have another form, WVForm, with a WVPanel and on that, there is a WVBrowser and WVWindowParent.

Here's what I'm trying to do..

1) I want to "embed" the browser onto one of my child forms, say ChildFormB.ChildPanel. Keep in mind that this child panel gets parented to MainPanel, which can be swapped out with other child panels over time. I need to make sure that whenever ChildFormB.ChildPanel is set to MainPanel, the browser function is properly restored and resized.

2) I also want to allow a "popout" function, which will show a modeless WVForm , separate from my MainForm, to allow the user a full screen mode or to use it on another monitor. Here, the WVPanel would be reparented to WVForm, then shown in a different window, i.e. WVForm.Show;

What do I need to do to restore the WVBrowser function whenever ChildFormB.ChildPanel parent changes or if the WVForm is shown. Are there any special considerations that I need to be aware of here?

salvadordf commented 1 year ago

@roknjohn It should be possible to do what you describe. Follow the steps I gave previously and call NotifyParentWindowPositionChanged and UpdateSize when necessary as @amancini showed.

Alternatively, consider creating TFrames with embedded browsers at runtime as you can see in the TabbedBrowser demo.

Edit: I forgot to mention that moving browsers between monitors can be tricky because they can have different scale. I haven't tried this scenario.