Помощь - Поиск - Пользователи - Календарь
Полная версия: Событие для динамически созданного компонента
Форум «Всё о Паскале» > Delphi, Assembler и другие языки. > Delphi
sheka
Продолжнение "Вызывает антирес и такой ишо разрез"
Как можно осуществить событие для динамически созданного компонента? Проблема в том, что программа модульная и "процедура не описана как метод формы".
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;

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

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 мин.
Да, кстати, на предупреждения компилятора тоже обращай внимание, ладно? У тебя будет как минимум одно предупреждение, связанное с некорректной работой с переменными цикла (хоть проект и не открылся в Дельфи, но как текстовый файл я его просмотрел, это предупреждение видно невооруженным взглядом).
volvo
Итак, я нашел, что не давало открывать проект в 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
sheka
Цитата
Легко
Да...lol.gif
А я то думал они есть и были у всех, кроме меня..Нажмите для просмотра прикрепленного файла

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

Как можно вручную открыть окно "Мessages"?
volvo
Цитата
А я то думал они есть и были у всех, кроме меня..
А я думал, что у меня более новая версия (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 сказать нельзя. Не зря во многих языках управляющая переменная цикла видима только внутри самого цикла, чтоб к ней потом нельзя было обратиться.
sheka
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);
sheka
Цитата
Могу подсказать, что надо будет сделать, чтобы оно заработало в 2009/2010, если тебя интересует (в том виде, в котором это сейчас - оно не очень-то работает, только при совпадении некоторых условий, а это плохой стиль программирования)

Подскажите, пожалуйста.
Unconnected
Цитата
The loop Variable value is not guaranteed by Delphi at loop end. So do not use it!


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


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... Получится у тебя это?
sheka
Все, конечно же, можно обойти, но так было бы чуть короче:
Код (Показать/Скрыть)


Ну и сам проэкт Нажмите для просмотра прикрепленного файла

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

Цитата
[Error] Too many actual parameters
volvo
Цитата
А вот ответ на Ваш код

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

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

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

Удачи...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.