Сейчас на форуме: rmn, Magister Yoda, vasilevradislav, tyns777, zombi-vadim (+4 невидимых)

 eXeL@B —› Программирование —› Вопросы по ListView (двойная буферизация, выравнивание ячеек, уведомления...)
Посл.ответ Сообщение

Ранг: 10.7 (новичок)
Активность: 0=0
Статус: Участник

Создано: 01 мая 2008 13:37
· Личное сообщение · #1

Здраствуйте. Меня интересуют несколько аспектов. Здесь вроде как много народу на Api интерфейс любят делать. Так вот...
1) Как сделать двойную буферизацию ListView? Рыскал в поисковиках на эту тему, но либо попадались статейки/туториалы на VCL, либо тупо упоминание как якобы надо делать. Наткнулся на пример на языке Си и попытался переделать под Delphi.
WM_PAINT :
begin
GetClientRect(hApp, RhLV);
hdcWnd := BeginPaint(hApp, PS);
hbmMem := CreateCompatibleBitmap(hdcWnd, RhLV.Right - RhLV.Left, RhLV.Bottom - RhLV.Top);
hdcMem := CreateCompatibleDC(hdcWnd);
hbmWnd := SelectObject(hdcMem, hbmMem);
BitBlt(hbmWnd, 0, 0, RhLV.Right - RhLV.Left, RhLV.Bottom - RhLV.Top, hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hbmWnd);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
EndPaint(hApp, PS);
end;
WM_ERASEBKGND : Result := TRUE;

Сначала делал именно для контрола ListView, но потом в процессе переделки оказалось что хоть какой хэндл контрола подставь BeginPaint, все равно будет буферизировано сразу целое диалоговое окно. Думаю что все равно такой код немного неправильный, потому как например к ListView применяю стиль LVS_EX_DOUBLEBUFFER, а если его не применять - никакой двойной буферизации целого диалога нет. Но ведь по идее должно и без этого стиля тогда буферизироваться... Что за дела...
2) Подскажите как выравнивать столбцы в ListView при изменении размеров контрола. Ну например справа от его границ. Какие хотя бы сообщения присылать/отсылать или нужно что-нибудь задать в параметре столбца при его создании?
3) Как все-таки без корректно ловить уведомление от ListView, когда выделили другую строчку в нем? Использовал LVN_ITEMCHANGED, но если элемент в контроле выделен и изменяется размер списка, то начинаются жуткие тормоза - у меня 2 таких контрола и выполняетсяпоиск значений в файле при нажатии на первый контрол. Так вот каждый раз при изменении размеров этот поиск начинает выполняться. Событие LVN_ITEMCHANGED мне нужно только для определения конкретного значения из 1 списка, чтобы потом его обработать и отобразить другие данные для него во 2 списке. Потом посмотрел в сторону нажатий клавиш стрелка вниз/вверх. Все равно мне только и нужно с клавиатуры "тыкать" на строчки списка. Однако после старта программы VK_UP и VK_DOWN не срабатывают с первого раза. Приходится по 2 раза "тыкнуть" чтобы выделилась другая строчка. Есть более унивеорсальный способ?

Спасибо.)




Ранг: 387.4 (мудрец)
Активность: 0.170
Статус: Участник
системщик

Создано: 01 мая 2008 22:04
· Личное сообщение · #2

www.codeproject.com/KB/list/

тут, правда, MFC, но ты просто скомпиль пару примеров, а потом выдерни API вызовы.



Ранг: 10.7 (новичок)
Активность: 0=0
Статус: Участник

Создано: 04 мая 2008 17:24
· Личное сообщение · #3

Ммм... Долго рыскал, но все-таки нашел функцию автоматического подгона столбцов по нужным координатам. Это ListView_SetColumnWidth.
Буферизацию лучше такую оставлю. Только еще добавил на всякий случай FillRect.
Пришлось для ListView использовать NM_CLICK.

Хотя у кого есть мысли по поводу двойной буферизации, хотелось бы услышть ответ.



Ранг: 38.2 (посетитель)
Активность: 0.020
Статус: Участник

Создано: 07 мая 2008 12:29
· Личное сообщение · #4

Мыслей нет, откуда мысли, если голова моя пуста. Хочу заметить, что найти что-либо для чистого АПИ чрезвычайно сложно, тогда как для МФЦ есть горы любого мусора. Был бы благодарен если бы кто-нибудь выложил ссылки на исходники.
Если программируешь GUI на АПИ - ты бесстрашный человек, там столько всякого....



Ранг: 213.5 (наставник)
Активность: 0.120
Статус: Участник
забанен

Создано: 08 мая 2008 05:05
· Личное сообщение · #5

Exception пишет:
Хотя у кого есть мысли по поводу двойной буферизации, хотелось бы услышть ответ

Как вариант можно захучить обработчик сообщений самого дочернего окна ListView (к примеру SetWindowLong(hListView,GWL_WNDPROC, NewListViewProc)) и уже там, в хуке(NewListViewProc) обрабатывать WM_PAINT, WM_LBUTTONDOWN и т. д.
тогда это будет только для ListView

Exception пишет:
Рыскал в поисковиках на эту тему

а ты гугли сразу уже готовые полноценные опенсорсные проекты/компоненты для Delphi(в них потом и ищи уже готовую реализацию GDI)

-----
ЗЫ: истЕна где-то рядом, Welcome@Google.com





Ранг: 116.6 (ветеран), 8thx
Активность: 0.050
Статус: Участник

Создано: 08 мая 2008 08:45
· Личное сообщение · #6

Exception
Посмотри в сторону VirtualTreeView http://www.soft-gems.net/VirtualTreeview . ИМХО возможностей очень много да и представить дерево в виде плоского списка не проблема ) И исшо - если нужна скорость при работе с большим набором данных в ListView или TreeView, то лучше с них сразу сваливать, т.к. виндовые контролы, к которым за данными лезешь через сообщения это полный пипец.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 08 мая 2008 17:39
· Личное сообщение · #7

dermatolog пишет:
Посмотри в сторону VirtualTreeView. ИМХО возможностей очень много да и представить дерево в виде плоского списка не проблема ) И исшо - если нужна скорость при работе с большим набором данных в ListView или TreeView, то лучше с них сразу сваливать, т.к. виндовые контролы, к которым за данными лезешь через сообщения это полный пипец.


Очень спорное утверждение. Про ListView. VirtualTreeView от Мишки Лешки очень хорошая замена для TreeView, но не однозначно хорошая замена для ListView. Если посмотреть на исходники VTV, то сразу станет ясно, почему.

Для ListView есть хорошая возможность, работа его в виртуальном режиме. Нужно только не полениться и прочитать про это. В этом случае он будет ровно тем, чем должен быть. Средством отображения многоколоночных данных. Причем абсолютно никакой разницы в скорости заполнения/отображения, отображаете вы 10, или 10000000 записей. Достаточно только описать правила доступа к данным и обработчики их получения, и сделать одно присвоение в коде: MyListView.Count := 10 (или 10000000, если вам надо );

У Мишки Лешки же нужно описать Node, задать NodeSize, и после этого для каждой ноды будет происходить дополнительное аллоцирование памяти под каждую ноду. Вобщем то понятно почему. С деревом по другому сложно. Ну и все теже методы, что и для LV в виртуальном режиме тоже остаются. Еще и с освобождением памяти могут быть нюансы. Если вдруг в в вашей ноде есть, допустим String, и по запаре забылось поставить обработчик на FreeNode, то память будет течь. И чем чаще будет перезаполняться VTV, тем больше памяти утечет.

Получается, что заменять LV на VTV, это очень спорное решение. TreeView заменять правильно. А вот LV нет абсолютно никакого смысла.




Ранг: 116.6 (ветеран), 8thx
Активность: 0.050
Статус: Участник

Создано: 08 мая 2008 18:18
· Личное сообщение · #8

UR пишет:
Для ListView есть хорошая возможность, работа его в виртуальном режиме. Нужно только не полениться и прочитать про это. В этом случае он будет ровно тем, чем должен быть. Средством отображения многоколоночных данных. Причем абсолютно никакой разницы в скорости заполнения/отображения, отображаете вы 10, или 10000000 записей.

Достаточно посмотреть исходники любого виндового контрола чтобы понять, что доступ данных через систему сообщений это мегатормоза ) Проверено практикой.
UR пишет:
У Мишки Лешки же нужно описать Node, задать NodeSize, и после этого для каждой ноды будет происходить дополнительное аллоцирование памяти под каждую ноду.

Вы не правы. Если вы в ноде будете хранить просто указатель, то никаких телодвижений не нужно вообще.
UR пишет:
Еще и с освобождением памяти могут быть нюансы. Если вдруг в в вашей ноде есть, допустим String, и по запаре забылось поставить обработчик на FreeNode, то память будет течь. И чем чаще будет перезаполняться VTV, тем больше памяти утечет.

Вы опять не правы. Высвобождением String-ов занимается дельфовый менеджер памяти и не надо заморачиваться по этому поводу - все давно за вас сделал Borland.




Ранг: 116.6 (ветеран), 8thx
Активность: 0.050
Статус: Участник

Создано: 08 мая 2008 18:28
· Личное сообщение · #9

P.S. Я сам с VT работаю много лет - на нём можно сделать дохера чего. Например есть свой TVTDBGrid (кстати пример как не надо писать компоненты - это посмотреть исходники стандартного TDBGrid), есть инспектор свойств с древовидной структурой.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 08 мая 2008 19:46
· Личное сообщение · #10

dermatolog пишет:
Достаточно посмотреть исходники любого виндового контрола чтобы понять, что доступ данных через систему сообщений это мегатормоза ) Проверено практикой


Не понимаю, причем здесь это? Отрисовать несколько записей совершенно не проблема. А в виртуальном режиме все, что нужно, это получить индекс записи. Дальше дело ваше. Хотите шлите сообщения, хотите рисуйте сами. Делов куча. Главное не в этом, а в том, что список любого размера работает с одинаковой скоростью. И скорость эта не зависит от кол-ва записей. Работает исключительно быстро.

dermatolog пишет:
Вы не правы. Если вы в ноде будете хранить просто указатель, то никаких телодвижений не нужно вообще.


Угу. Только Pointer для каждой записи в размере 4-х байт должен откуда то взяться. Для 10000000 записей (например) это не много ни мало 40мб просто так сожраной памяти. Просто для индексов. Которые в случае прлоской структуры хранить не надо. Они получаются из номера элемента. И давая совет надо предупреждать о таких вещах.

dermatolog пишет:
Вы опять не правы. Высвобождением String-ов занимается дельфовый менеджер памяти и не надо заморачиваться по этому поводу - все давно за вас сделал Borland.


Ну чтож. Дело, как говориться, хозяйское. Можно не верить, но можно и проверить. Простой пример:

PMyNodeData = ^TMyNodeData;
TMyNodeData = packed record
pIndex: Pointer; //Пусть это будет какой нибудь указатель на отображаемую структуру
strComment: String; //А здесь, допустим коментарий для конкретной записи
end;

Вот допустим понадобилось сделать именно нак. При добавлении ноды заполняем соответствующую NodeData. Так вот если во FreeNode не сделать strComment := '', то все эти строки будут болтаться в памяти до закрытия приложения. Аналогично будут болтаться и все структуры/об'екты созданные при добавлении ноды и не прибитые ручками. Собственно, событие OnFreeNode ровно для того и заложено, что бы руками подбирать мусор, который руками же и создается. Если есть сомнения, можно проверить, блиго это дело пяти минут.

Кстати. Исходники менеджера памяти Дельфевского тоже доступны. Можно было бы и посмотреть. Автоматом освобождается память только в том случае, если кол-во реферов на данную облость памяти равно 0. Не важно, строки это, либо регионы памяти. Перед каждой выделенной строкой есть счетчик ссылок. Пока он не ноль, память не осободится.

Вобщем, что-бы не уходить далеко от темы. Мое мнение, что VTV является хорошей заменой для TreeView, но отнюдь не идеальной заменой для ListView. Сам использую VTV как замену штатному TreeView, как замену ListView не использую. Штатных возможностей ListView за глаза хватает.



Ранг: 10.7 (новичок)
Активность: 0=0
Статус: Участник

Создано: 08 мая 2008 21:11
· Личное сообщение · #11

Чего-то вы заспорились тут.
Проблему частично решил WM_SETREDRAW функцией для отключения/включения обновления ListView перед составлением списка.
А буферизация... Да пускай уж будет такая. Один фиг, что хорошо, так сразу целое окно при изменении размеров не рябит.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 08 мая 2008 23:10
· Личное сообщение · #12

Exception пишет:
Чего-то вы заспорились тут.


Я не спорю, а всего лишь на некоторые нюансы внимание обращаю.

С DoubleBuffered есть еще некоторые моменты. Как отрисовка делана? Сам рисуешь, или штатно? И, соответственно, как реагируешь на WM_ERASEBKGND. И т.п. Вообще то надо весь код смотреть. От заполнения и до конца отрисовки, поскольку Дельфи Invalidate может вызывать во многих местах. И перерисовку ячеек при изменении значений, и еще кучу разных весчей.

Оптимально перекрыть обработчики, которые OnAdvancedCustomDraw, OnAdvancedCustomDrawItem и OnAdvancedCustomDrawSubItem. Они вызываются до Paint и если надо рисовать что то особеное, то лучше это делать в этих эвентах, возвращать DefaultDraw := False и тогда весь процесс рисования будет тебе полностью подконтролен.

Честно говоря, я вообще не понимаю, в чем у тебя проблема. Никогда с подобным не сталкивался. Мельканий и прочей фигни не видел. Даже без двойной буфферизации. Вот как делаю я:

1) Перевожу LV в виртуальный режам. Свойство OwnerData
2) Завожу оброботчик для OnData (здесь получаю нужные для ячейки данные)
3) Завожу обработчик для OnAdvancedCustomDrawItem (здесь рисую картинку из ImageLista, если надо)
4) Завожу обработчик для OnAdvancedCustomDrawSubItem (здесь рисую содержимое субитемов)

Так примерно это в коде:

FMyDataList - в примере TStringList. Заполнен где-то.

procedure TMyForm.ListView1Data(Sender: TObject; Item: TListItem);
begin
if (Item <> nil) and (Item.Index >= 0) and (Item.Index < FMyDataList.Count) then begin
//Тут нужными тебе условиям задаешь что надо
with Item do begin
Caption := FMyDataList.Strings[Item.Index];
//Устанавливай в нужное тебе значение по своим критериям
ImageIndex := 1;
end;
end;
end;

procedure TMyForm.ListView1AdvancedCustomDrawItem(
Sender: TCustomListView; Item: TListItem; State: TCustomDrawState;
Stage: TCustomDrawStage; var DefaultDraw: Boolean);
var RT: TRect;
DC: THandle;
BH: THandle;
begin
if (Stage = cdPrePaint) then
if (Item <> nil) then begin
DC := GetDC(TListView(Sender).Handle);
try
if (Item.ImageIndex <> -1) then begin
RT := Item.DisplayRect(drIcon);
BH := Windows.CreateSolidBrush(ColorToRGB(TListView(Sender).Color));
Windows.FillRect(DC, RT, BH);
DeleteObject(BH);
//Здесь рисую картинку из ImageList'а. Не помню вызова по памяти.
//MyImageList.Draw(DC, RT, Item.ImageIndex);
end;
finally
ReleaseDC(TListView(Sender).Handle, DC);
end;
end;
DefaultDraw := True;
end;

procedure TMyForm.ListView1AdvancedCustomDrawSubItem(
Sender: TCustomListView; Item: TListItem; SubItem: Integer;
State: TCustomDrawState; Stage: TCustomDrawStage;
var DefaultDraw: Boolean);
var S : String;
//---------------------------------------
procedure DoPaintItem;
var DC: THandle;
CL: TColor;
RT: TRect;
SZ: TSize;
DF: DWORD;
begin
ListView_GetSubItemRect(Sender.Handle, Item.Index, SubItem, LVIR_BOUNDS, @RT);
Inc(RT.Left, 8);
with Sender.Canvas do begin
if (Sender.Focused) and (Item.Selected) then CL := FHighlightColor
else CL := FDefaultColor;
DC := GetDC(TListView(Sender).Handle);
try
SelectObject(DC, Font.Handle);
SetTextColor(DC, ColorToRGB(CL));
SetBkMode(DC, TRANSPARENT);
DF := DT_LEFT or DT_VCENTER or DT_SINGLELINE;
GetTextExtentPoint32(DC, PChar(S), Length(S), SZ);
if (SZ.cx > RT.Right - RT.Left) then
//Эта функция проверяет, и если строка длиннее, чем ширина Rect,
//тримирует строку и добавляет в конец точки
//Кстати, из исходников Мишки Лешки, его VTV
S := ShortenString(DC, S, RT.Right - RT.Left, False);
DrawText(DC, PChar(S), Length(S), RT, DF, False);
finally
ReleaseDC(TListView(Sender).Handle, DC);
end;
end;
end;
//---------------------------------------
begin
if (Stage = cdPrePaint) then begin
if (Item <> nil) and (Item.Index >= 0) and (Item.Index < FMyDataList.Count) then begin
if (SubItem = 1) then begin
S := FMyDataList.Strings[Item.Index];
DoPaintItem;
end else
if (SubItem = 2) then begin
S := 'Что то нужное тебе'; //Получай из нужных тебе источников
DoPaintItem;
end;
//Дальше нужные тебе SubItems, сколько их там у тебя...
end;
end;
DefaultDraw := True;
end;

//Переводим LV в виртуальный режим
ListView1.OwnerData := True;
//Теперь устанавливаем кол-во записей
ListView1.Count := FMyDataList.Count;

Если надо почистить LV, то просто ListView1.Count := 0.

Все. Ничего не мыргает.
Если нужна юникодность, то просто используешь соответствующие юникодные аналоги для GetTextExtentPoint32 и DrawText. Ну и соответственно юникодный StringList (или что у тебя там будет).

Важно! Это только пример! Писал по памяти, возможны ошибки. Над оптимальностью кода не задумывался.



Ранг: 213.5 (наставник)
Активность: 0.120
Статус: Участник
забанен

Создано: 09 мая 2008 01:15
· Личное сообщение · #13

Exception пишет:
Чего-то вы заспорились тут.

Тоже встану на защиту Отца dermatolog`а и UR
В споре почти всегда рождаецца истЕна ;)( cracklab! это же не какой-нибудь ламосайтег.ру, тут печатаюццо люди -> у которых многолетний(!) стаж в кодинге)
И гораздо интереснее почитать этот спор, чем лаконичный ответ решения проблемы

Exception пишет:
Проблему частично решил WM_SETREDRAW

Судя по твоим ответам должно вообще все замечательно работать, непонятно что значит "Проблему частично решил"

Exception пишет:
Использовал LVN_ITEMCHANGED

Я когда собираюсь вешать обработчик на какое-нибудь сообщение - частенько перед этим стартую тест-прогу и тупо вешаю на нее утилиту Microsoft Spy++, настраиваю то, что нужно чтобы записалось в лог-файл/окно и потом уже анализирую какие и сколько сообщений приходило при нажатии кнопки мыши, изменении размеров окна и т. д.
Утиль сохраняет также параметры приходящих сообщений и иногда показывает такие сообщения которые могут решить очень много проблем сразу..

-----
ЗЫ: истЕна где-то рядом, Welcome@Google.com




Ранг: 10.7 (новичок)
Активность: 0=0
Статус: Участник

Создано: 09 мая 2008 09:30
· Личное сообщение · #14

Demon666 пишет:
Судя по твоим ответам должно вообще все замечательно работать, непонятно что значит "Проблему частично решил"

Да ну насчет ListView - все замечательно. Я просто отказался от перерисовки элементов списка. Ерундень какая-то. Итак пока устраивают стандартные системные цвета...

Demon666 пишет:
Я когда собираюсь вешать обработчик на какое-нибудь сообщение - частенько перед этим стартую тест-прогу и тупо вешаю на нее утилиту Microsoft Spy++

Да я еще программу даже не отлаживал. Впринципе это пока простенький диспетчер задач с неработающими некоторыми функциями...

Строго не ругать то что в аттаче. Но после последних изменений список процессов и загруженных модулей должен более менее быстро отображаться.

e2fe_08.05.2008_CRACKLAB.rU.tgz - ProcTools.rar




Ранг: 116.6 (ветеран), 8thx
Активность: 0.050
Статус: Участник

Создано: 12 мая 2008 07:31
· Личное сообщение · #15

UR пишет:
Не понимаю, причем здесь это? Отрисовать несколько записей совершенно не проблема. А в виртуальном режиме все, что нужно, это получить индекс записи. Дальше дело ваше. Хотите шлите сообщения, хотите рисуйте сами. Делов куча. Главное не в этом, а в том, что список любого размера работает с одинаковой скоростью. И скорость эта не зависит от кол-ва записей. Работает исключительно быстро.

Ну вот с VTV это действительно не проблема )

UR пишет:
Угу. Только Pointer для каждой записи в размере 4-х байт должен откуда то взяться. Для 10000000 записей (например) это не много ни мало 40мб просто так сожраной памяти. Просто для индексов. Которые в случае прлоской структуры хранить не надо. Они получаются из номера элемента. И давая совет надо предупреждать о таких вещах.

Детали реализации - это отдельный вопрос. Не надо мешать всё в кучу - указатели на данные в самих нодах и доступ к темже указателям (в собственном массиве или списке) через индекс нода. Например сортировка нодов с указателями в каждом ноде намного удобнее тойже сортировки с перестановкой индексов в списке. Поэтому давайте не будет спорить кто ожирает и сколько памяти - все зависит от реализации.

UR пишет:
Кстати. Исходники менеджера памяти Дельфевского тоже доступны. Можно было бы и посмотреть. Автоматом освобождается память только в том случае, если кол-во реферов на данную облость памяти равно 0. Не важно, строки это, либо регионы памяти. Перед каждой выделенной строкой есть счетчик ссылок. Пока он не ноль, память не осободится.

Поля структур как раз и относятся к "связанным" объектам с подсчетам референсов. Если вы высвобождаете структуру имеющую ссылку на строку, то количество ссылок на строку всегда будет=0 и строка высвободится автоматически.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 12 мая 2008 19:25
· Личное сообщение · #16

dermatolog пишет:
Ну вот с VTV это действительно не проблема )


Увы, проблема. Однажды мне понадобилось средство отоброжения большого кол-ва данных. Суммарное кол-во записей могло доходить до 600 000 000 (шестисот миллионов). Данные не мои, не организованны в виде базы. Нарушать их целостность и перестраивать под себя я не мог. Нужно было просто предоставить возможность их отображать. VTV не справился с этим. Очень медленно оказалось. Из-за огромного кол-ва сожранной памяти. В результате я за вечер написал нужного мне наследника от TListView.

Я устраивать баталии не собираюсь. Повторять сказанное тоже смысла не вижу. Единственное, о чем хочу сказать еще раз: Всегда, природа так устроена, у всего есть своя специфика. Нет одного лекарства против всех болезней. Хуже всего советы типа "вот эта таблетка от гемороя и бессонницы". Без уточнения, что побочный эффект - энурез. Рекомендуя что-то стоит учитывать требования задачи и предупреждать об особенностях. VTV свои особенности имеет. Рекомендуется ВНИМАТЕЛЬНО ознакомится с документацией и просмотреть особенности реализации некоторых решений. Исходники доступны.

dermatolog пишет:
Поля структур как раз и относятся к "связанным" объектам с подсчетам референсов. Если вы высвобождаете структуру имеющую ссылку на строку, то количество ссылок на строку всегда будет=0 и строка высвободится автоматически.


Неужели трудно проверить? Если нет времени, или желания проверять на "живом" коде, то предложу к рассмотрению следующее:

Аксиома: Освобождает тот, кто выделил.

Если не устраивает строка, то заменим ее на, допустим, TObject. Кто должен сказать ему Free? По каким критериям определяется момент, в который это Free должно произойти? В какой момент происходит декримент счетчика ссылок?

Вобщем, абсолютно не важно, строка это, либо TObject и его наследники. В физическом смысле все они представляют из себя некоторую облость памяти. Отличие только в том, что для об'ектов предусмотрен специальный механизм освобождения памяти выделенной в процессе жизни об'екта.

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




Ранг: 116.6 (ветеран), 8thx
Активность: 0.050
Статус: Участник

Создано: 12 мая 2008 20:57
· Личное сообщение · #17

UR пишет:
Неужели трудно проверить? Если нет времени, или желания проверять на "живом" коде, то предложу к рассмотрению следующее:

Все давно проверено и перепроверено. Для отслеживания утечек памяти есть полно утилит - возьми хотябы FastMM и проверь на нём свою теорию.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 12 мая 2008 21:39
· Личное сообщение · #18

dermatolog пишет:
Все давно проверено и перепроверено. Для отслеживания утечек памяти есть полно утилит - возьми хотябы FastMM и проверь на нём свою теорию.


Есть в наличии и FastMM, есть и диагностический софт. Все, что хотел сказать - сказал. Привычки высказываться голословно нет, моя информация из реальной практики. Кого заинтересовало, тот посмотрит и проверит сам. Продолжать особого смысла не вижу.

PS: Сегодня уже делать ничего не буду. Завтра набросаю пример. Демонстрацию.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 12 мая 2008 22:59
· Личное сообщение · #19

Настроение появилось, решил не ждать до завтра.

В аттаче демо. В опциях FastMM надо включить FullDebug и наслаждаться результатом.

PS: Только не надо говорить, что так никто не делает. Дело не в этом, а в том, что строки не освобождаются до закрытия приложения. При каждом заполнении VTV (если крыжик не стоит) по 1000 строк которые уже не используются остаются в памяти.

a85a_12.05.2008_CRACKLAB.rU.tgz - vtv_demo.rar




Ранг: 116.6 (ветеран), 8thx
Активность: 0.050
Статус: Участник

Создано: 13 мая 2008 05:46
· Личное сообщение · #20

UR пишет:
В аттаче демо. В опциях FastMM надо включить FullDebug и наслаждаться результатом.

При закрытии приложения - AV. Фтопку такие тесты )



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 13 мая 2008 12:11
· Личное сообщение · #21

dermatolog пишет:
При закрытии приложения - AV. Фтопку такие тесты )


Надеюсь, ты можешь сказать в каком конкретно месте вылетает AV? Хотелось бы услышать. В противном случае это все смахивает на простое балабольство.

Данный код работает и не вызывает исключений под Delphi5/7 (я не пользуюсь более новыми версиями за ненадобностью). Не используется НИЧЕГО не стандартного. Никаких вывихов мозговых в коде нет. VTV от Мишки Лешки и FastMM, это все, что не идет в комплекте со стандартной поставкой Delphi.

Если у тебя падает с AV, значит причина в твоей среде. В том же VTV или FastMM. Это, кстати, еще один довод в пользу осторожного юзания сторонних решений. Код VTV и FastMM не правился и изменений в него не вносилось. Версия VTV 4.0.16, Fast Memory Manager 4.78.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 13 мая 2008 12:41
· Личное сообщение · #22

Хоть у меня никаких AV и не вылетает, но решил ужесточить контроль. В аттаче доработанный примерчик. Все, что добавил, это очистку VTV на закрытие и контроль Node и NodeData на nil.


4132_13.05.2008_CRACKLAB.rU.tgz - vtvdemo.rar




Ранг: 116.6 (ветеран), 8thx
Активность: 0.050
Статус: Участник

Создано: 13 мая 2008 14:07
· Личное сообщение · #23

2 UR
Твой пример компилил на Delphi 5+стандартные FastMM и VT. На выходе получаю AV - разбираться времени не было.
Теперь по теме самого самбжа. Я немного не точно выражался, когда говорил про высвобождение памяти с сылками на строки. Информация о ссылках на строки есть, но только на уровне объектов (у каждого объекта есть специальная таблица) и при уничтожении объекта специальные процедуры FinalizeArray и FinalizeRecord подчищают такие связи. Для структур этой таблицы нет и здесь ты прав, что строковые строки нужно высвобождать руками. В любом случае если в нодах хранить только указатели на объекты (что собственно я всегда и делаю и всем рекомендую )), то проблем с утечками памяти не будет.



Ранг: 6.1 (гость)
Активность: 0=0
Статус: Участник

Создано: 13 мая 2008 17:57
· Личное сообщение · #24

dermatolog пишет:
Твой пример компилил на Delphi 5+стандартные FastMM и VT. На выходе получаю AV - разбираться времени не было.


Фиг с ним. Правда если и второй вариант падает, то надо будет посмотреть и МишкеЛешке отписать (если это его бага). Вероятнее всего какойто Invalidate/Repaint пролазит при закрытии. Ну и дергает уже прибитые ссылки.

dermatolog пишет:
Для структур этой таблицы нет и здесь ты прав, что строковые строки нужно высвобождать руками. В любом случае если в нодах хранить только указатели на объекты (что собственно я всегда и делаю и всем рекомендую )), то проблем с утечками памяти не будет.


Вот вроде и разобрались. В любом случае понятие "Об'ектное програмирование" как термин не должно восприниматься просто на веру. Обычно именно это и пораждает неприятные и трудно ловимые баги. Автоматическая сборка мусора штука очень приятная. Тут спору нет. Однако подводных камней при этом тоже хватает. В чистой концепции об'ектного програмирования это совершенно безопасная весчь, однако в реальной практике это далеко не всегда так. В Delphi например нужно ужесточение типизации, исключение механизмов приведения типов и полный отказ от pointer'ов. Тогда еще можно поручать программе чистить мусор самостоятельно и не очень задумываться об этом. Пока этого нет - "никому верить нельзя".

Пеперь вернусь к жору памяти. Жрет, и будет жрать из-за природы своей. Ну не может дерево не жрать! Да, если хранить только указатель на данные, то жрет минимально. Полюбому расход памяти можно рассчитывать как С + (N * 4). Где С, это некий оверхед и N число нод. Меньше не будет никак (больше запросто). Я настоятельно рекомендую не отмахиваться от этого и всегда иметь это ввиду. Разочарований не будет.


 eXeL@B —› Программирование —› Вопросы по ListView (двойная буферизация, выравнивание ячеек, уведомления...)
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати