Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.12.20;
Скачать: CL | DM;

Вниз

Ошибка в коде, который раньше работал.   Найти похожие ветки 

 
kyn66 ©   (2009-11-03 13:14) [0]

Уважаемые мастера. Помогите найти ошибку в коде, взятом из рабочей программы:
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;


Ошибка вылетает на "жирной" строке


 
Демо ©   (2009-11-03 13:22) [1]


> Ошибка вылетает на "жирной" строке


Что за ошибка? И что поменялось в окружении?


 
Сергей М. ©   (2009-11-03 13:23) [2]


> который раньше работал


Он и раньше не мог работать.
Ты ж Bitmap1 собственноручно убиваешь

см. Bitmap1.Free

а потом обращаешься к трупу за свойством Transparent

)


 
kyn66 ©   (2009-11-03 13:26) [3]

Ошибка стандартнонепонятнаяоткудавзятая Access Violation.

> Ты ж Bitmap1 собственноручно убиваешь


Так я же его убиваю Bitmap1, который используется в первой процедуре и нужен только для наполнения st данными. А ошибка вылетает во второй процедуре и используется там Binmap, без цифирей.


 
kyn66 ©   (2009-11-03 13:29) [4]


> Демо ©   (03.11.09 13:22) [1]
> > Ошибка вылетает на "жирной" строкеЧто за ошибка? И что
> поменялось в окружении?


Да собственно особо ничего. Раньше этот код работал в отдельной форме и объявлял я Bitmap в Interface формы, а убивал по Distroy формы. Вот и вся разница.


 
Сергей М. ©   (2009-11-03 13:29) [5]


> используется там Binmap, без цифирей.


И что ?
Цифирь эта  - всего лишь цифирь в идентификаторе лок.переменной.
Которая в строчке

Bitmap := TBitmap(ListBox1.Items.Objects[Index]);

получает значение, равное копии указателя на объект, который ты собственноручно убил в 1-й процедуре.


 
Игорь Шевченко ©   (2009-11-03 13:30) [6]


>     if Bitmap <> nil then


if Bitmap is TBitmap


 
Anatoly Podgoretsky ©   (2009-11-03 13:30) [7]

> kyn66  (03.11.2009 13:14:00)  [0]

Так и пишет "вылетаю на "жирной" строке"


 
Dennis I. Komarov ©   (2009-11-03 13:30) [8]


> Ошибка стандартнонепонятнаяоткудавзятая Access Violation.

очень даже всегда понятная: Был "Вася" и нет его...


 
Игорь Шевченко ©   (2009-11-03 13:30) [9]

Упс. Ты вообще соображаешь, что пишешь ? Марш за книжки


 
Сергей М. ©   (2009-11-03 13:31) [10]


> убивал по Distroy формы. Вот и вся разница


Т.е. убивал объект ты заведомо позже самого последнего обращения к нему.
А теперь ты сначала убил, а потом измываешься над трупом.
Вот и вся разница)


 
kyn66 ©   (2009-11-03 13:31) [11]


> а потом обращаешься к трупу за свойством Transparent


И тем более ошибка в блоке после проверки Bitmap на nil


 
Сергей М. ©   (2009-11-03 13:32) [12]


> в коде, который раньше работал


Раньше был другой код.
Потому и работал.


 
Dennis I. Komarov ©   (2009-11-03 13:32) [13]


> И тем более ошибка в блоке после проверки Bitmap на nil

А с чего ты взял, что там nil?


 
Сергей М. ©   (2009-11-03 13:34) [14]


> ошибка в блоке после проверки Bitmap на nil


А почему бы ей не быть не-nil ?
Ты же записал не-nil, вот она и прошла проверку.
А объект ты убил.
А ссылка на него осталась.


 
kyn66 ©   (2009-11-03 13:34) [15]


> получает значение, равное копии указателя на объект, который
> ты собственноручно убил в 1-й процедуре.


Bitmap локально объявлен во второй процедуре и с успехом инициализируется там же

Bitmap := TBitmap(ListBox1.Items.Objects[Index]);


Терзают смутные сомнения по поводу корректной отработки st.AddObject("вторая запись", Bitmap1)...


 
Сергей М. ©   (2009-11-03 13:35) [16]


> и с успехом инициализируется там же
>


мусором !

Объекта-то нет, ты уничтожил его до этого !


 
Сергей М. ©   (2009-11-03 13:36) [17]


> смутные сомнения по поводу корректной отработки st.AddObject("вторая
> запись", Bitmap1)


Не терзайся, он работает абсолютно корректно - копирует строки и ассоциированные с ними ссылки.


 
clickmaker ©   (2009-11-03 13:36) [18]

> Bitmap локально объявлен во второй процедуре и с успехом
> инициализируется там же
>
> Bitmap := TBitmap(ListBox1.Items.Objects[Index]);

это не инициализация. Это присваивание значения указателя, который указывает уже на труп


 
kyn66 ©   (2009-11-03 13:39) [19]


> Сергей М. ©   (03.11.09 13:34) [14]


Я дико извеняюсь, но закомментировал "убийство" Bitmap1 и все пошло нормально. Я подумал что он уже не нужен, поскольку Listbox1 уже наполнен данными... ListBox1.Items.AddStrings(st);


 
Сергей М. ©   (2009-11-03 13:41) [20]


> акомментировал "убийство" Bitmap1 и все пошло нормально


Теперь тебя ждут другие грабли - утечка памяти


 
Dennis I. Komarov ©   (2009-11-03 13:43) [21]


> Сергей М. ©   (03.11.09 13:41) [20]

Фигня то какая... Разве ее мало? Разве нас это заставит буквари читать?


 
kyn66 ©   (2009-11-03 13:44) [22]

Просто procedure FormSt; может повторяться несколько раз, поэтому и решил что нужно удалять ненужные объекты, так как в этой процедуре Bitmap1 создается заново
Bitmap1 := TBitmap.Create;


 
kyn66 ©   (2009-11-03 13:45) [23]



> Сергей М. ©   (03.11.09 13:41) [20]


> Теперь тебя ждут другие грабли - утечка памяти


:) Сообщение появилось пока я про это и пмсал [22].


 
clickmaker ©   (2009-11-03 13:47) [24]

> Я подумал что он уже не нужен, поскольку Listbox1 уже наполнен
> данными

AddObject не копирует объект.
и почему бы не вызвать DM1.ImageList1.GetBitmap(32, Bitmap1); один раз?
а при закрытии программы убить глобальный объект Bitmap1


 
kyn66 ©   (2009-11-03 13:48) [25]

2Сергей М.

Как посоветует мастер поступить в такой ситуации? Чтобы и волки были сыты......


 
kyn66 ©   (2009-11-03 13:51) [26]


> и почему бы не вызвать DM1.ImageList1.GetBitmap(32, Bitmap1);
>  один раз?а при закрытии программы убить глобальный объект
> Bitmap1


Согласен, так можно и сделать. У Bitmap1 небольшая смысловая нагрузка, в плане просто картинку передать и все. Можно его отдельно создать и главное потом не забыть его удалить по завершении.


 
Сергей М. ©   (2009-11-03 13:51) [27]

Вернись к варианту, котоый был раньше ("работал").
И вынеси GetBitmap из тела цикла.


 
Сергей М. ©   (2009-11-03 13:53) [28]


> главное потом не забыть его удалить по завершении


Можешь даже и не удалять - система не обеднеет, это для нее не потеря.


 
Демо ©   (2009-11-03 14:06) [29]


> Сергей М. ©   (03.11.09 13:53) [28]
>
> > главное потом не забыть его удалить по завершении
>
>
> Можешь даже и не удалять - система не обеднеет, это для
> нее не потеря.
>
>

Ж-))


 
kyn66 ©   (2009-11-03 14:45) [30]


> Сергей М. ©   (03.11.09 13:51) [27]
> Вернись к варианту, котоый был раньше ("работал").И вынеси
> GetBitmap из тела цикла.


Все понял! Спасибо!
Тема закрыта.


 
kyn66 ©   (2009-11-03 15:59) [31]

2Сергей М. ©

Я извеняюсь, не вовремя объявил о закрытии темы. Хотел задать еще один вопрос , а чем от Bitmap1 отличается st. При уничтожении Bitmap1 возникает ошибка(правильная), а при уничтожении st ошибки нет? Чем они отличаются?

...
 st.AddObject("третья запись", Bitmap1);
 end;
ListBox1.Items.AddStrings(st);
st.Free;
Bitmap1.Free;
end;


[0]

Спецом решил уничтожить st и все работает...


 
clickmaker ©   (2009-11-03 16:16) [32]

> чем от Bitmap1 отличается st

тем, что AddObject НЕ копирует объект, а AddStrings - копирует строки в листбокс


 
Германн ©   (2009-11-03 16:19) [33]


> Я извеняюсь, не вовремя объявил о закрытии темы. Хотел задать
> еще один вопрос , а чем от Bitmap1 отличается st. При уничтожении
> Bitmap1 возникает ошибка(правильная), а при уничтожении
> st ошибки нет? Чем они отличаются?
>

Они ничем не отличаются друг от друга. Обе - локальные переменные процедуры FormSt.
А отличие указано в

> clickmaker ©   (03.11.09 13:47) [24]
>
> > Я подумал что он уже не нужен, поскольку Listbox1 уже
> наполнен
> > данными
>
> AddObject не копирует объект.


 
kyn66 ©   (2009-11-03 16:20) [34]


> а AddStrings - копирует строки в листбокс


Но в данном случае копируются строки, содержащие указатель на объект, который нельзя уничтожать (Bitmap1). Как это увязывается вместе?


 
clickmaker ©   (2009-11-03 16:40) [35]

> Как это увязывается вместе?

так, что строки - управляемый объект. Для них VCL выделяет память и следит за ссылками. А про абстрактный объект метод ничего не знает. Там может быть и record и просто число типа int


 
Германн ©   (2009-11-03 17:43) [36]


> Но в данном случае копируются строки, содержащие указатель
> на объект, который нельзя уничтожать (Bitmap1). Как это
> увязывается вместе?

Если подумать, то этот вопрос сам в себе содержит и точный ответ и ошибку в понимании основ. :)


 
kyn66 ©   (2009-11-03 17:50) [37]


> clickmaker ©   (03.11.09 16:40) [35]


Спасибо.


 
kyn66 ©   (2009-11-05 10:50) [38]

Уважаемые мастера! Прошу разъяснить еще раз, ну не могу понять связи.... См.[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. Спасибо.



 
Сергей М. ©   (2009-11-05 10:54) [39]


> Какая связь между двумя переменными Bitmap1(объявлена в
> первом блоке кода) и Bitmap(объявлена во втором блоке)


Обе переменные содержат значение, являющее собой указатель на один и тот же объект.


 
RWolf ©   (2009-11-05 10:58) [40]

в Дельфи Bitmap:TBitmap — на самом деле указатель на объект.
Строкой DM1.ImageList1.GetBitmap(32, Bitmap1); ты присваиваешь ему адрес реально существующего объекта, который хранится в ImageList1. Кроме того, этим же объектом пользуется процедура ListBox1DrawItem. Кода ты выполняешь Bitmap.Free, объект уничтожается, и при обращеннии по его адресу из другого места программы имеем глюк.


 
kyn66 ©   (2009-11-05 10:59) [41]


> Обе переменные содержат значение, являющее собой указатель
> на один и тот же объект.


Ну я как и предполагал. Но удалив один указатель, второй-то должен остаться действующим? Как тогда правильно уничтожать такие объекты(применительно к данной ситуации), чтобы они не повисли в памяти?


 
RWolf ©   (2009-11-05 11:05) [42]


> Но удалив один указатель, второй-то должен остаться действующим?

Удаляются не указатели, а объекты, на которые они указывают.

> Как тогда правильно уничтожать такие объекты

.Free, как и любые другие. Просто надо следить за указателями; удалил объект — больше не пользуйся указателями на него.


 
Сергей М. ©   (2009-11-05 11:05) [43]


> тоже объявлена как и у меня переменная Bitmap и после отрисовки
> она уничтожается


При Bitmap.Free уничтожается не переменная, а объект, ранее созданный при вызове конструктора TBitmap.Create, указатель на который записан в переменную Bitmap при присвоении в строке Bitmap := TBitmap.Create.
Сама же лок.переменная Bitmap уничтожается (вместе с ее содержимым, каким бы оно  ни было) при завершении работы метода ListBox1DrawItem (читай - при выполнеии оператора end).
И поскольку содержимое переменной Bitmap нигде никуда не копировалось в ходе работы метода, созданный объект "умер", равно как и единственная существовавшея ссылка на него в переменной Bitmap.
Отныне не существует ни самого объекта, ни ссылок на него.

В твоем же случае ты еще при жизни своего объекта сделал три копиии ссылки на него, после чего убил объект и переменную, с которой были сделаны копии. Но копии-то ссылок остались ! И сразу же после уничтожения объекта они стали указывать в никуда, ибо объекта по адресу, на который о ни по-прежнему указывают, объекта уже нет.


 
Сергей М. ©   (2009-11-05 11:07) [44]


> удалив один указатель, второй-то должен остаться действующим?


Ну что значит "действующим" ?
Да, он продолжает указывать на некий адрес в памяти, по которому раньше жил объект, но по которому этого объекта уже нет, ибо ты уничтожил его своими руками.


 
kyn66 ©   (2009-11-05 11:20) [45]

Очень популярно разъяснено. Понятно, хоть десять переменных привяжи к одному объекту и при уничтожении хотя-бы одной переменной с объектом, все остальные зависнут в воздухе. Я так понял? Так как же мне поступить правильно? Как их уничтожать правильно?


> В твоем же случае ты еще при жизни своего объекта сделал
> три копиии ссылки на него,


Почему 3 ? Вроде 2 должно быть.


 
Сергей М. ©   (2009-11-05 11:29) [46]


> при уничтожении хотя-бы одной переменной с объектом, все
> остальные зависнут в воздухе


Да не переменной, а самого объекта !


> Почему 3 ? Вроде 2 должно быть.


>     st.AddObject("первая запись", Bitmap1); //раз копия
>     st.AddObject("вторая запись", Bitmap1); //два копия
>     st.AddObject("третья запись", Bitmap1); //три копия


 
RWolf ©   (2009-11-05 11:36) [47]

смотри:

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; //и прибили объект! всё, указатели невалидны.


 
kyn66 ©   (2009-11-05 11:39) [48]


> Да не переменной, а самого объекта !


Ну я и имел это ввид (переменной с объектом), пардон за неграмотные выражения. Я решил 2 раза потом, что 1-й раз - DM1.ImageList1.GetBitmap(32, Bitmap1);, а второй, когда Bitmap := TBitmap(ListBox1.Items.Objects[Index]); Вот и решил, что у меня фигурируют две независимые переменные, точнее ссылки на объекты. Сергей, сейчас я понял про связь с объектами. Так как разрулить полюбовно ситуацию с уничтожением объекта. Может так и оставить, уничтожив глобальную по закрытии главной формы? А во втором блоке уничтожение убрать?


 
Сергей М. ©   (2009-11-05 11:47) [49]


> kyn66 ©   (05.11.09 11:39) [48]


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


 
kyn66 ©   (2009-11-05 11:50) [50]

Ок!

2Сергей М.
2RWolf


СПАСИБО за помощь!



Страницы: 1 2 вся ветка

Текущий архив: 2009.12.20;
Скачать: CL | DM;

Наверх




Память: 0.61 MB
Время: 0.016 c
2-1257016742
maxstarts
2009-10-31 22:19
2009.12.20
Программа виснет при скрытие вкладок pagecontrol ов


2-1257157663
Сергей
2009-11-02 13:27
2009.12.20
Как передать данные в CRReport.PrintOut


2-1257005562
minomorf
2009-10-31 19:12
2009.12.20
Как оргаизовать связку число-строка?


2-1256906798
Aleks
2009-10-30 15:46
2009.12.20
Как очистить CheckBoxes при показе ListView?


1-1228851112
Tack
2008-12-09 22:31
2009.12.20
Как открыть длинный URL в браузере?