Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 09.10.2014, 09:51   #1
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
Вопрос Дублекат вкладок в TabControl после обновления ListView

Доброго времени суток!
Пытаюсь реализовать работу с вкладками TabControl
Код:
unit frm_Main;

...

var
  FormMain: TFormMain;

implementation

uses frm_2;

{$R *.dfm}

procedure TFormMain.Button1Click(Sender: TObject);
var
  i: Integer;
  Item: TListItem;
begin
  LVUsers.Clear;

  for i := 0 to 4 do
  begin
    Item := LVUsers.Items.Add;
    Item.Caption := '';
    Item.SubItems.Add(Format('Name: %d', [i])); // Name
    Item.SubItems.Add(Format('30%d', [i])); // Room
    Item.SubItems.Add(IntToStr(i)); // ID
    Item.SubItems.Add('0'); // Icon
    Item.ImageIndex := 0;
  end;
end;

procedure TFormMain.LVUsersDblClick(Sender: TObject);
begin
  if LVUsers.Selected = nil then Exit;
  Form2.ProcAddTab(LVUsers.Items[LVUsers.ItemIndex], True, True);
end

end.



unit frm_2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, StdCtrls, ComCtrls, ToolWin, ExtCtrls, Contnrs;

type
  TTabData = class(TObject)
  public
    UserID: Integer;
    Nick: string;
    TempMessage: string;
  end;

  TTabDataList = class(TObjectList)
  private
    function GetTab(Index: Integer): TTabData;
  public
    function AddTab(UserID: Integer; Nick, TempMessage: string): TTabData;
    property Tabs[Index: Integer]: TTabData read GetTab; default;
  end;

type
  TForm2 = class(TForm)
...
  private
    { Private declarations }
  public
    { Public declarations }
    procedure ProcAddTab(Usr: TListItem; ChangeTab, ShowForm: Boolean);
  end;

var
  Form2: TForm2;
  TabList: TTabDataList;
  tbInd: Integer;
  UserData: TTabData;

implementation

uses frm_Main;

{$R *.dfm}

function TTabDataList.AddTab(UserID: Integer; Nick, TempMessage: string): TTabData;
begin
  Result := TTabData.Create;
  Result.UserID := UserID;
  Result.Nick := Nick;
  Result.TempMessage := TempMessage;
  inherited Add(Result);
end;

function TTabDataList.GetTab(Index: Integer): TTabData;
begin
  Result := inherited Items[Index] as TTabData;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  TabList := TTabDataList.Create(True); // TabList сам уничтожтит элемент при удалении
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  FreeAndNil(TabList);
end;

procedure TForm2.ProcAddTab(Usr: TListItem; ChangeTab, ShowForm: Boolean);
var
  UsrData: TTabData;
  i: Integer;
begin
  UsrData := Usr.Data;

  if (UsrData = nil) then  // Нет такого пользователя
  begin
    // Создаем, добавляем в список TabList
    UsrData := TabList.AddTab(StrToInt(Usr.SubItems[2]), Usr.SubItems[0], '');
    // Связываем с элементом в LVUsers
    Usr.Data := UsrData;
  end;
  // Ищем пользователя на вкладках
  i := TabControl1.Tabs.IndexOfObject(UsrData);

  if (i < 0) then // Нет вкладки с таким пользователем, добавляем новую вкдадку - здесь дыра
  begin
    i := TabControl1.Tabs.Add(UsrData.Nick);
    // Связываем c конкретной вкладкой
    TabControl1.Tabs.Objects[i] := UsrData;
  end;

  if ChangeTab then
  begin
    // Сделаем вкладку активной
    TabControl1.TabIndex := i;
  end;
  // Покажем форму если разрешено
  if ShowForm then
  begin
    Self.WindowState := wsNormal;
    Self.Show;
  end;
end;

end.
Нашёл один недостаток. Если пересоздать список пользователей в ListView и кликать по этим записям, то в TabControl появляться дубликаты уже имеющихся/открытых вкладок.
Тут
Код:
  // Ищем пользователя на вкладках
  i := TabControl1.Tabs.IndexOfObject(UsrData);
отладчик показывает одинаковые данные до обновления и после обновления списка пользователей
(0, 'Name: 0', '')
(0, 'Name: 0', '')

В чём проблема? Это можно исправить?

Последний раз редактировалось Shouldercannon; 09.10.2014 в 09:57.
Shouldercannon вне форума Ответить с цитированием
Старый 09.10.2014, 10:11   #2
min@y™
Цифровой кот
Старожил
 
Аватар для min@y™
 
Регистрация: 29.08.2014
Сообщений: 7,629
По умолчанию

Цитата:
В чём проблема? Это можно исправить?
Воспользуйся дебаггером, прочеши вот это место:
Код:
  UsrData := Usr.Data;

  if (UsrData = nil) then  // Нет такого пользователя
  begin
    // Создаем, добавляем в список TabList
    UsrData := TabList.AddTab(StrToInt(Usr.SubItems[2]), Usr.SubItems[0], '');
    // Связываем с элементом в LVUsers
    Usr.Data := UsrData;
  end;
  // Ищем пользователя на вкладках
  i := TabControl1.Tabs.IndexOfObject(UsrData);

  if (i < 0) then // Нет вкладки с таким пользователем, добавляем новую вкдадку - здесь дыра
  begin
    i := TabControl1.Tabs.Add(UsrData.Nick);
    // Связываем c конкретной вкладкой
    TabControl1.Tabs.Objects[i] := UsrData;
  end;
Расскажу я вам, дружочки, как выращивать грибочки: нужно в поле утром рано сдвинуть два куска урана...
min@y™ вне форума Ответить с цитированием
Старый 09.10.2014, 11:24   #3
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
По умолчанию

Дебаг (1 - список в ListView создан первый раз; 2 - список пересоздан)
Код:
  UsrData := Usr.Data; //1: UsrData = nil; 2: UsrData = nil

  if (UsrData = nil) then  // Нет такого пользователя
  begin
    // Создаем, добавляем в список TabList
    UsrData := TabList.AddTab(StrToInt(Usr.SubItems[2]), Usr.SubItems[0], ''); //1: UsrData = '0', 'Name: 0'; 2: UsrData = '0', 'Name: 0'
    // Связываем с элементом в LVUsers
    Usr.Data := UsrData; //1: Usr.Data = (0, 'Name: 0', ''); 2: Usr.Data = (0, 'Name: 0', '') 
  end;
  // Ищем пользователя на вкладках
  i := TabControl1.Tabs.IndexOfObject(UsrData); //1: i = '-1'; 2: i = -1

  if (i < 0) then // Нет вкладки с таким пользователем, добавляем новую вкдадку
  begin
    i := TabControl1.Tabs.Add(UsrData.Nick); //1: i = 'Name: 0'; 2: i = 'Name: 0'
    // Связываем c конкретной вкладкой
    TabControl1.Tabs.Objects[i] := UsrData; //1: 0 = (0, 'Name: 0', ''); 2: 1 = (0, 'Name: 0', '') всё одинаково до этого момента, индекс стал на 1 больше
  end;
Недочёт здесь
Код:
  // Ищем пользователя на вкладках
  i := TabControl1.Tabs.IndexOfObject(UsrData);
неужели цикл не находит совпадения?
Код:
uses Classes

function TStrings.IndexOfObject(AObject: TObject): Integer;
begin
  for Result := 0 to GetCount - 1 do
    if GetObject(Result) = AObject then Exit;
  Result := -1;
end;

Последний раз редактировалось Shouldercannon; 09.10.2014 в 13:20.
Shouldercannon вне форума Ответить с цитированием
Старый 10.10.2014, 21:40   #4
Shouldercannon
Участник клуба Подтвердите свой е-майл
 
Аватар для Shouldercannon
 
Регистрация: 26.01.2008
Сообщений: 1,897
По умолчанию

Оказывается, сравниваются объекты - 2 объекта с идентичными данными - не одно и то же, но легче от этого не стало.
Shouldercannon вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Проблема после обновления Fahman Общие вопросы Delphi 6 20.12.2013 10:00
TabControl и listview запутался. updaite C# (си шарп) 16 05.11.2013 19:54
Закрытие вкладок TabControl Shouldercannon Общие вопросы Delphi 2 12.12.2012 21:09
WPF:ориентация вкладок в компоненте TabControl Mixim WPF, UWP, WinRT, XAML 1 22.05.2012 11:07
Переключение вкладок на TabControl программно Casper-SC Общие вопросы .NET 4 20.10.2011 14:00