我想为我的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.
的
答案 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.