TChromium ChromeTabs不工作 [英] TChromium ChromeTabs Not Working

查看:525
本文介绍了TChromium ChromeTabs不工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想为我的TChromium做一个Tabs。

我有这个:

 浏览器:阵列[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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆