TChromium ChromeTabs无效

时间:2013-07-16 17:07:19

标签: delphi delphi-xe3 tchromium

我想为我的TChromium做一个标签。
我有这个:

   Browsers: array[0..1000] of TChromium;

这个ChromeTabs程序:

    procedure TForm1.ChromeTabsActiveTabChanged(Sender: TObject; ATab: TChromeTab);
    var
    c:integer;
    begin
    for c := 0 to ChromeTabs.Tabs.Count do
       if browsers[c]<>NIL then
        if c=ChromeTabs.ActiveTabIndex then browsers[c].Visible:=true else browsers[c].visible:=false;
    end;



procedure TForm1.ChromeTabsButtonAddClick(Sender: TObject;
  var Handled: Boolean);
begin
browsers[ChromeTabs.ActiveTabIndex]:=TChromium.Create(Chromium);
browsers[ChromeTabs.ActiveTabIndex].OnAddressChange:=Chromium.OnAddressChange;
browsers[ChromeTabs.ActiveTabIndex].OnAfterCreated:=Chromium.OnAfterCreated;
browsers[ChromeTabs.ActiveTabIndex].OnBeforeContextMenu:=Chromium.OnBeforeContextMenu;
browsers[ChromeTabs.ActiveTabIndex].OnBeforePopup:=Chromium.OnBeforePopup;
browsers[ChromeTabs.ActiveTabIndex].OnLoadEnd:=Chromium.OnLoadEnd;
browsers[ChromeTabs.ActiveTabIndex].OnLoadError:=Chromium.OnLoadError;
browsers[ChromeTabs.ActiveTabIndex].OnLoadingStateChange:=Chromium.OnLoadingStateChange;
browsers[ChromeTabs.ActiveTabIndex].OnProcessMessageReceived:=Chromium.OnProcessMessageReceived;
browsers[ChromeTabs.ActiveTabIndex].OnStatusMessage:=Chromium.OnStatusMessage;
browsers[ChromeTabs.ActiveTabIndex].DefaultEncoding:=Chromium.DefaultEncoding;

browsers[ChromeTabs.ActiveTabIndex].parent:=Form1;
browsers[ChromeTabs.ActiveTabIndex].Align:=alClient;
browsers[ChromeTabs.ActiveTabIndex].Show;
browsers[ChromeTabs.ActiveTabIndex].Load(Chromium.DefaultUrl);
end;



procedure TForm1.ChromeTabsButtonCloseTabClick(Sender: TObject;
  ATab: TChromeTab; var Close: Boolean);
begin
browsers[ATab.Index].Destroy;
Close:=True;
end;

Chromium对象是我的默认浏览器,我放在我的表格上。

因此,当我试图关闭其中一个标签时,它有时会出现访问冲突错误 当我尝试从Adress_Line加载Url时,它会出现访问冲突错误 此外,当我打开2个或更多Tabs时,它们看起来很糟糕,就像这样 - http://s43.radikal.ru/i101/1307/99/650e18d5e190.jpg

请帮我解决所有这些问题:(

Thanks.

1 个答案:

答案 0 :(得分:2)

访问冲突异常的问题是由已经销毁的对象调用Destroy方法引起的。让我解释一下情况。

想象一下,您有3个带有下一个索引的选项卡和带有以下浏览器实例的Browsers数组:

ChromeTabs.Tabs            Browsers
----------------------     ----------------------
Index       Tab name       Index       Browser
----------  ----------     ----------  ----------
0           Tab 1          0           Browser 1
1           Tab 2          1           Browser 2
2           Tab 3          2           Browser 3

现在,您点击中间标签的关闭按钮(标签为1的标签),然后点击OnButtonCloseTabClick运行此标签:

procedure TForm1.ChromeTabsButtonCloseTabClick(Sender: TObject;
  ATab: TChromeTab; var Close: Boolean);
begin
  // the ATab.Index equals 1
  Browsers[ATab.Index].Destroy;
  Close := True;
end;

这将从上表中销毁名为Browser 2的浏览器实例。当数组作为Tabs集合重新编制索引时,这不会有问题。让我们看一下标签和数组会发生什么:

ChromeTabs.Tabs            Browsers
----------------------     ----------------------
Index       Tab name       Index       Browser
----------  ----------     ----------  ----------
0           Tab 1          0           Browser 1
1           Tab 3          1           ---        <-- dangling pointer
                           2           Browser 3

如您所见,关闭第二个选项卡后,Tabs集合已重新编制索引,但您的数组不是。你刚刚销毁了对象实例,但是在同一个索引上,来自被破坏对象的悬空指针仍然存在。

现在,如果再次单击第二个选项卡的关闭按钮(名为Tab 3的选项卡),您将在事件处理程序中运行与以前完全相同的代码:

procedure TForm1.ChromeTabsButtonCloseTabClick(Sender: TObject;
  ATab: TChromeTab; var Close: Boolean);
begin
  // as before, the ATab.Index equals 1, but this time you'll get AV
  // since object from element Browsers[1] has been destroyed before
  // and now that element contains just dangling pointer
  Browsers[ATab.Index].Destroy; // <-- 
  Close := True;
end;

但是这次你会遇到访问冲突,因为Browsers[1]元素中的对象之前已经被破坏了。

为了您的目的,不是数组正确的集合类型。我建议你使用TObjectList<T>泛型对象列表集合。使用该集合,我会以这种方式重写您的代码:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  System.Generics.Collections, ChromeTabs, ChromeTabsClasses, cefvcl;

type
  TForm1 = class(TForm)
    ChromeTabs1: TChromeTabs;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ChromeTabs1ButtonAddClick(Sender: TObject;
      var Handled: Boolean);
    procedure ChromeTabs1ButtonCloseTabClick(Sender: TObject;
      ATab: TChromeTab; var Close: Boolean);
    procedure ChromeTabs1ActiveTabChanging(Sender: TObject; AOldTab,
      ANewTab: TChromeTab; var Allow: Boolean);
  private
    FBrowsers: TObjectList<TChromium>;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Tab_Closed:Boolean=False;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  // create instance of the object list and let it manage
  // lifetime of the inserted objects
  FBrowsers := TObjectList<TChromium>.Create;
  FBrowsers.OwnsObjects := True;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  // release the object list
  FBrowsers.Free;
end;

procedure TForm1.ChromeTabs1ButtonAddClick(Sender: TObject;
  var Handled: Boolean);
var
  ChromiumInstance: TChromium;
begin
  // create an instance of the browser component and
  // initiliaze its properties - here it's simplified
  ChromiumInstance := TChromium.Create(nil);
  ChromiumInstance.Parent := Self;
  ChromiumInstance.SetBounds(8, 8, 150, 150);
  // now add the new browser instance to the collection
  FBrowsers.Add(ChromiumInstance);
end;

procedure TForm1.ChromeTabs1ButtonCloseTabClick(Sender: TObject;
  ATab: TChromeTab; var Close: Boolean);
begin
  // delete the browser instance from the collection; since we've
  // assigned True to the OwnsObjects property of the collection,
  // we don't need to care of freeing the browser instance
  FBrowsers.Delete(ATab.Index);
  // allow the tab to close
  Close := True;
  //and fix tab close
  Tab_Closed:=True;
end;

procedure TForm1.ChromeTabs1ActiveTabChanging(Sender: TObject; AOldTab,
  ANewTab: TChromeTab; var Allow: Boolean);
begin
  // check if there's an "old tab" and if so, check also if we have its
  // index in the range of our collection; if so, then hide the browser
  if Assigned(AOldTab) and (AOldTab.Index < FBrowsers.Count) then
    FBrowsers[AOldTab.Index].Visible := False;
  // and show the activated tab browser
  If((ChromeTabs.Tabs.Count<>1)) Then
  Begin
  If((ANewTab.Index=(ChromeTabs.Tabs.Count-1)) AND Tab_Closed=True) Then
  FBrowsers[AOldTab.Index].Visible := True
  Else
  FBrowsers[ANewTab.Index].Visible := True;
  End
  Else FBrowsers[ANewTab.Index].Visible := True;
  //Now Tab is not closed
  Tab_Closed:=False;
end;

end.