Должен ли я вычесть 1 из верхней границы моих циклов «для»? - PullRequest
0 голосов
/ 16 ноября 2009

У меня возникли проблемы с выяснением, что происходит с этой функцией. Я не уверен, должен ли я использовать -1 или нет, и независимо от того, как я пытаюсь расположить код, кажется, что он возвращает ноль, даже если это не так. Может ли кто-то со свежими глазами взглянуть? Кроме того, я не уверен, что мой результат: = ноль в правильном месте.

function TFrmMain.FindQueryFrm(Server, Nickname: String): TFrmMessage;
var
  I,M: Integer;
begin
  ///  No -1 in the I loop - why? Because the first childform will not always be
  ///  of type TFrmMessage, which is what we're looking for.
  ///
  ///  Is this approach wrong?
  for I := 0 to MDIChildCount do
  begin
    if Screen.Forms[I] is TFrmMessage then
    begin
      ///  Same concept with -1 here (M Loop)... I need to check all forms
      ///  stored by QueryManager to see if their .MyServer and .QueryWith's match
      ///
      ///  Is the M Loop wrong?
      for M := 0 to QueryManager.Count do
      begin
        if UpperCase((QueryManager[M] as TFrmMessage).MyServer) = UpperCase(Server) then
        begin
          if UpperCase((QueryManager[M] as TFrmMessage).QueryWith) = UpperCase(NickName) then
          begin // BINGO!
            Result := (QueryManager[M] as TFrmMessage);
            exit;
          end;
        end; // HOST COMPARE
      end; // M Loop
    end; // Is TFrmMessage
  end; // I Loop
  Result := nil; // None Found
end;

Ответы [ 4 ]

8 голосов
/ 17 ноября 2009

Если вас интересуют только дети с MDI, как вам кажется, учитывая, что вы используете MDIChildCount формы, то используйте MDIChildren формы имущество. Эти два свойства сочетаются друг с другом, как и свойства FormCount и Forms экрана. Ваш код смешивает свойство form с свойством screen .

begin
  for I := 0 to MDIChildCount - 1 do
  begin
    if MDIChildren[I] is TFrmMessage then
    begin

Кроме того, вам определенно следует вычесть 1 из числа диспетчеров запросов, иначе это означает, что вы неправильно отслеживаете, сколько менеджеров запросов у вас изначально. «-1», который вы видите в большинстве кодов, присутствует, потому что верхняя граница цикла Delphi «for» равна включительно . Переменная цикла начнется с нижней границы, и цикл продолжит работать, пока переменная не пройдет верхнюю границу. Это может помочь вам понять, что происходит в базовом случае, когда в списке нет элементов. В этом случае цикл вообще не должен запускаться, верно? Потому что там нечего найти. Цикл, установленный для запуска из «0 to 0», будет выполняться один раз, поэтому верхняя граница должна быть отрицательной , чтобы предотвратить запуск цикла. (Все это описано в документации .)

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


Я вижу , который вы спрашивали о детях с ДИ на About.com. Там Зарко Гаджич ответил на ваш вопрос , сообщив вам такой код:

for cnt := 0 to -1 + MDIChildCount do

Хотя это действительный код, он не является идиоматическим. Я никогда не видел, чтобы кто-нибудь еще писал такой код, поэтому было бы разумно не использовать эту привычку. Когда мы хотим на единицу меньше, чем что-либо, мы не добавляем буквально отрицательный к значению. Скорее вычитаем положительное:

for cnt := 0 to MDIChildCount - 1 do

В качестве альтернативы, я иногда использую стандартную функцию Pred:

for cnt := 0 to Pred(MDIChildCount) do
1 голос
/ 17 ноября 2009

Возвращается nil, потому что вы на самом деле не посещаете каждую форму в приложении в вашем цикле, и это не имеет никакого отношения к тому, использовать ли в цикле использование -1 (что, в правильно написанной версии, ты должен сделать).

Вы не посещаете каждую форму, потому что вы просматриваете список форм приложений, который содержит MDIChildren и не-MDI-формы. Но значение, которое вы используете, чтобы решить, сколько из этих форм нужно просматривать, - это MDIChildCount. Это число включает только MDIChildren. Итак, если ваше приложение имеет 7 форм, из которых 4 являются детьми MDI, вы просматриваете только первые 4 из 7 форм (ну, 5 из-за проблемы цикла). Если вам нужна форма с номером 6 или 7 (что вполне вероятно), вы никогда ее не получите.

Кроме того, я не вижу, где, внутри цикла на формах, вы на самом деле ссылаетесь на любое свойство формы.

1 голос
/ 17 ноября 2009

Короче говоря: да! Массивы в Delphi основаны на 0, поэтому использование подсчета чего-либо дает вам слишком много.

MyArray[0] := 'first item';
MyArray[1] := 'second item';
for i:=0 to MyArray.count-1 do
begin
  ...
end;

Если вы используете счетчик (равный 2) без минус 1, то при последнем прохождении цикла будет запрашиваться myarray [2], которого там нет.

Короче говоря, вы должны использовать (более чистый) синтаксис, такой как:

for M := 0 to Pred(QueryManager.Count) do
1 голос
/ 16 ноября 2009

Если я не ошибаюсь, поскольку вы используете Screen.Forms, вам также следует использовать Screen.FormsCount.
Если массив имеет N элементов и начинается с индекса 0, мы перечисляем его с 0 .. N-1.
Array[N] было бы неправильно.

Проверьте, работает ли приведенный ниже код:

//for I := 0 to MDIChildCount do
for I := 0 to Screen.FormsCount-1 do
begin
  if Screen.Forms[I] is TFrmMessage then
  begin
     for M := 0 to QueryManager.Count-1
     ...
...