IPB
ЛогинПароль:

> ВНИМАНИЕ!

Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Событие для динамически созданного компонента
сообщение
Сообщение #1


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Продолжнение "Вызывает антирес и такой ишо разрез"
Как можно осуществить событие для динамически созданного компонента? Проблема в том, что программа модульная и "процедура не описана как метод формы".
procedure MyOnClick(Sender: TObject);
begin
form1.Label1.Caption:=inttostr(form1.MainMenu1.Items.IndexOf(sender as TMenuItem));
end;

procedure CreateSubMenu(MainMenu: TMainMenu; p: TP);
var
i,j: integer;
k: longint;
N: TMenuItem;
begin
k:=3;
//...
SetLength(MenuItemArray, 2, k);
for j:=0 to k-1 do
for i:=0 to 1 do
begin
N:=TMenuItem.Create(MainMenu);
n.Caption:=inttostr(i)+inttostr(j);
n.OnClick:=MyOnClick; //вот здесь пишет Incompatible types: 'method pointer and regular procedure'
MainMenu.Items[i+1].items[1].Insert(j,n);
MenuItemArray[i][j]:=n;
end;
end;

Сама программа: Прикрепленный файл  VstupInfo.rar ( 275.13 килобайт ) Кол-во скачиваний: 502


Сообщение отредактировано: sheka -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Цитата
Как можно осуществить событие для динамически созданного компонента?
Легко:

procedure CreateSubMenu(MainMenu: TMainMenu; p: TP);
var
// ...
M: TMethod; // Делай раз !!!
begin
// ...
// n.OnClick:=MyOnClick; // Это не нужно

M.Code := @MyOnClick; // Делай два !!!
M.Data := n;
n.OnClick := TNotifyEvent(M); // Всё, собственно, обработчик установлен

// ...
end;
Работоспособность твоего кода не проверял, ибо не надо использовать нестандартных компонентов smile.gif Не у всех они присутствуют.

Добавлено через 2 мин.
Да, кстати, на предупреждения компилятора тоже обращай внимание, ладно? У тебя будет как минимум одно предупреждение, связанное с некорректной работой с переменными цикла (хоть проект и не открылся в Дельфи, но как текстовый файл я его просмотрел, это предупреждение видно невооруженным взглядом).
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Гость






Итак, я нашел, что не давало открывать проект в D2009 - одно из свойств TIdHTTP уже отсутствует, поэтому проект не открывался. Открыл. Посмотрел... Могу подсказать, что надо будет сделать, чтобы оно заработало в 2009/2010, если тебя интересует (в том виде, в котором это сейчас - оно не очень-то работает, только при совпадении некоторых условий, а это плохой стиль программирования). Но это - не главное, что я хотел сказать. Главное - в другом.

У тебя парсинг сделан "в лоб". А зачем? Можно же воспользоваться средствами, которые тебе предоставляет Дельфи, и тогда вот это:

Цитата
procedure FindWreckersOnline(var Memo: TMemo;source: string);
var
prev,i: longint;
s,n,m: string;
poem: ansistring;
begin
// ... тут - получение строки Poem
prev:=0;
while PosEx('<tr><td>',poem,prev+1)<>0 do
begin
s:='';
prev:=PosEx('<tr><td>',poem,prev+1);
for i:=prev to PosEx('</td></tr>',poem,prev) do
s:=s+poem[i];
for i:=1 to 6 do
delete(s,pos('<',s),pos('>',s)-pos('<',s)+1);
n:='';
i:=1;
while s[i] in Digits do
begin
n:=n+s[i];
inc(i);
end;
delete(s,1,length(n));
i:=1;
while (s[i] in Letters)or (s[i]=' ') do
inc(i);
m:='';
while s[i] in Digits do
begin
m:=m+s[i];
inc(i);
end;
delete(s,pos('<',s)-length(m),length(s)-pos('<',s)+length(m)+1);
Memo.Lines.Append(Format('%-5s',[n])+Format('%-7s',[m])+s);
end;
end;
Станет вот этим:

procedure FindWreckersOnline(var Memo: TMemo; source: string);
var
// ...
poem: string;
i, start, finish, counter: integer;
SL: TStringList;
begin
// Получение Poem с сайта
start := PosEx('<tbody>', Poem) + Length('<tbody>'#$A'<tr><td>');
finish := PosEx('</table>', Poem, start);
Poem := Copy(Poem, start, finish - start);

SL := TStringList.Create;
try
Poem := StringReplace(Poem, ' ', '_', [rfReplaceAll]);
Poem := StringReplace(Poem, #$A'<tr><td>', '|', [rfReplaceAll]);
Poem := StringReplace(Poem, '</td><td>', '|', [rfReplaceAll]);
Poem := StringReplace(Poem, '</td></tr>', '', [rfReplaceAll]);

SL.Delimiter := '|'; SL.DelimitedText := Poem;
counter := pred(SL.Count div 6);

Memo.Lines.BeginUpdate;
for i := 0 to counter do
begin
Memo.Lines.Add(Format('%-5s%-7s %s',
[SL.Strings[6*i + 0],
StringReplace(SL.Strings[6*i + 1], '_', ' ', [rfReplaceAll]),
SL.Strings[6*i + 2]]));
end;
Memo.Lines.EndUpdate;

finally
SL.Free;
end;
end;
Ошибиться, как видишь, практически негде... Работает абсолютно так же, как твой код, только я один пробел (между фамилией и баллом, добавил, чтоб лучше смотрелось) smile.gif
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Цитата
Легко
Да...lol.gif
А я то думал они есть и были у всех, кроме меня..Прикрепленный файл  Indy_9_00_17_src.zip ( 937.21 килобайт ) Кол-во скачиваний: 395


Я видел это предупреждение(это там где for i:=i to.., да?), но подумал, раз я его нигде не использую - то ничего страшного. А чем это может быть опасно?

Как можно вручную открыть окно "Мessages"?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Гость






Цитата
А я то думал они есть и были у всех, кроме меня..
А я думал, что у меня более новая версия (Indy 10), в которой НЕТ свойства MaxLineAction. Я что, должен теперь установить более старую версию? smile.gif

Цитата
Как можно вручную открыть окно "Мessages"?
Нажать на Alt+F7 или Alt+F8 (переход к предыдущей/следующей ошибке), при этом должно появиться и окно Messages, если ошибки/предупреждения были, конечно.

Цитата
Я видел это предупреждение(это там где for i:=i to.., да?), но подумал, раз я его нигде не использую - то ничего страшного.
Ау.... Кто и чего где не использует? Ты получил предупреждение? Так вот тебе надо сделать так, чтоб твоя программа компилировалась без предупреждений. Чем опасно? Вот этим:

http://www.delphibasics.co.uk/RTL.asp?Name=For
Цитата
Notes
The loop Variable value is not guaranteed by Delphi at loop end. So do not use it!
Теперь понимаешь, в чем проблема?
      for i:=prev to PosEx('">',poem,prev)-1 do
s:=s+poem[i];

// Вот тут чему равно i? Ты можешь гарантировать это?
Source.Name:=s;
s:='';
for i:=i+length('">') to PosEx('</td>',poem,i)-1 do // Здесь возникает предупреждение !!!
s:=s+poem[i];

После окончания первого цикла у тебя i может быть не равно PosEx('">',poem,prev)-1 (на что ты рассчитываешь), тогда весь твой второй цикл улетит в тартарары... Будет незнамо где начинаться (и неизвестно где заканчиваться, потому как конечное значение второго цикла тоже вычисляется с учетом i). Дельфи гарантирует, что i будет принимать какое-то осмысленное значение ТОЛЬКО тогда, когда цикл закончился Break-ом, тогда то значение переменной, при котором произошел Break, сохранится и после цикла. У тебя Break отсутствует так что ничего определенного по поводу значения i сказать нельзя. Не зря во многих языках управляющая переменная цикла видима только внутри самого цикла, чтоб к ней потом нельзя было обратиться.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


procedure TForm1.FormCreate(Sender: TObject);
var
M: TMethod; // Делай раз !!!
begin
// ...
M.Code := @MyOnClick; // Делай два !!!
M.Data := n;
n.OnClick := TNotifyEvent(M); // Всё, собственно, обработчик установлен
// ...
end;

А что делать если в MyOnClick нужно еще передать дополнительные параметры?
MyOnClick(Sender: TObject;n: integer;var SourceVisual: TSourceVisual);
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Цитата
Могу подсказать, что надо будет сделать, чтобы оно заработало в 2009/2010, если тебя интересует (в том виде, в котором это сейчас - оно не очень-то работает, только при совпадении некоторых условий, а это плохой стиль программирования)

Подскажите, пожалуйста.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


mea culpa
*****

Группа: Пользователи
Сообщений: 1 372
Пол: Мужской
Реальное имя: Николай

Репутация: -  24  +


Цитата
The loop Variable value is not guaranteed by Delphi at loop end. So do not use it!


Ого, я тоже всегда считал, что если цикл завершился, то "loop variable" будет равна конечному параметру..


--------------------
"Знаешь, стыдно - когда не видно, что услышал всё, что слушал.."
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Гость






Цитата
Подскажите, пожалуйста.
Вот так:


procedure FindWreckersOnline(var Memo: TMemo;source: string);
var
srvReply: TStringStream;
Poem: string; // Подразумевается WideString

i, start, finish, counter: integer;
SL: TStringList;
begin
srvReply := TStringStream.Create('', 1251); // Будем получать данные в кодировке 1251
Form1.IdHTTP1.Get(source, srvReply);
Poem := srvReply.DataString; // Пересылаем в строку полученную информацию ...

... при этом работу по перекодировке из 1251 (или любой другой кодировки, которая указана в TStringStream.Create вторым параметром) возьмет на себя Дельфи.

Цитата
Ого, я тоже всегда считал, что если цикл завершился, то "loop variable" будет равна конечному параметру..
Очень плохо. Я тысячу раз говорил, что это не так, ни в Дельфи ни в Паскале, нигде это не должно подразумеваться, но никто ж не слушает... И в Турбо Паскале тоже нельзя было полагаться на подобное поведение, но на это тоже всем наплевать, здесь и сейчас работает и ладно.

Цитата
А что делать если в MyOnClick нужно еще передать дополнительные параметры?
Подумать, так ли они нужны на самом деле. Потому что обработчик события OnClick имеет строго определенную сигнатуру:
Цитата
type TNotifyEvent = procedure (Sender: TObject) of object;
, что явно не подразумевает передачу дополнительных параметров. Попробуй передать доп. параметры (а самое главное - обработать их в самОй процедуре), если обработчик - метод класса, то есть, без этих всяких ухищрений с TMethod... Получится у тебя это?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Я.
****

Группа: Пользователи
Сообщений: 809
Пол: Мужской
Реальное имя: Саша

Репутация: -  11  +


Все, конечно же, можно обойти, но так было бы чуть короче:
Код (Показать/Скрыть)


Ну и сам проэкт Прикрепленный файл  VstupInfo.rar ( 284.58 килобайт ) Кол-во скачиваний: 390


Добавлено через 8 мин.
А вот ответ на Ваш код
srvReply := TStringStream.Create('', 1251);

Цитата
[Error] Too many actual parameters
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Гость






Цитата
А вот ответ на Ваш код

Цитата
Могу подсказать, что надо будет сделать, чтобы оно заработало в 2009/2010
, если что:
Прикрепленное изображение

Так что Дельфи 2009 обрабатывает совершенно нормально мой код (предупреждения о CharInSet - не в счет, я их пока не исправлял, и они выше по тексту)

Цитата
но так было бы чуть короче:
И сильно неправильнее, кстати. Я ж тебе сказал, какую сигнатуру имеет TNotifyEvent, а ты опять за свое. КАК ТЫ ОБЪЯСНИШЬ Дельфи, что функция с двумя параметрами должна втиснуться в то, что Дельфи с рождения знает, как TNotifyEvent - то есть, в функцию с одним параметром? Покажи мне, не как ты обходишь то, что наворотил, а как Дельфи принимает вместо одного параметра два, и как именно ты к этим параметрам обращаешься при выполнении кода. (Очень удачно ты сделал, да? Сначала выбрал неправильную структуру программы, потом обошел еще более неправильным костылем, и вроде бы даже и прав остался? Сейчас все работает, а потом - хоть потоп? Ну, разубеждать тебя не буду, дел у меня других нет что-ли... Потом сам придешь спрашивать. Я даже знаю, что именно. Но это уже, извини, без меня. Я больше на твои вопросы не отвечаю...)

Удачи...
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 27.04.2024 12:15
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name