2013-07-16 2 views
0

Я хочу сделать вкладки для моего TChromium.
У меня есть это:TChromium ChromeTabs не работает

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; 

объект Хром браузер по умолчанию, я размещен на моей форме.

Итак, когда я пытаюсь закрыть одну из Tab, иногда возникает ошибка доступа.
Когда я пытаюсь загрузить URL из Adress_Line, он дает ошибку нарушения доступа.
Кроме того, когда я открытии 2 или более вкладок, они выглядят плохо, как это - http://s43.radikal.ru/i101/1307/99/650e18d5e190.jpg

Пожалуйста, помогите мне решить все эти проблемы :(

Thanks.

+0

Вам нужно будет переинсталлировать этот массив объектов «TChromium». Представьте, что у вас три вкладки, сначала с индексом 0, второй с индексом 1 и третьим с индексом 2.Теперь вы закрываете вторую вкладку с индексом 1, уничтожаете объект «TChromium» (элемент «Браузеры» с индексом 1), но этот элемент в массиве остается указывать на уничтоженный объект. Затем вкладки получают переиндексацию, поэтому первая вкладка по-прежнему равна 0, но предыдущая третьца получает индекс 1. И вы пытаетесь получить доступ к элементу с индексом 1, как и раньше, когда вы закрываете эту вторую вкладку. AV вы получаете, потому что вы вызываете метод 'Destroy' на уничтоженном объекте. – TLama

+0

Но определенно лучше для этого будет использовать 'коллекцию обобщений 'tobjectList вместо этого массива. – TLama

+0

Как я могу переиндексировать этот массив? А что такое TObjectList? – Priler

ответ

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; 

Но на этот раз вы» ll получить нарушение доступа, потому что объект из элемента 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.