Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Удаление строки и потоки


Автор: ZBugz 12.4.2010, 14:35
Всем привет. Помогите  smile 
Смысл вот в чем. Есть ListView, в нем задания, выделяю что надо, запускаю, по окончании могу удалить, а могу и руками удалить выделенную строку. При смещении элементов, меняеться ItemIndex. Ну в итоге в потоке они друг на друга лезут и все зависает. 
Мне надо что бы в потоке во всех Synchronize() вывлдилась инфа по конкретной строке, поэтому я привязался к строке, но потом понял что при удалении, даже если пройтись по списку и переназначить Index то возможно где то он измениться все равно.
Говорят что можно написать используя Lv.Data. Я вообще не понял как это делать...
Помогите  smile 
Пример прилогаю, мне бы с пояснениями и желательно максимально сохранить струтуру кода.

Автор: Akella 12.4.2010, 15:10
Цитата(ZBugz @  12.4.2010,  14:35 Найти цитируемый пост)
выделяю что надо, запускаю, по окончании могу удалить, а могу и руками удалить выделенную строку. 

Уже не раз писали, что удалять нужно от конца к началу, а не от начала к концу. Цикл организовать нужно от конца к началу.

Добавлено через 2 минуты и 19 секунд
Я, честно говоря, не понял, при чём здесь потоки? Можешь пояснить? Как связано удаление строк из ListView с потоками? И ещё вопрос. А может замечание. Вопросы по организации циклов по ListView лучше задавать в разделе для новичков ;) 

Автор: ZBugz 12.4.2010, 16:08
Цитата

Уже не раз писали, что удалять нужно от конца к началу, а не от начала к концу. Цикл организовать нужно от конца к началу.

Так, это я сделаю smile Впринципе так раньше и было smile Зачем то исправил  smile 
Цитата

Я, честно говоря, не понял, при чём здесь потоки? Можешь пояснить? Как связано удаление строк из ListView с потоками? И ещё вопрос. А может замечание. 

Значит так, выделяю задания, они ухоодят в поток, выполняються, от каждого задания в его строчку пишу данные, типа сколько процентов выполнено. В момет выполнения я заходл удалить строку, удалил. Последующие строки сдивнулись, отображение информации соответственно должно тоже сдвинуться, я это сделал. А вот если поток завершился, к примеру 2-е задание раньше чем 1-е и т.д. То оно по окончании удаляеться, но так как задание (строка), к примеру 3, тоже завершилось и тоже встало в очередь на удаление, а ItemIndex уже поменялся, то в итоге задание отписывает что оно завершенно в тот itemIndex, которого уже нету. Ну и получаем ошибку.

Цитата

Вопросы по организации циклов по ListView лучше задавать в разделе для новичков ;)

Да тут впринципе не о нем речь.

Добавлено через 1 минуту и 5 секунд
Проблема в том, что информацию я вывожу от номера строки, по другому просто не умею :( 

Автор: Akella 12.4.2010, 20:49
Цитата(ZBugz @  12.4.2010,  16:08 Найти цитируемый пост)
Значит так, выделяю задания, они ухоодят в поток, выполняються, от каждого задания в его строчку пишу данные, типа сколько процентов выполнено. В момет выполнения я заходл удалить строку, удалил. Последующие строки сдивнулись, отображение информации соответственно должно тоже сдвинуться, я это сделал. А вот если поток завершился, к примеру 2-е задание раньше чем 1-е и т.д. То оно по окончании удаляеться, но так как задание (строка), к примеру 3, тоже завершилось и тоже встало в очередь на удаление, а ItemIndex уже поменялся, то в итоге задание отписывает что оно завершенно в тот itemIndex, которого уже нету. Ну и получаем ошибку.

Ты выполняешь это всё в потоке? Или ты не понимаешь, http://www.google.com/search?ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=delphi+%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B8?

Или я не могу догнать, в чём у тебя проблема. Многабукаф - мало толку.

Цитата(ZBugz @  12.4.2010,  16:08 Найти цитируемый пост)
Да тут впринципе не о нем речь.

Кхм... тогда о чём?

Добавлено через 1 минуту и 6 секунд
Цитата(ZBugz @  12.4.2010,  14:35 Найти цитируемый пост)
Мне надо что бы в потоке во всех Synchronize() вывлдилась инфа по конкретной строке,

Ага, значит речь именно о потоках smile. Начинает доходить. smile

Добавлено через 2 минуты и 34 секунды
Цитата(ZBugz @  12.4.2010,  14:35 Найти цитируемый пост)
Говорят что можно написать используя Lv.Data. Я вообще не понял как это делать...

Да, в Data можно записать какой-нибудь уникальный код, когда ты добавляешь очередную строку.

Автор: Akella 12.4.2010, 21:30
user posted image
Обрати внимание на нумерацию справа.

Я создал по порядку все строки в списке. Потом удалили несколько нечётных. Затем скопировал в мемо всё. При чём номера строк в мемо брал из Data.
Проект прикрепил.

Автор: Akella 12.4.2010, 21:31
Проект был создан на Delphi 2007

Автор: ZBugz 13.4.2010, 09:25
Цитата(Akella @ 12.4.2010,  21:30)
Я создал по порядку все строки в списке. Потом удалили несколько нечётных. Затем скопировал в мемо всё. При чём номера строк в мемо брал из Data.
Проект прикрепил.

Я так делал. Та то работает. Мне бы как в моем поекте smile Там чуток по другому smile 

Автор: Akella 13.4.2010, 10:43
Цитата(ZBugz @  13.4.2010,  09:25 Найти цитируемый пост)
Я так делал. Та то работает.


тогда поясни, к чему был этот вопрос  smile 
Цитата(ZBugz @  12.4.2010,  14:35 Найти цитируемый пост)
Говорят что можно написать используя Lv.Data. Я вообще не понял как это делать...


Автор: ZBugz 13.4.2010, 13:09
Я имел ввиду что бы прям в дату весь поток запихнуть (потом, когда надо удалить поток\строку) и выводить информацию от тех параметров которые я в поток передал не привязываясь к строке.

Автор: Akella 13.4.2010, 15:34
Цитата(ZBugz @  13.4.2010,  13:09 Найти цитируемый пост)
Я имел ввиду что бы прям в дату весь поток запихнуть

Ты хоть посмотрел какой тип имеет Data? И я не представляю, как в переменную можно запихнуть поток?? (если бы Data была переменной)

Автор: Mikel 13.4.2010, 19:56
В Data можно запихнуть хоть паровоз smile Только создав его сначала, а потом в Data поместить указатель на паровоз smile

Автор: ZBugz 14.4.2010, 07:38
Цитата(Akella @ 13.4.2010,  15:34)
Ты хоть посмотрел какой тип имеет Data? И я не представляю, как в переменную можно запихнуть поток?? (если бы Data была переменной)

Mikel прав. Запихиваеться легко, я пробывал  smile Работает.

Но суть не в этом, меня  это не устраивает по другим причинам. Я сегодня отпишу, как только проверю одну весчь от Akella

Автор: Akella 14.4.2010, 09:01
Data - это указатель, потому поток туда не запихнёшь ;)

Автор: ZBugz 14.4.2010, 14:02
Цитата(Akella @ 14.4.2010,  09:01)
Data - это указатель, потому поток туда не запихнёшь ;)

Блин, я в шоке  smile 

Короче, все сделал типа так:

Код

  for j:= 0 to Lv.Items.Count-1 do
   begin
    CT[idx] := TThread.Create(Lv.Items[j], idx);
    Lv.Items[j].Data:=CT[idx];
    CT[idx].Start;
   end; 

Гиде CT это массив CT: array [1..2000] of TThread; и idx это номер потока

Так вот, 0 и 1 строка нормально отображаеться, а все что выше, почему то сьежает ниже через строку... smile 

Короче, берем 2-е задание, нажимаю выполнить, до CT[idx].Start и в потоке в Create N.Index=2 (N: TListItem), в Execute попадает как N.Index=3. И это только тогда, когда я добавил задания в чистый ListView, если загрузить с заданиями, то ниче не двигаеться.

Шё це такэ ? smile  Поможите  smile 

Автор: Akella 14.4.2010, 16:06
Цитата(ZBugz @  14.4.2010,  14:02 Найти цитируемый пост)
Data - это указатель, потому поток туда не запихнёшь ;)

Блин, я в шоке  smile 


и всё равно засовываешь TThread в Pointer
Цитата(ZBugz @  14.4.2010,  14:02 Найти цитируемый пост)
 Lv.Items[j].Data:=CT[idx];


Добавлено через 49 секунд
Это называется "Впихнём невпихуемое", да?

Добавлено через 1 минуту и 31 секунду
Продолжай в том же духе. За упорство Ктулху тебя вознаградит.

Автор: ZBugz 15.4.2010, 07:25
Цитата

и всё равно засовываешь TThread в Pointer
Это называется "Впихнём невпихуемое", да?

Почему так нельзя ?  smile Нормально запихиваеться и работает без ошибок. Строки удаляються как надо, информация отображаеться где надо...

Тока вот глючок что если выбрать задание со 2-й строки, перепрыгивает на 1 index больше.... Причем в greate приходит 2, а в execute уже 3 smile  Толи глюк контрола, толи хз... Сеня со стандартным контролом ListView попробую...

Автор: Akella 15.4.2010, 11:13
Цитата(ZBugz @  15.4.2010,  07:25 Найти цитируемый пост)
Почему так нельзя ?  smile Нормально запихиваеться и работает без ошибок. Строки удаляються как надо, информация отображаеться где надо...

ну тогда не знаю smile

Автор: kami 15.4.2010, 22:48
Цитата(ZBugz @  14.4.2010,  14:02 Найти цитируемый пост)
CT[idx] := TThread.Create(Lv.Items[j], idx);

Это лишнее. Я про CT[idx].
Не стоит один экземпляр класса/структуры etc.. учитывать в нескольких местах, это может привести к неявностям при их удалении.
лучше сразу "запихивать" в Items[i].Data и работать только там, благо TreeView ListView это более чем позволяет. Главное - в OnDeletion избавиться от "впихнутого" в нод экземпляра класса. Если ко всему прочему работать не с индексами элементов в ListView, а хранить в каждом потоке, соответствующем элементу списка, только ссылку на него (при этом индекс элемента при необходимости получать динамически - перебором, к примеру), то отпадает необходимость и в удалении "от конца к началу", это становится непринципиальным.

Цитата(Akella @  14.4.2010,  16:06 Найти цитируемый пост)
Это называется "Впихнём невпихуемое", да?

Почему? Это достаточно стандартная практика, и не обязательно для потоков. Я и сейчас нахожу очень удобным "впихивать" экземпляры обслуживающих классов в Socket.Data, Node.Data и т.п. При этом постоянно пользуюсь FastMM и никаких мемликов не наблюдаю (конечно, после ликвидации корявостей из-за невнимательности).

Автор: Akella 16.4.2010, 00:16
ну так мы просто присваиваем ссылку на адрес памяти, а не сам поток или объект, так?

Автор: ZBugz 16.4.2010, 08:02
Цитата(Akella @ 16.4.2010,  00:16)
ну так мы просто присваиваем ссылку на адрес памяти, а не сам поток или объект, так?

Ага, именно так.

Добавлено через 8 минут и 28 секунд
Цитата

Это лишнее. Я про CT[idx].
Не стоит один экземпляр класса/структуры etc.. учитывать в нескольких местах, это может привести к неявностям при их удалении.
лучше сразу "запихивать" в Items[i].Data и работать только там, благо TreeView ListView это более чем позволяет. 

Как бы сказать, понял, но на половину... Можно для тормозов пояснения ?  smile А лучше пример с комментами smile 

Цитата

Главное - в OnDeletion избавиться от "впихнутого" в нод экземпляра класса. Если ко всему прочему работать не с индексами элементов в ListView, а хранить в каждом потоке, соответствующем элементу списка, только ссылку на него (при этом индекс элемента при необходимости получать динамически - перебором, к примеру), то отпадает необходимость и в удалении "от конца к началу", это становится непринципиальным.

А вот как тогда вообще от индексов отвязаться ? Впринципе сейчас, при создании потока я передаю Lv.Items[j] 
Там, в поток.create я присваиваю эту дату переменной N: TListItem и в во всех Синхронайзах я уже использую вывод информации так:
N.SubItems[3]:=A и т.д. Т.е. от строки я отвязялся. По завершению, я подаю в главную фому сообщение с номером потока, поток прибиваю, далее читаю настроку и грохую строку. Тем самым убиваю три зайца: Поток 100% завершен, строка грохаеться только после 100% завершения потока и к строкам я не привязан вообще.

Единственно что в OnDeletion я ниче не делаю, потому что даже не знаюнадо ли мне в этом случае что то делать.

To Akella:
А можно ли мне вообще отвязаться от моего массива CT ? И как ?  smile Типа тупо написать 
Код

 for j:= 0 to Lv.Items.Count-1 do
   begin
    Lv.Items[j].Data:=TThread.Create(Lv.Items[j], idx);
    TThread.Start;
   end; 


?


Автор: Akella 16.4.2010, 08:54
Цитата(ZBugz @  16.4.2010,  08:02 Найти цитируемый пост)
А можно ли мне вообще отвязаться от моего массива CT ?

Можно, отказывайся  smile

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

Автор: kami 16.4.2010, 12:45
Цитата(ZBugz @  16.4.2010,  08:02 Найти цитируемый пост)
А можно ли мне вообще отвязаться от моего массива CT ? И как ?   Типа тупо написать 

Нужно отказаться.
Код

 for j:= 0 to Lv.Items.Count-1 do
   begin
    Lv.Items[j].Data:=TMyThread.Create(Lv.Items[j], idx);
    TMyThread( Lv.Items[j].Data).Start;
   end; 


В OnDeletion пишем:
Код

TmyThread(item.data).Terminate;// или как-там-он-у-тебя-прерывается
TmyThread(item.Data).Free;
Item.Data:=nil;

Цитата(ZBugz @  16.4.2010,  08:02 Найти цитируемый пост)
По завершению, я подаю в главную фому сообщение с номером потока, поток прибиваю, далее читаю настроку и грохую строку.

Передавай не номер потока в массиве, а указатель на соответствующий ему ListItem.

Примечание: далее "я" читать как имхо, и не подразумевать под этим "выпячивание и битие пяткой в грудь".
Примерно так (ну, это по моему разумению, я делаю так постоянно):
В потоке при необходимости завершения (поток должен знать кроме "своего" ListItem (я обозвал его ParentListItem) еще и хендл окна в основном потоке):
Код

PostMessage(MainWndHandle, WM_USER+1, integer(ParentListItem), integer(Self));

В основном потоке:

Код

TMyForm=class(TForm)
private
  procedure NeedTerminateThread(var Message:TMessage); message WM_USER+1;
...
end;

procedure TMyForm.NeedTerminateThread(var Message:TMessage);
var
  li:TListItem;
  th:TMyThread;
begin
  li:=TListItem(Message.WParam);
  th:=TMyThread(Message.LParam);
  далее - делаем нужные действия с ними, по окончанию - удаляем li.
  li.Delete;
  И не забываем, что здесь не нужно удалять поток, он удалится в OnDeletion. (код описан выше по тексту)
end;


Добавлено через 7 минут и 15 секунд
Цитата(Akella @  16.4.2010,  00:16 Найти цитируемый пост)
мы просто присваиваем ссылку на адрес памяти, а не сам поток или объект, так?

Ну так... любой экземпляр созданного класса (for example - myForm:TForm)- это тоже всего лишь указатель на его поля и методы...

Автор: ZBugz 19.4.2010, 09:27
Ага, ладно, попробую отпишусь smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)