Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 4 532

/ вопрос открыт /

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

P.S. про dispose знаю, но это не помогает в моей проблеме, и потом еще думаю что если не уничтожить панель, то возможны утечки памяти.

Приложение:
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6. Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7. Dialogs, StdCtrls;
  8.  
  9. type
  10. TForm1 = class(TForm)
  11. Button1: TButton;
  12. procedure FormClick(Sender: TObject);
  13. procedure Button1Click(Sender: TObject);
  14. procedure FormCreate(Sender: TObject);
  15.  
  16. private
  17. { Private declarations }
  18. public
  19. { Public declarations }
  20. end;
  21.  
  22. type MyFerst = record
  23. num: integer;
  24. next: Pointer;
  25. End;
  26.  
  27. type TMyElement = record
  28. prev: Pointer;
  29. button: TButton;
  30. next: Pointer;
  31. End;
  32.  
  33. type MyElementP = ^TMyElement;
  34.  
  35. var
  36. Form1: TForm1;
  37. MyButton: TButton;
  38. i:integer;
  39.  
  40.  
  41.  
  42.  
  43.  
  44. implementation
  45.  
  46. {$R *.dfm}
  47.  
  48.  
  49. procedure TForm1.FormClick(Sender: TObject);
  50. var
  51. ALeft, ATop, AWidth, AHeight: Integer;
  52. MyPoint: TPoint;
  53. p:pointer;
  54. Begin
  55. Windows.GetCursorPos(MyPoint);
  56. AWidth := 75;
  57. AHeight := 25;
  58. ALeft := MyPoint.X-Form1.Left-5;
  59. ATop := MyPoint.Y-Form1.Top-35;
  60.  
  61. i:=i+1;
  62.  
  63.  
  64. Ferst.num:=i;
  65.  
  66.  
  67. Begin
  68. Ferst.next:=Pointer(ElementP);
  69. Element:=ElementP^;
  70. Element.prev:=@Ferst;
  71. End
  72.  
  73. Begin
  74. Element.next:=Pointer(ElementP);
  75. p:=@Element;
  76. Element:=ElementP^;
  77. Element.prev:=p;
  78. End;
  79.  
  80.  
  81. Element.next:=nil;
  82.  
  83. MyButton:=Element.button;
  84. MyButton.Parent:=Form1;
  85. MyButton.Name:='ButtonN'+IntToStr(i);
  86.  
  87.  
  88. end;
  89.  
  90. procedure TForm1.Button1Click(Sender: TObject);
  91. begin
  92. ElementP:=MyElementP(Ferst.next);
  93. Element:=ElementP^;
  94. MyButton:=Element.button;
  95.  
  96. end;
  97.  
  98. procedure TForm1.FormCreate(Sender: TObject);
  99. begin
  100.  
  101. Ferst.next:=nil;
  102. end;
  103.  
  104. end.


SOA Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: SOA (статус: Посетитель)
Вопрос отправлен: 24 августа 2010, 18:14
Состояние вопроса: открыт, ответов: 1.

Ответ #1. Отвечает эксперт: Вадим К

Здравствуйте, SOA!
Вообще то я рекомендовал бы взять TList и не заниматься изобретением велосипедов. Там просто.
вначале создам
list := TList.create;

добавляем
list.add(button);

удаляем по индексу
but := TButton(list[i]);
but.free;
list.delete(i);

удалим list в конце работы
list.free;
правда перед этим не забываем почистить оставшиеся элементы.


Если по коду, то тут есть базовое недопонимание. Оно в строках
Element:=ElementP^;
Element.prev:=@Ferst;

В первой строке объект копируется, это же запись.
и когда в следующей строке делается присваивание, то исходный объект, куда указывает ElementP^ не изменяется! И так как указатель указывает неведомо куда, получаем в лоб.
нужно первую строку выкинуть, а в второй писать так
ElementP^.prev:=@Ferst;

Ответ отправил: Вадим К (статус: Академик)
Время отправки: 24 августа 2010, 18:39
Оценка за ответ: 5

Комментарий к оценке: Спасибо за разъяснения, если сделать так как вы написали, то все работает.

Мини-форум вопроса

Всего сообщений: 25; последнее сообщение — 13 октября 2014, 23:07; участников в обсуждении: 5.

Страницы: [1] [2] [Следующая »]

SOA

SOA (статус: Посетитель), 25 августа 2010, 07:32 [#1]:

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

^Element:=Pointer(ElementP);

не придумал, а компилятор ругается на эту конструкцию.
Я конечно понимаю что скорее всего это нереально, но всетаки вы случайно не знаете как можно изменять указатель переменной в delphi?
min@y™

min@y™ (статус: Доктор наук), 25 августа 2010, 09:44 [#2]:

Да выкинь ты этот связный список к ядрене фене! Ну нафига тебе такой геморрой? Тебе ж сказали: юзай TList и куча проблем сразу испарится.
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
SOA

SOA (статус: Посетитель), 25 августа 2010, 10:28 [#3]:

To min@y™:
Вместо связного списка сначала хотел использовать динамический массив и вроде бы все работало, но при создании третьей кнопки, непонятно почему возникала ошибка обращения к памяти, из-за чего и было решено использовать связный список, ввиду того что работа будет вестись исключительно через указатели.
Вадим К

Вадим К (статус: Академик), 25 августа 2010, 10:31 [#4]:

Посмотрим на эту конструкцию
^Element:=Pointer(ElementP);
в ней две ошибки.
во первых, что такое:
^Element
Такого синтаксиса нет.
а
Pointer(ElementP);
это приведение переменной к безтипному указателю. Смысла особого нет.

Цитата (SOA):

но всетаки вы случайно не знаете как можно изменять указатель переменной в delphi

А можно словами объяснить детальней, что это такое должно получиться, а то выглядит страшненько. У переменной нет указателя. У переменной есть адрес. Но его изменить в процессе работы нельзя.
Галочка "подтверждения прочтения" - вселенское зло.
SOA

SOA (статус: Посетитель), 25 августа 2010, 10:35 [#5]:

Вадим К
>У переменной есть адрес. Но его изменить в процессе работы нельзя.

Этого то я и боялся.
min@y™

min@y™ (статус: Доктор наук), 25 августа 2010, 10:40 [#6]:

Никак не пойму: ты боишься использовать TList, что-ли? Думаешь, слишком сложно, да?
На его основе, кстати, можно создать и TButtonList! :))
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
SOA

SOA (статус: Посетитель), 25 августа 2010, 10:52 [#7]:

To min@y™:
я не собираюсь, ничего доказывать, или опровергать, не до этого.
Вадим К

Вадим К (статус: Академик), 25 августа 2010, 10:55 [#8]:

Цитата (SOA):

Этого то я и боялся.

Этого бояться нельзя. это преимущество.
А вот для реализации того, что хочется, как раз нужны указатели.
Галочка "подтверждения прочтения" - вселенское зло.
min@y™

min@y™ (статус: Доктор наук), 25 августа 2010, 11:05 [#9]:

Цитата (SOA):

я не собираюсь, ничего доказывать, или опровергать, не до этого.

Ты реально хочешь оставить свой связный список, когда есть более эффективные варианты? Серьёзно?
Делаю лабы и курсачи по Delphi и Turbo Pascal. За ПИВО! Пишите в личку, а лучше в аську. А ещё лучше - звоните в скайп!
Roma_no_off

Roma_no_off (статус: Посетитель), 25 августа 2010, 22:29 [#10]:

А какой смысл пользоваться TList'ми и прочим, когда у формы есть свойство Components? Оно и содержит все, что находится на форме, а узнать, что это конкретно кнопка можно простой конструкцией:
if Form1.Components[i] is TButton then ...
SOA

SOA (статус: Посетитель), 26 августа 2010, 13:38 [#11]:

Помогите пожалуста с кодом еще раз, не могу понять почему компилчтор ругается на Self, хотя не должен.
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;
 
type
  TForm1 = class(TForm)
    procedure FormClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
type buttonP = ^TButton;
 
Procedure AddElement(c: TRect);
 
var
  Form1: TForm1;
  NowActive: TButton;
  Button: buttonP;
  i: integer =0 ;
 
implementation
 
{$R *.dfm}
 
Procedure AddElement(c: TRect);
var
Point: TPoint;
AWidth,AHidth,ATop,ALeft: Integer;
Begin
new(Button);
 
Button^:=TButton.Create(Self); // Ругается тут
nowActive:=Button^;
Windows.GetCursorPos(Point);
ALeft:=Point.X-c.Left-5;
ATop:=Point.Y-c.Top-35;
AWidth:=49;
AHidth:=41;
i:=i+1;
NowActive.Name:='hello '+IntToStr(i);
NowActive.Parent:=Self; // Также ругается тут
NowActive.SetBounds(ALeft,ATop,AWidth,AHidth);
 
End;
 
procedure TForm1.FormClick(Sender: TObject);
begin
AddElement(Form1.ClientRect);
end;
 
end.
Вадим К

Вадим К (статус: Академик), 26 августа 2010, 14:01 [#12]:

Логично, что он ругается. потому что где ему взять self в этой процедуре?
По порядку, что такое self ? - это первый неявный параметр любого нестатического метода (не процедуры!)
То есть на самом деле, метод для обработчика клика кнопки выглядит так
procedure TForm1.FormClick(Self:TForm; Sender: TObject);
Просто этот первый параметр скрывается и разруливается компилятором.
Self указывает на та экземпляр класса (то есть объект), который "владеет" этим методом. то есть в данном случае это форма.


процедура Procedure AddElement(c: TRect); не является методом и поэтому у нее нет первого скрытого параметра. и взяться ему негде. Поэтому наиболее простой способ исправить, это заменить в Procedure AddElement(c: TRect); слово self на form1.
Галочка "подтверждения прочтения" - вселенское зло.
SOA

SOA (статус: Посетитель), 26 августа 2010, 14:05 [#13]:

Так ведь он (компилятор) не хочет даже создавать кнопку

Button^:=TButton.Create(Self); // Ругается тут

хотя должен.
Вадим К

Вадим К (статус: Академик), 26 августа 2010, 14:20 [#14]:

а зачем все это
type buttonP = ^TButton;
????
зачем плодить указатель на ссылку???
TButton - это просто ссылка, поэтому половина кода бессмыслена.
Procedure AddElement(c: TRect);
var
Point: TPoint;
AWidth,AHidth,ATop,ALeft: Integer;
Button:TButton;
Begin
 
Button:=TButton.Create(form1); 
nowActive:=Button;
Windows.GetCursorPos(Point);
ALeft:=Point.X-c.Left-5;
ATop:=Point.Y-c.Top-35;
AWidth:=49;
AHidth:=41;
i:=i+1;
NowActive.Name:='hello '+IntToStr(i);
NowActive.Parent:=form1;
NowActive.SetBounds(ALeft,ATop,AWidth,AHidth);
 NowActive.visible := true;
End;
то Roma_no_off :
в некоторых случаях бывает очень удобно хранить именно свои компоненты так. а то на форме могут быть ещё кнопки...
Галочка "подтверждения прочтения" - вселенское зло.
SOA

SOA (статус: Посетитель), 26 августа 2010, 14:23 [#15]:

Вы правы все так.
Вадим К

Вадим К (статус: Академик), 26 августа 2010, 14:29 [#16]:

Тяжелое влияние с++ ?
Галочка "подтверждения прочтения" - вселенское зло.
SOA

SOA (статус: Посетитель), 26 августа 2010, 17:16 [#17]:

Если вы про связный список, то я его не считаю тяжелым влиянием, наоборот, в свое время он помог мне лучше понять, как обращаться с указателями и зачем они нужны.
А если про незнание что такое Self, так это только потому что delphi я преимущественно изучал не по книжкам, а по FAQ и Help.
Вадим К

Вадим К (статус: Академик), 26 августа 2010, 17:26 [#18]:

нет, я имел ввиду создание указателя для ссылки и вообще стиль написания кода.
Галочка "подтверждения прочтения" - вселенское зло.
SOA

SOA (статус: Посетитель), 26 августа 2010, 17:41 [#19]:

Указатель для ссылки создавался по примеру help для delphi
Help -> New procedure -> Example

В C++ насколько знаю с указателями попроще, там только Pointer используется.(Не надо запоминать какой тип указателя создал для того или иного типа).
Вадим К

Вадим К (статус: Академик), 26 августа 2010, 17:42 [#20]:

Цитата (SOA):

В C++ насколько знаю с указателями попроще, там только Pointer используется.(Не надо запоминать какой тип указателя создал для того или иного типа).

неправда:)
Галочка "подтверждения прочтения" - вселенское зло.

Страницы: [1] [2] [Следующая »]

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:53
Выполнено за 0.03 сек.