Сейчас на форуме: (+2 невидимых) |
eXeL@B —› Оффтоп —› Как организовать синхронизацию сортированных записей в TList со списком в TListView? |
Посл.ответ | Сообщение |
|
Создано: 11 ноября 2009 02:43 · Личное сообщение · #1 Пишу небольшую серверную часть которая должна принимать от клиентов некое число и отображать всех подключенных в ListView табличке в отсортированном виде. Все коннекты хранятся в списке который сортируется и обновляется по мере отключения, подключения и передачи данных клиентами. Всё работает сносно, но очень не нравится мне синхронизация сортированных записей в TList с TListView. Сделал как сумел, но чувствую есть способы грамотнее и красивее. Очень прошу подсказать как реализовать всё это без постоянной очистки и регенерации ListView. Сейчас по таймеру вызываю Refresh... Вот код: Code:
|
|
Создано: 11 ноября 2009 03:22 · Поправил: sendersu · Личное сообщение · #2 Несколько замечаний 1) зачем таймер? да и не безопасно так делать (у таймера ведь свой поток?) 2) предложение - вызивать treeview Refresh() после апдейта списка conn в методах OnConnect()/OnDisconnect() 3) в самом Refresh - есть варанты: а) очистка/заполнение - как у тебя, но я б добавил вызов BeginUpdate()/EndUpdate() на form1.listview1.Items (глянь хелп зачем) б) ребилд листа без варианта а - надо пробежаться по айтемах дерева, что пропало - удалить, что появилось в листе - добавить. Begin/EndUpdate() тоже надо 4) зачем try/finally в цикле в Refresh? 5) идея - добавить иконку в дерево для каждого елеме. зеленая - есть конект, красная - конец/оборвался (на следующем апдейте дерева - удалять) P.S. под деревом (treeview) надо читать listview, сорри |
|
Создано: 11 ноября 2009 14:40 · Поправил: ToBad · Личное сообщение · #3 sendersu пишет: 1) зачем таймер? да и не безопасно так делать (у таймера ведь свой поток?) Данные постоянно меняются у клиентов, но по протоколу они передают их только по запросу сервера. По этому таймер нужен, ровно как и внеплановый опрос по кнопке будет присутствовать. Почему не безопасно? Тут насколько я понимаю и так сервером создаются потоки для каждого клиента... sendersu пишет: но я б добавил вызов BeginUpdate()/EndUpdate() Отличный совет!!! Я даже не знал об этих методах.... sendersu пишет: предложение - вызывать treeview Refresh() после апдейта списка conn в методах OnConnect()/OnDisconnect() Да, так и делаю, просто выкинул лишнее для наглядности когда постил. sendersu пишет: ребилд листа без варианта а - надо пробежаться по айтемах дерева, что пропало - удалить, что появилось в листе - добавить. Begin/EndUpdate() тоже надо Не совсем понял, ещё один Begin/EndUpdate()? На TList что-ли который Conn? sendersu пишет: зачем try/finally в цикле в Refresh? Х.з. try/except поставлю, в момент прохода по листу может дисконнект одного из клиентов произойти... |
|
Создано: 11 ноября 2009 15:28 · Личное сообщение · #4 ToBad пишет: Данные постоянно меняются у клиентов, но по протоколу они передают их только по запросу сервера. По этому таймер нужен, ровно как и внеплановый опрос по кнопке будет присутствовать. Почему не безопасно? Тут насколько я понимаю и так сервером создаются потоки для каждого клиента... да, есть такой подход - один клиент - один поток, но не понимаю другого, в теории клиент запрашивает данные, а сервер (слуга) - обслуживает запрос и возвращает ответ. Ты наверное имеешь ввиду обмен информацией по уже установленному дочернему конекте, да? То есть список не только для показа активых конектов но и еще атрибутов взаимодействия? ToBad пишет: sendersu пишет:ребилд листа без варианта а - надо пробежаться по айтемах дерева, что пропало - удалить, что появилось в листе - добавить. Begin/EndUpdate() тоже надо Не совсем понял, ещё один Begin/EndUpdate()? На TList что-ли который Conn? имел в виду то же что и в 3а пункте. Х.з. try/except поставлю, в момент прохода по листу может дисконнект одного из клиентов произойти... дык в етом и весь нюанс, ситуация: мы ребилдим список, и в етот классный момент у нас происходит доваление новых данных -> здесь возможно все, от креша до неправильного отображения данных поетому, следует подумать о блокировке общего ресурса, а именно - списка Conn методов -много |
|
Создано: 11 ноября 2009 17:10 · Личное сообщение · #5 sendersu пишет: То есть список не только для показа активых конектов но и еще атрибутов взаимодействия? Интересуют только активные коннекты. sendersu пишет: дык в етом и весь нюанс, ситуация: мы ребилдим список, и в етот классный момент у нас происходит доваление новых данных -> здесь возможно все, от креша до неправильного отображения данных поетому, следует подумать о блокировке общего ресурса, а именно - списка Conn методов -много Да, это может стать проблемой. Буду придерживать флажками убиение элемента списка при дисконнекте и добавление при коннекте если происходит refresh а так же придерживать refresh при входе в коннект/дисконнект. Так наверное? По ходу появился ещё вопрос. Сейчас у меня по протоколу есть только возвращение числа клиентом. Существует функция Reask, которая посылает каждому клиенту команду. Послали 5 - клиент вернул свое число. Теперь я добавляю команду 4, получив её клиент инкрементирует у себя число и пришлёт его в ответ. В TConnects добавил Cmd. Если не установлено в 4, то принимает значение 5. Я обрабатываю клики на листвьюв так: Code:
Когда будет расширен функционал вместо месседжа будет диалоговое окно. В данном примере вывод окна сделан для того, что бы можно было убить клиента и только потом послать команду. Когда клиент жив, при следующем Reask я отправляю 4 и получаю ответ, всё происходит нормально, но если клиента закрыть, смещение индексов в списке мне не страшно, так как я запомнил не индекс перед входом в месседж или диалог, а ConAux нужного мне элемента, однако я не могу сделать так: Code:
а следовательно и знать, что выставляю ConAux.cmd:=4; для уже мертвого соединения... |
|
Создано: 11 ноября 2009 18:11 · Личное сообщение · #6 |
|
Создано: 11 ноября 2009 18:19 · Поправил: Модератор · Личное сообщение · #7 |
|
Создано: 12 ноября 2009 02:45 · Личное сообщение · #8 ToBad пишет: Да, это может стать проблемой. Буду придерживать флажками убиение элемента списка при дисконнекте и добавление при коннекте если происходит refresh а так же придерживать refresh при входе в коннект/дисконнект. Так наверное? я советую не играться в кошки-мышки а использовать обекты синхронизации ОС - или юзер или кернел мода. Для примера можно заюзать TCriticalSection клас. Создать 1 обект, перед изменением состояния общего ресурса (список) - захват (Acquire()), после работы - отдать назад (Release()) ToBad пишет: По ходу появился ещё вопрос. к индексам желательно не привязиваться (если гуи сортирует - тем более нельзя! индекс плавает, верно? поетому вот ето - ConAux:=PConnects(conn[ListView1.ItemIndex] не есть хорошо, взамен надо запоминать в твоем ListView1 не только Caption, но и сам ConAux (Указатель на структуру клиента), как? вот так: привязиваемся к реальным обьектам юзера - ConAux типа поинтер на структуру TConnects ConAux:= PConnects(conn[i]); it:=form1.listview1.Items.Add; // Добавили строку it.Data := TObject(ConAux); // <-- теперь у нас есть уникальный ключ для каждого рядка в списке! ... кстати - утебя уже был похожий подход с потоком - AThread.Data:= TObject(ConAux); Вообще скажу тебе - в Дельфи такой дженерик подход - пихать свои юзер данные (как правило поинтер на чего то свое в такие вот проперти - Data, Tag, ... (називаються по разному в разных дельфи классах) по вопросу - все верно, когда клиет умер - его ConAux уже уничтожен (в твоем методе IdTCPServer1Disconnect) но! когда ты читаеш пропертю Data текущего выбранного елемента ты етого еще не знаешь (поинтер остался, а память под ним может быть уже тю-тю (FreeMem) чтоб проверить жив ли клиент - можно например поискать его в списке клиентов, а-ля if conn.IndexOf(currentConAux) <> -1 then //ура клиент жив! не забываем, что даже простой поиск по списку через IndexOf() - ето доступ к общему ресурсу, который надо защитить (см. выше) удачи |
|
Создано: 12 ноября 2009 03:36 · Личное сообщение · #9 sendersu - Огромное спасибо за исчерпывающий ответ!!! Ты мне очень помог, теперь есть масса информации для размышления и варианты как это сделать! progopis пишет: По многочисленным жалобам (обойдёмся без ников) p.s. Топик закрываю дабы не сердить уважаемых модераторов и всех остальных многочисленных которые обходятся без ников, но очень не безразличны к порядку на форуме. ;) Спасибо, что дали дорешить проблему и не забанили по ip весь мой регион, не изгнали с позором с форума и не набили морду... Впредь буду тщательнее выбирать куда постить... |
eXeL@B —› Оффтоп —› Как организовать синхронизацию сортированных записей в TList со списком в TListView? |