Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Почему появляются дубликаты вкладок в TabControl 
:(
    Опции темы
Shouldercannon
  Дата 10.10.2014, 09:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.8.2010

Репутация: нет
Всего: нет



Доброго времени суток!
Пытаюсь реализовать работу с вкладками 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', '')

В чём проблема?
PM MAIL   Вверх
Poseidon
Дата 10.10.2014, 10:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Вместо
Код

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


сделай
Код

  if (i < 0) then
    i := TabControl1.Tabs.AddObject(UsrData.Nick, UsrData);



--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
Shouldercannon
Дата 10.10.2014, 13:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.8.2010

Репутация: нет
Всего: нет



Результат остался тот же :(
PM MAIL   Вверх
drkot
Дата 10.10.2014, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



проверяй наличие, и создавай если такой нет, а если есть просто переключайся на неё.
TabControl1.Tabs.IndexOf();



--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
Poseidon
Дата 10.10.2014, 15:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



drkot, код его вообще смотрел?


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
drkot
Дата 10.10.2014, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Цитата(Poseidon @  10.10.2014,  16:45 Найти цитируемый пост)
смотрел?

если у него IndexOfObject не ищет, то может по имени получится ;)


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
Poseidon
Дата 10.10.2014, 21:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Не вариант, т.к. имя может быть одинаковое у разных записей. Тут больше интересно почему же все-таки не ищет IndexOfObject. Я вот состряпал на коленке теститик, все срабатывает. Не понятно почему у Shouldercannon не работает.


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
drkot
Дата 10.10.2014, 21:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Либо он что-то не так делает, либо у него UsrData каждый раз новая.


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
Shouldercannon
Дата 11.10.2014, 06:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.8.2010

Репутация: нет
Всего: нет



Цитата(Poseidon @ 10.10.2014,  21:15)
Не вариант, т.к. имя может быть одинаковое у разных записей. Тут больше интересно почему же все-таки не ищет IndexOfObject. Я вот состряпал на коленке теститик, все срабатывает. Не понятно почему у Shouldercannon не работает.

Прикрепляю свои наработки для эксперемента

Присоединённый файл ( Кол-во скачиваний: 1 )
Присоединённый файл  TabControl.zip 15,26 Kb
PM MAIL   Вверх
Poseidon
Дата 11.10.2014, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Все понятно. В TForm2.ProcAddTab передается TListItem, взятое из TListView.Items. Там же потом извлекается Data. Так вот, что же храниться в Data? А там храниться ссылка на обрасть памяти. Той самой памяти, которая заполняется в AddTab и отдается потом в TabControl1.Tabs.Objects. При нажатии Button1 срабатывает LVUsers.Clear; TListView очищается и, соответственно, очищаются все Data. При последующем срабатывании ProcAddTab данных в Data нет. А раз так, то выполняется условие (UsrData = nil), заново выделяется и заполянется данными панять в AddTab, идет сравнение по IndexOfObject и оно не срабатывает т.к. хоть данные и одинаковые, но это не те же данные, а поэтому IndexOfObject возвращает -1. Это очень хорошо видно, если под отладчиком в ProcAddTab вызвать Pointer(UsrData) и посмотреть что там будет для каждой записи при первом заполнении LVUsers и потом при перезаполнении LVUsers. 

Короче, IndexOfObject не срабатывает потому, что мы сравниваем разные экземпляры класса TTabData. И хоть они заполненны одинаковыми данными, это все-равно разные экземпляры.

Я бы переделал TTabData в record и, соответственно, немного переделается логика работы программы. Но тогда не будет таких подводных камней и UsrData с одинаковыми данными будут считаться одинаковыми.


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
Shouldercannon
Дата 12.10.2014, 10:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.8.2010

Репутация: нет
Всего: нет



Цитата(Poseidon @ 11.10.2014,  19:09)
Если под отладчиком в ProcAddTab вызвать Pointer(UsrData) и посмотреть что там будет для каждой записи при первом заполнении LVUsers и потом при перезаполнении LVUsers. 

Короче, IndexOfObject не срабатывает потому, что мы сравниваем разные экземпляры класса TTabData. И хоть они заполненны одинаковыми данными, это все-равно разные экземпляры.

Я бы переделал TTabData в record и, соответственно, немного переделается логика работы программы. Но тогда не будет таких подводных камней и UsrData с одинаковыми данными будут считаться одинаковыми.

Для Name: 0
Первое формирование данных в ListView - $1E29A0C
Второе формирование данных в ListView - $1E29EA8
Третье формирование данных в ListView - $1E2A2C8

Цитата(Poseidon @ 11.10.2014,  19:09)
Я бы переделал TTabData в record и, соответственно, немного переделается логика работы программы. Но тогда не будет таких подводных камней и UsrData с одинаковыми данными будут считаться одинаковыми.

Можно попросить помочь с этим, данный код был написан не лично мной и при внесении изменений всё полетит в тартарары. Пока не шибко разбираюсь
Вот первый пример
Код

unit frm_2;

interface

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

type
  TTabData = record
  public
    UserID: Integer;
    Nick: string;
    TempMessage: string;
  end;
...

и понеслась
Build
  [Error] frm_2.pas(12): ',' or ':' expected but identifier 'UserID' found
  [Error] frm_2.pas(73): Object or class type required
  [Error] frm_2.pas(77): Incompatible types: 'TObject' and 'TTabData'
  [Error] frm_2.pas(82): Operator not applicable to this operand type
  [Error] frm_2.pas(106): Incompatible types: 'TTabData' and 'Pointer'
  [Error] frm_2.pas(108): Incompatible types
  [Error] frm_2.pas(113): Incompatible types: 'TTabData' and 'Pointer'
  [Error] frm_2.pas(116): Incompatible types: 'TObject' and 'TTabData'
  [Error] frm_2.pas(122): Incompatible types: 'TObject' and 'TTabData'
  [Fatal Error] Project1.dpr(6): Could not compile used unit 'frm_2.pas'

Это сообщение отредактировал(а) Shouldercannon - 12.10.2014, 10:17
PM MAIL   Вверх
drkot
Дата 13.10.2014, 01:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Цитата(Shouldercannon @  12.10.2014,  11:16 Найти цитируемый пост)
 public

для начала это убрать

а в дальнейшем взять любую книжку по Delphi (или справку) и словарик англо-русский.... да попробовать самому подучиться...


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
Poseidon
Дата 13.10.2014, 09:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Delphi developer
****


Профиль
Группа: Комодератор
Сообщений: 5273
Регистрация: 4.2.2005
Где: Гомель, Беларусь

Репутация: 53
Всего: 133



Цитата(Shouldercannon @  12.10.2014,  10:16 Найти цитируемый пост)
Можно попросить помочь с этим, данный код был написан не лично мной и при внесении изменений всё полетит в тартарары. 

Я не сильно там лез в дебри, т.к. я бы вообще все переписал бы даже в этих трех строках, но посмотреть что к чему есть где.

Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  TabControl.rar 17,21 Kb


--------------------
Если хочешь, что бы что-то работало - используй написанное, 
если хочешь что-то понять - пиши сам...
PM MAIL ICQ   Вверх
Shouldercannon
Дата 13.10.2014, 10:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 3.8.2010

Репутация: нет
Всего: нет



Poseidon, низкий Вам поклон.
Застрял на получении данных для выбранной вкладки из UserData.
Индекс текущей вкладки
Код

tbInd := TabControl1.TabIndex;

Вопрос, как теперь подлезть к указанному tbInd в UserData?

Это сообщение отредактировал(а) Shouldercannon - 13.10.2014, 14:07
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1524 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.