|
Вопрос # 3 529/ вопрос открыт / |
|
Здравствуйте, эксперты!
Когда жму кнопку один, программа должна найти пути всех DLL в папке Plugins и получить их типа и имена, а так же имена файлов.
Когда жму 2-ю кнопку, в ЛистБокс надо вывести имена всех плагинов. Почему-то не могу. Прикрепляю проект, подскажите в чем ошибка плиз, я классы первый раз пишу, скорее всего что-то недопонял. Заранее спасибо!
К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса)
 |
Вопрос задал: webkent (статус: 2-ой класс)
Вопрос отправлен: 15 декабря 2009, 10:47
Состояние вопроса: открыт, ответов: 1.
|
Ответ #1. Отвечает эксперт: Вадим К
Здравствуйте, webkent!
Посмотрел код. в коде есть откровенное непонимание. например строка
ListBox1.Items:=PL.Items.GetNames
Это очень плохая конструкция. Если оно заработает, то это будет странно... Правильно как минимум так
ListBox1.Items.Clear;
ListBox1.Items.AddString(PL.Items.GetNames)
правда, в данном коде это не поможет. Потому что реализация GetNames плохая. В ней явная утечка памяти. Что бы избежать утечку памяти, надо либо сделать метод вида
procedure GetNames(sl:TStrings);
и вызывать как
Pl.items.GetNames(ListBox1.items);
В середине метода можно напрямую обращаться к строкам ListBox через параметр sl (то есть просто sl.Add(строка); Реализацию внутри пишите сами.
Реализация GetFileNames ещё веселее - там вызываются методы не созданного объекта. И GetTypes тоже:)
пойдем дальше
List:array[0..MaxListSize] of TPlugin
лучше писать
List:TList; плюс в коде будет пара приведений. Но зато не надо будет извращаться с SetLength и думать, как удалить элемент с середины списка.
MaxListSize... это интересная конструкция. Если бы знали, как она получается, не использовали бы. посмотрите на значение этой константы. Пара таких классов и прощай память. (подсказка const MaxListSize = Maxint div 16; Maxint = 2 в 31 степени минус 1.)
конструкцию
Procedure log(MSG:Tstrings);
var i:integer;
begin
{...............................................................................}
if MSG.Count=1 then
MSG[0]:=DateTimeToStr(Now)+' '+MSG[0]
else
for i:=0 to MSG.Count-1 do
MSG[i]:=DateTimeToStr(Now)+' '+MSG[i];
{...............................................................................}
MSG.SaveToFile('PluginsLog.txt');
end;
долго рассматривал. неужели условие действительно нужно? сомневаюсь. Там только цикл нужен.
И теперь вернемся к основном коду. имеем метод Initialize. Я так подозреваю, что это конструктор. Но для объекта Pl настоящий конструктор не вызывается... печально. Поэтому работать сей код в принципе не должен.
Код кнопки должен выглядеть где то так
Pl:=TPlugins.Create;
PL.Initialize;
Pl.items.GetNames(ListBox1.items);
Pl.Free;
и не надо две кнопки:) исправте код, а там будет видно, что дальше делать.
 |
Ответ отправил: Вадим К (статус: Академик)
Время отправки: 15 декабря 2009, 23:19
Оценка за ответ: 5
|
Мини-форум вопроса
Всего сообщений: 14; последнее сообщение — 18 декабря 2009, 16:09; участников в обсуждении: 4.
|
IlluminatI (статус: 2-ой класс), 15 декабря 2009, 21:10 [#1]:
webkent, получить "их типа и имена", это в смысле расширение и имя? имя понятно зачем получать, а вот расширение зачем? Вы указали, что нужно получить список dll, значит и расширения у них будут dll. Или тут что-то другое имеется ввиду?
|
|
Мережников Андрей (статус: Абитуриент), 15 декабря 2009, 21:26 [#2]:
to IlluminatI: "их типа и имена" это что-то другое, отличное от имени файла и расширения потому, что далее по тексту вопрошающий говорит об именах файлов. Так что телепаты отдыхают...
|
|
webkent (статус: 2-ой класс), 16 декабря 2009, 08:36 [#3]:
2 Вадим К:
Спасибо за ответ!
"Это очень плохая конструкция. Если оно заработает, то это будет странно... Правильно как минимум так. "
почему? А если я хочу не добавить в листбокс, а присвоить ему значения, возвращенные функцией. Конечно, можно и GetNames(sl:TStrings), но чем такой вид лучше?
По поводу цикла, вы снова правы, убрал условие.
"List:array[0..MaxListSize] of TPlugin"
Тут я согласен, но, можно ли вызывать из TList методы его членов типа TPlugin? Допустим вот так реально сделать, используя TList?:
var s:string;
s:=TList[n].GetName();
Если можно, то как это сделать? Если я пишу так:
Items:TList;
То потом не могу вызвать методы отдельного TPlugin:
PL.Items[n].КакойтоМетод; //Не работает. Как правильно, подскажите?
По поводу конструктора, а в процедуре Initialize я писал такую строку Self:=TPlugin.Create. Почему-то думал, что должно работать, но сейчас и сам понимаю что ошибся.
Вот версия, в которой я исправил то что вы написали, кроме array of TPlugin т.к. не знаю как правильно использовать их методы из TList: http://webfile.ru/4164853
Спасибо огромное за ответы, очень помогаете развиваться!
|
|
Вадим К (статус: Академик), 18 декабря 2009, 00:02 [#4]:
Расскажу о некоторых моментах, может улучшит Ваше понимание.
Итак, пусть у нас есть приватное поле list:TList;
итак, в конструкторе нам надо это создать
list:=TList.create;
в деструкторе соответственно почистим вложенные объекты и сам лист
for i:=0 to list.count-1 do
TPlugin(list[i]).Free;
list.free;
Теперь напишем метод добавления
function TPlugins.add:TPlugin;
begin
result := TPlugin.Create;
list.add(result);
//тут можно заполнить дефолтные параметры нового элемента
end;
использовать так
var p:TPlugin;
begin
//...
p := pl.Add();//эта строка фактически конструктор и добавление в список
p.метод(); //а теперь можно вызывать методы нового элемента
//...
end;
поехали дальше. Сделаем удобное обращение к элементам
в описании класса
private
procedure GetPrivate(index:integer):TPlugin;
public
property Items(index:integer):TPlugin read GetPlugin;default;
и реализация
procedure TPlugins.GetPrivate(index:integer):TPlugin;
begin
if (index < 0) or (index >= list.count)
ShowMessage('ОШИБКА, индекс за пределами!!!!')// тут конечно лучше сгенерировать исключение.
else
result := TPlugin(list[index]);
end;
теперь можно писать так
pl.items[1].метод();
а благодаря слову default даже так
pl[2].метод();
не правда, красиво получается?
поехали дальше, напишем метод Count, что бы выводило кол-во элементов
//описание класса
public
function Count:integer;
//....
//реализация
function TPlugins.Count():integer;
begin
result := list.Count;
end;
метод "удалить элемент по индексу"
//реализация
procedure TPlugins.Delete(index:integer);
begin
TPlugin(list[index]).free;
list.delete(index);
end;
Думаю, другие методы себе сами напишите.
Для класса TList такое включение предпочтительней наследования. Почему? да просто наружу выносятся только те методы, которые реально надо. Во вторых - полный контроль над ним. Никакой другой код не повлияет.
В третьих. припустим, что TList оказался плохим решением, а у нас написана большая программа. Мы только заменим в одном модуле, перепишем несколько методов и готово.
Как только освоите эту методику, многие куски кода можно будет красиво упрощать. Можно будет делать классы с заданной функциональностью и потом легко управлять ими.
комментарии к предыдущему посту.
код вида
s:=TList[n].GetName();
не будет работать. потому что у TList нет классового метода с default. А как писать правильно - я писал выше.
Галочка "подтверждения прочтения" - вселенское зло.
|
|
webkent (статус: 2-ой класс), 18 декабря 2009, 08:56 [#5]:
Спасибо огромное! Вот, как раз то чего мне так не хватало:
TPlugin(list[index]);
Начинаю писать. По возможности буду помогать другим тут на сайте.
|
|
webkent (статус: 2-ой класс), 18 декабря 2009, 11:42 [#6]:
Кстати, тут проблемка, выдает Access violation на строчках
Result:=TPlugin.Create;
Items.Add(Result); --> вот именно при выполнении этой строки.
То же самое при таком виде:
Items.Add(TPlugin.Create);
В чем может быть дело? Items : TPList : TList
|
|
Вадим К (статус: Академик), 18 декабря 2009, 11:49 [#7]:
не могу понять суть строки Items : TPList : TList
Я таких множественных определений не понимаю.
Хотя, если все делано по моему коду, то подозреваю либо рекурсию, либо ....
Приводите полный код. и лучше выкладывайте сразу сюда
https://www.delphi-int.ru/code/paste/
Галочка "подтверждения прочтения" - вселенское зло.
|
|
webkent (статус: 2-ой класс), 18 декабря 2009, 12:03 [#8]:
Items:TPList:TList - это не код, от себя написал, что бы показать, что Items идет от TList.
Вот
https://www.delphi-int.ru/code/22b4dd0f
Строка номер 45. Заранее прошу прощения за то что я такой ламер =)
|
|
webkent (статус: 2-ой класс), 18 декабря 2009, 12:06 [#9]:
там рекурсии нет, просто у TPlugins есть своя ф-ция Add, а у Items - своя.
|
|
webkent (статус: 2-ой класс), 18 декабря 2009, 12:11 [#10]:
Простите дурака, уже допер, не прописал Items:=TPList.Create.
|
|
Вадим К (статус: Академик), 18 декабря 2009, 12:16 [#11]:
Первое. я писал, что наследоваться от TList - плохая затея. Не предназначен этот класс для наследования. Поэтому следует исключить промежуточный класс.
Второе. А ошибка возникает на законном месте. Я же писал - надо конструктор! Или просто не знаем, как выглядит конструктор?
type
TPlugins = class
private
list:TList;
public
constructor Create;
destructor Destroy; override;
end;
constructor TPlugins.Create;
begin
Items := TList.Create;
end;
destructor TPlugins.Destroy;
begin
for i:=0 to list.count-1 do
TPlugin(list[i]).Free;
list.free;
end;
Галочка "подтверждения прочтения" - вселенское зло.
|
|
webkent (статус: 2-ой класс), 18 декабря 2009, 12:26 [#12]:
Не знал, спасибо =)
|
|
Вадим К (статус: Академик), 18 декабря 2009, 13:06 [#13]:
Ну так надо определить свой конструктор Точно также, как я для TPlugins написал. Но конструктор TObject все равно надо вызывать правда он часто неявно вызывается или явно через ключевое слово inherited;
Галочка "подтверждения прочтения" - вселенское зло.
|
|
webkent (статус: 2-ой класс), 18 декабря 2009, 16:09 [#14]:
Да, дело уже продвигается по немногу, вроде бы многое стало понятно.
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|