TChromium ChromeTabs不工作 [英] TChromium ChromeTabs Not Working
问题描述
我有这个:
浏览器:阵列[0..1000]的TChromium;
此ChromeTabs程序:
procedure TForm1.ChromeTabsActiveTabChanged(Sender:TObject; ATab:TChromeTab);
var
c:integer;
开始
为c:= 0到ChromeTabs.Tabs.Count do
如果浏览器[c]<> NIL然后
如果c = ChromeTabs.ActiveTabIndex然后浏览器[c ] .Visible:= true else browsers [c] .visible:= false;
结束
程序TForm1.ChromeTabsButtonAddClick(发件人:TObject;
var Handled:Boolean);
begin
浏览器[ChromeTabs.ActiveTabIndex]:= TChromium.Create(Chromium);
浏览器[ChromeTabs.ActiveTabIndex] .OnAddressChange:= Chromium.OnAddressChange;
浏览器[ChromeTabs.ActiveTabIndex] .OnAfterCreated:= Chromium.OnAfterCreated;
浏览器[ChromeTabs.ActiveTabIndex] .OnBeforeContextMenu:= Chromium.OnBeforeContextMenu;
浏览器[ChromeTabs.ActiveTabIndex] .OnBeforePopup:= Chromium.OnBeforePopup;
浏览器[ChromeTabs.ActiveTabIndex] .OnLoadEnd:= Chromium.OnLoadEnd;
浏览器[ChromeTabs.ActiveTabIndex] .OnLoadError:= Chromium.OnLoadError;
浏览器[ChromeTabs.ActiveTabIndex] .OnLoadingStateChange:= Chromium.OnLoadingStateChange;
浏览器[ChromeTabs.ActiveTabIndex] .OnProcessMessageReceived:= Chromium.OnProcessMessageReceived;
浏览器[ChromeTabs.ActiveTabIndex] .OnStatusMessage:= Chromium.OnStatusMessage;
浏览器[ChromeTabs.ActiveTabIndex] .DefaultEncoding:= Chromium.DefaultEncoding;
浏览器[ChromeTabs.ActiveTabIndex] .parent:= Form1;
浏览器[ChromeTabs.ActiveTabIndex] .Align:= alClient;
浏览器[ChromeTabs.ActiveTabIndex]。
浏览器[ChromeTabs.ActiveTabIndex] .Load(Chromium.DefaultUrl);
结束
程序TForm1.ChromeTabsButtonCloseTabClick(发件人:TObject;
ATab:TChromeTab; var Close:Boolean);
begin
browsers [ATab.Index] .Destroy;
关闭:= True;
结束
Chromium对象是我的默认浏览器,我放在我的表单上。
所以,当我试图关闭其中一个Tab时,它有时会提供访问冲突错误。
当我尝试从Adress_Line加载一个Url时,它给出访问违规错误。
此外,当我打开2个或更多的Tabs时,他们看起来不好,像这样 - http://s43.radikal.ru/i101/1307/99/650e18d5e190.jpg
请帮我解决所有这些问题:(
谢谢。
/ em>
访问冲突异常的问题是由调用
方法对于已经被破坏的对象,让我解释一下这个情况。
想象一下,你有3个标签与下一个索引和浏览器
数组与以下浏览器instan ces:
ChromeTabs.Tabs浏览器
--------- ------------- ----------------------
索引选项卡名称索引浏览器
- -------- ---------- ---------- ----------
0标签1 0浏览器1
1标签2 1浏览器2
2标签3 2浏览器3
现在点击在中间选项卡的关闭按钮(标签为1)和 OnButtonCloseTabClick
中运行:
procedure TForm1.ChromeTabsButtonCloseTabClick(Sender:TObject;
ATab:TChromeTab; var Close:Boolean);
begin
// ATab.Index等于1
浏览器[ATab.Index] .Destroy;
关闭:= True;
结束
这将破坏一个名为浏览器2的浏览器实例
从上表。当数组将被重新索引为 Tabs
集合时,这不会是问题。让我们看看标签页和数组中会发生什么:
ChromeTabs.Tabs浏览器
---------------------- ----------------------
索引标签名称索引浏览器
---------- ---------- ---------- ----------
0标签1 0浏览器1
1标签3 1 ---< - - dangling pointer
2浏览器3
如您所见,在关闭第二个选项卡后, Tabs
集合已被重新索引,但是您的数组不是。你刚刚摧毁了对象实例,但这个破坏对象的悬挂指针仍然存在于同一个索引上。
现在,如果单击第二个选项卡的关闭按钮再次(名为 Tab 3
的选项卡),您将在事件处理程序中运行与以前相同的代码:
< pre class =lang-pascal prettyprint-override>
procedure TForm1.ChromeTabsButtonCloseTabClick(Sender:TObject;
ATab:TChromeTab; var Close:Boolean);
begin
//如前所述,ATab.Index等于1,但是这次你会得到AV
//因为元素浏览器[1]的对象在$ b $之前被销毁b //现在该元素只包含悬挂指针
浏览器[ATab.Index] .Destroy; //< -
关闭:= True;
结束
但是这次你会得到访问冲突,因为浏览器中的对象[1]
元素已被销毁。
为了您的目的不是数组正确的集合类型。我建议您使用 TObjectList< T> ;
泛型对象列表集合。使用该集合,我将以这种方式重写代码:
unit Unit1;
接口
使用
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);
程序ChromeTabs1ButtonAddClick(发件人:TObject;
var Handled:Boolean);
程序ChromeTabs1ButtonCloseTabClick(发件人:TObject;
ATab:TChromeTab; var Close:Boolean);
程序ChromeTabs1ActiveTabChanging(发件人:TObject; AOldTab,
ANewTab:TChromeTab; var Allow:Boolean);
private
FBrowsers:TObjectList< TChromium> ;;
public
{公开声明}
end;
var
Form1:TForm1;
Tab_Closed:Boolean = False;
实现
{$ R * .dfm}
程序TForm1.FormCreate(发件人:TObject);
begin
//创建对象列表的实例,让它管理
//插入对象的生命周期
FBrowsers:= TObjectList< TChromium> .Create;
FBrowsers.OwnsObjects:= True;
结束
procedure TForm1.FormDestroy(Sender:TObject);
begin
//发布对象列表
FBrowsers.Free;
结束
procedure TForm1.ChromeTabs1ButtonAddClick(Sender:TObject;
var Handled:Boolean);
var
ChromiumInstance:TChromium;
begin
//创建浏览器组件的一个实例,
// initiliaze它的属性 - 这里简化
ChromiumInstance:= TChromium.Create(nil);
ChromiumInstance.Parent:=自我;
ChromiumInstance.SetBounds(8,8,150,150);
//现在将新的浏览器实例添加到集合
FBrowsers.Add(ChromiumInstance);
结束
procedure TForm1.ChromeTabs1ButtonCloseTabClick(Sender:TObject;
ATab:TChromeTab; var Close:Boolean);
begin
//从集合中删除浏览器实例;因为我们已经
//为集合的OwnsObjects属性赋值True
//我们不需要关心释放浏览器实例
FBrowsers.Delete(ATab.Index) ;
//允许标签关闭
关闭:= True;
//并修复标签关闭
Tab_Closed:= True;
结束
procedure TForm1.ChromeTabs1ActiveTabChanging(Sender:TObject; AOldTab,
ANewTab:TChromeTab; var Allow:Boolean);
begin
//检查是否有旧选项卡,如果是,请另行查看我们的集合范围内是否有
//索引;如果是这样,然后隐藏浏览器
如果分配(AOldTab)和(AOldTab.Index< FBrowsers.Count)然后
FBrowsers [AOldTab.Index] .Visible:= False;
//并显示激活的标签浏览器
如果((ChromeTabs.Tabs.Count 1))然后
开始
如果((ANewTab.Index =(ChromeTabs。然后
FBrowsers [AOldTab.Index] .Visible:= True
Else
FBrowsers [ANewTab.Index] .Visible = = True;
End
其他FBrowsers [ANewTab.Index] .Visible:= True;
//现在Tab未关闭
Tab_Closed:= False;
结束
结束。
I want do a Tabs for my TChromium.
I have this:
Browsers: array[0..1000] of TChromium;
And this ChromeTabs procedures:
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 object is my default Browser, i placed on my Form.
So, when i'm trying to close one of the Tab, it gives Access Violation Error sometimes.
When i'm trying to load an Url from Adress_Line, it gives Access Violation Error.
Also, when i opening 2 or more Tabs, they look bad, like this - http://s43.radikal.ru/i101/1307/99/650e18d5e190.jpg
Please, help me to fix all this problems :(
Thanks.
The problem of the access violation exception is caused by calling Destroy
method on an object which has been already destroyed. Let me explain the situation.
Imagine that you have 3 tabs with the next indexes and the Browsers
array with the following browser instances:
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
Now you click on the middle tab's close button (tab indexed by 1) and in the OnButtonCloseTabClick
you run this:
procedure TForm1.ChromeTabsButtonCloseTabClick(Sender: TObject;
ATab: TChromeTab; var Close: Boolean);
begin
// the ATab.Index equals 1
Browsers[ATab.Index].Destroy;
Close := True;
end;
That will destroy a browser instance called Browser 2
from the above table. That wouldn't be problem when the array would be reindexed as the Tabs
collection do. Let's look what happens to the tabs and your array:
ChromeTabs.Tabs Browsers
---------------------- ----------------------
Index Tab name Index Browser
---------- ---------- ---------- ----------
0 Tab 1 0 Browser 1
1 Tab 3 1 --- <-- dangling pointer
2 Browser 3
As you can see, the Tabs
collection has been reindexed after closing the second tab, but your array wasn't. You just destroyed the object instance, but the dangling pointer from that destroyed object is still there, on the same index.
Now if you click the close button of the second tab again (the tab called Tab 3
), you'll run the very same code as before in your event handler:
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;
But this time you'll get an access violation because object from the Browsers[1]
element has been destroyed before.
For your purpose is not array the right type of collection. I would suggest you to use TObjectList<T>
generics object list collection. Using that collection I would rewrite your code this way:
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.
这篇关于TChromium ChromeTabs不工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!