![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Ошибка в коде, который раньше работал. [D7, XP]
kyn66 © (2009-11-03 13:14:00)Уважаемые мастера. Помогите найти ошибку в коде, взятом из рабочей программы:
1) Наполняем stданными
procedure FormSt;
Var
st : TStringList;
Bitmap1 : TBitmap;
begin
st := TStringList.Create;
Bitmap1 := TBitmap.Create;
ListBox1.Clear;
for i := 1 to KolLotery do
begin
DM1.ImageList1.GetBitmap(32, Bitmap1);
st.AddObject('первая запись', Bitmap1);
st.AddObject('вторая запись', Bitmap1);
st.AddObject('третья запись', Bitmap1);
end;
ListBox1.Items.AddStrings(st);
st.Free;
Bitmap1.Free;
end;
2) Отрисовываем ListBox с пиктограммами
procedure TMainFrm.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
Var
Offset : Integer;
Bitmap : TBitmap;
begin
Offset := 0;
with TCustomListBox(Control).Canvas do
begin
FillRect(Rect);
Bitmap := TBitmap(ListBox1.Items.Objects[Index]);
if Bitmap <> nil then
begin
Bitmap.Transparent :=True;
BrushCopy(Bounds(Rect.Left + 2, Rect.Top + 2, Bitmap.Width, Bitmap.Height),
Bitmap, Bounds(0, 0, Bitmap.Width, Bitmap.Height), clWhite);
Offset := Bitmap.Width + 8;
end;
TextOut(Rect.Left + Offset, Rect.Top, Listbox1.Items[Index]);
end;{With}
end;
Ошибка вылетает на "жирной" строке
kyn66 (2009-11-05 11:50:00) [1]Ок!
2Сергей М.
2RWolf
СПАСИБО за помощь!
Сергей М. (2009-11-05 11:47:00) [2]
> kyn66 © (05.11.09 11:39) [48]
Да как угодно.
Главное понимать, что в каждый момент времени творится с самим объектом и потенциально существующими ссылками на него.
kyn66 (2009-11-05 11:39:00) [3]
> Да не переменной, а самого объекта !
Ну я и имел это ввид (переменной с объектом), пардон за неграмотные выражения. Я решил 2 раза потом, что 1-й раз - DM1.ImageList1.GetBitmap(32, Bitmap1);, а второй, когда Bitmap := TBitmap(ListBox1.Items.Objects[Index]);Вот и решил, что у меня фигурируют две независимые переменные, точнее ссылки на объекты. Сергей, сейчас я понял про связь с объектами. Так как разрулить полюбовно ситуацию с уничтожением объекта. Может так и оставить, уничтожив глобальную по закрытии главной формы? А во втором блоке уничтожение убрать?
RWolf (2009-11-05 11:36:00) [4]смотри:
Bitmap1 := TBitmap.Create; //создали пустой TBitmap, Bitmap1 — указатель №1 на него
ListBox1.Clear;
for i := 1 to KolLotery do
begin
DM1.ImageList1.GetBitmap(32, Bitmap1); //скопировали содержимое объекта из другого TBitmap
st.AddObject('первая запись', Bitmap1); //запомнили указатель №1 на TBitmap
st.AddObject('вторая запись', Bitmap1); //запомнили указатель №2
st.AddObject('третья запись', Bitmap1); //запомнили указатель №3
end;
ListBox1.Items.AddStrings(st);
st.Free;
Bitmap1.Free; //и прибили объект! всё, указатели невалидны.
Сергей М. (2009-11-05 11:29:00) [5]
> при уничтожении хотя-бы одной переменнойс объектом, все
> остальные зависнут в воздухе
Да не переменной, а самого объекта!
> Почему 3 ? Вроде 2 должно быть.
> st.AddObject('первая запись', Bitmap1); //раз копия
> st.AddObject('вторая запись', Bitmap1); //два копия
> st.AddObject('третья запись', Bitmap1); //три копия
kyn66 (2009-11-05 11:20:00) [6]Очень популярно разъяснено. Понятно, хоть десять переменных привяжи к одному объекту и при уничтожении хотя-бы одной переменной с объектом, все остальные зависнут в воздухе. Я так понял? Так как же мне поступить правильно? Как их уничтожать правильно?
> В твоем же случае ты еще при жизни своего объекта сделал
> три копиии ссылки на него,
Почему 3 ? Вроде 2 должно быть.
Сергей М. (2009-11-05 11:07:00) [7]
> удалив один указатель, второй-то должен остаться действующим?
Ну что значит "действующим" ?
Да, он продолжает указывать на некий адрес в памяти, по которому раньше жил объект, но по которому этого объекта уже нет, ибо ты уничтожил его своими руками.
Сергей М. (2009-11-05 11:05:00) [8]
> тоже объявлена как и у меня переменная Bitmap и после отрисовки
> она уничтожается
При Bitmap.Free уничтожается не переменная, а объект, ранее созданный при вызове конструктораTBitmap.Create, указатель на который записан в переменную Bitmap при присвоении в строкеBitmap := TBitmap.Create.
Сама же лок.переменная Bitmap уничтожается (вместе с ее содержимым, каким бы оно ни было) при завершении работы метода ListBox1DrawItem (читай - при выполнеии оператораend).
И поскольку содержимое переменной Bitmap нигде никуда не копировалось в ходе работы метода, созданный объект "умер", равно как и единственная существовавшея ссылка на него в переменной Bitmap.
Отныне не существует ни самого объекта, ни ссылок на него.
В твоем же случае ты еще при жизни своего объекта сделал три копиииссылки на него, после чего убил объект и переменную, с которой были сделаны копии. Но копии-то ссылок остались ! И сразу же после уничтожения объекта они стали указывать в никуда, ибо объекта по адресу, на который о ни по-прежнему указывают, объекта уже нет.
RWolf (2009-11-05 11:05:00) [9]
> Но удалив один указатель, второй-то должен остаться действующим?
Удаляются не указатели, а объекты, на которые они указывают.
> Как тогда правильно уничтожать такие объекты
.Free, как и любые другие. Просто надо следить за указателями; удалил объект — больше не пользуйся указателями на него.
kyn66 (2009-11-05 10:59:00) [10]
> Обе переменные содержат значение, являющее собой указатель
> на один и тот же объект.
Ну я как и предполагал. Но удалив один указатель, второй-то должен остаться действующим? Как тогда правильно уничтожать такие объекты(применительно к данной ситуации), чтобы они не повисли в памяти?
RWolf (2009-11-05 10:58:00) [11]в Дельфи Bitmap:TBitmap — на самом деле указатель на объект.
Строкой DM1.ImageList1.GetBitmap(32, Bitmap1); ты присваиваешь ему адрес реально существующего объекта, который хранится в ImageList1. Кроме того, этим же объектом пользуется процедура ListBox1DrawItem. Кода ты выполняешь Bitmap.Free, объект уничтожается, и при обращеннии по его адресу из другого места программы имеем глюк.
Сергей М. (2009-11-05 10:54:00) [12]
> Какая связь между двумя переменными Bitmap1(объявлена в
> первом блоке кода) и Bitmap(объявлена во втором блоке)
Обе переменные содержат значение, являющее собой указатель на один и тот же объект.
kyn66 (2009-11-05 10:50:00) [13]Уважаемые мастера! Прошу разъяснить еще раз, ну не могу понять связи.... См.[0]. Какая связь между двумя переменными Bitmap1(объявлена в первом блоке кода) и Bitmap(объявлена во втором блоке). Все сделал как говорили, все работает, но хочу глубже разобраться. В сети нашел почти аналогичный пример http://demi-s.narod.ru/components/034.htmlТм тоже ListBox получает картинки из объекта. Так вот, в блоке примера ListBox1DrawItemтоже объявлена как и у меня переменная Bitmapи после отрисовки она уничтожается. В своей программе я объявил Bitmap1 : TBitmapглобально и уничтожаю ее после деактивации основной формы. Но стоит мне в своем втором блоке уничтожить переменную Bitmapпосле отрисовки ListBox, при закрытии программы вылетает ошибка Access violation по отношению к глобальнообъявленной переменной Bitmap1
procedure TMainFrm.FormDestroy(Sender: TObject);
begin
Bitmap1.Free;
end;
Разъясните спокойно, без эмоций, какая между ними связь? И почему при уничтожении локально объявленной Bitmapтеряется связь с глобально объявленной Bitmap1. Спасибо.
kyn66 (2009-11-03 17:50:00) [14]
> clickmaker © (03.11.09 16:40) [35]
Спасибо.
Германн (2009-11-03 17:43:00) [15]
> Но в данном случае копируются строки, содержащие указатель
> на объект, который нельзя уничтожать ( Bitmap1). Как это
> увязывается вместе?
Если подумать, то этот вопрос сам в себе содержит и точный ответ и ошибку в понимании основ. :)
clickmaker (2009-11-03 16:40:00) [16]> Как это увязывается вместе?
так, что строки - управляемый объект. Для них VCL выделяет память и следит за ссылками. А про абстрактный объект метод ничего не знает. Там может быть и record и просто число типа int
kyn66 (2009-11-03 16:20:00) [17]
> а AddStrings - копирует строки в листбокс
Но в данном случае копируются строки, содержащие указатель на объект, который нельзя уничтожать (Bitmap1). Как это увязывается вместе?
Германн (2009-11-03 16:19:00) [18]
> Я извеняюсь, не вовремя объявил о закрытии темы. Хотел задать
> еще один вопрос , а чем от Bitmap1 отличается st. При уничтожении
> Bitmap1 возникает ошибка(правильная), а при уничтожении
> st ошибки нет? Чем они отличаются?
>
Они ничем не отличаются друг от друга. Обе - локальные переменные процедуры FormSt.
А отличие указано в
> clickmaker © (03.11.09 13:47) [24]
>
> > Я подумал что он уже не нужен, поскольку Listbox1 уже
> наполнен
> > данными
>
> AddObject не копирует объект.
clickmaker (2009-11-03 16:16:00) [19]> чем от Bitmap1 отличается st
тем, что AddObject НЕ копирует объект, а AddStrings - копирует строки в листбокс
kyn66 (2009-11-03 15:59:00) [20]2Сергей М. ©
Я извеняюсь, не вовремя объявил о закрытии темы. Хотел задать еще один вопрос , а чем от Bitmap1отличается st. При уничтожении Bitmap1 возникает ошибка(правильная), а при уничтожении st ошибки нет? Чем они отличаются?
...
st.AddObject('третья запись', Bitmap1);
end;
ListBox1.Items.AddStrings(st);
st.Free;
Bitmap1.Free;
end;
[0]
Спецом решил уничтожить stи все работает...