Событие щелчка всплывающего меню delphi выполняется не только при щелчке мыши по элементу меню, но и после выполнения некоторой функции.

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

После этого нажмите кнопку 2.

Я ожидаю, что появится сообщение «Всплывающее окно процесса».

Но результат "Item1 Clicked!".

Что происходит и как я могу получить результат, который я ожидаю.

     //Popup Menu Item1 Click event handler
     procedure MyForm.Item1Click(Sender: TObject);
     begin
       FMsg := 'Item1 Clicked!';
     end;

     procedure MyForm.ProcessPopup(APoint: TPoint);
     begin
       PopupMenu1.Popup(APoint.X, APoint.Y);
       FMsg := 'Process Popup';
     end;

     procedure MyForm.Button1Click(Sender: TObject);
     begin
       ProcessPopup(Mouse.x, Mouse.Y);
     end;

     procedure MyForm.Button2Click(Sender: TObject);
     begin
       ShowMessage(FMsg);
     end;

person Jung honey Park    schedule 20.11.2014    source источник


Ответы (2)


Если бы вы установили несколько точек останова и использовали F8 для пошагового выполнения кода, вы бы увидели, что не так.

В любом случае причина, по которой отображается сообщение: «Item1 Clicked!» это потому, что в это время установлена ​​переменная FMsg.

Поток вашего кода выглядит следующим образом:

 //Popup Menu Item1 Click event handler
 procedure MyForm.Item1Click(Sender: TObject);
 begin
   FMsg := 'Item1 Clicked!'; //4. Called after you click on first popup item
 end;

 procedure MyForm.ProcessPopup(APoint: TPoint);
 begin
   PopupMenu1.Popup(APoint.X, APoint.Y); //2. This shows the popup menu
   FMsg := 'Process Popup'; //3. After that FMsg value is set to 'Process Popup'
 end;

 procedure MyForm.Button1Click(Sender: TObject);
 begin
   ProcessPopup(Mouse.x, Mouse.Y); //1. Called first when you ress the mouse button
 end;

 procedure MyForm.Button2Click(Sender: TObject);
 begin
   ShowMessage(FMsg); //5. Finally this is called on Buttom2 click
                      //At this time the value of FMsg is 'Item1 Clicked!' as it
                      //was set last in Item click event handler
 end;

ПРИМЕЧАНИЕ. Вызов «PopMenu1.Popup(APoint.X, APoint.Y)» не останавливает ваш код в ожидании, на какой элемент всплывающего окна вы нажмете. Я думаю, вы перепутали функциональность всплывающего меню с модальными формами (диалогами), где код действительно ожидает модального результата, возвращаемого из такой формы.

person SilverWarior    schedule 20.11.2014
comment
Спасибо за ваш ответ. Я постараюсь использовать модальную форму. - person Jung honey Park; 20.11.2014
comment
Я думаю, что ваше ПРИМЕЧАНИЕ не верно. PopupMenu запускает собственный цикл обработки сообщений и фактически останавливает код до тех пор, пока PopupMenu не будет закрыт. - person Tom Brunberg; 20.11.2014
comment
PopupMenu — это просто еще одно окно, порядок Z которого выше порядка Z форм, что означает, что PopupMenu сначала регистрируется в MouseClicks. Но отображение PopupMenu не блокирует выполнение другого кода. - person SilverWarior; 20.11.2014
comment
Таким образом, вы по-прежнему можете обновлять содержимое кода форм, например, с помощью Timer. Более того, если у вас установлено событие OnMove для форм, код в нем все равно будет выполняться, даже если в это время отображается ваше PopupMenu. - person SilverWarior; 20.11.2014
comment
@SilverWarior Поставьте точку останова на FMsg := 'Всплывающее окно процесса'; строку и убедитесь сами, что она не выполняется до закрытия всплывающего меню. - person Tom Brunberg; 20.11.2014
comment
События @SilverWarior TTimer обрабатываются, это правда. Что еще, например? - person Wolf; 20.01.2015

Происходит следующее: когда отображается всплывающее меню, оно запускает собственный цикл обработки сообщений. При щелчке элемента меню событие щелчка отправляется в очередь сообщений приложений. IOW, это не действует немедленно. Затем всплывающее меню закрывается, и выполнение продолжается с установкой FMsg на «Обработать всплывающее окно». Цикл сообщений приложения затем извлекает сообщение, которое было опубликовано щелчком меню, и впоследствии вызывает Item1Click, который назначает «Item1 clicked» для FMsg.

Как изменить Чтобы получить ожидаемый результат, вам придется вмешаться в обычную обработку сообщений, например, вызвав Application.ProcessMessages сразу после PopupMenu.Popup. Но я не рекомендую этого делать. Лучше переосмыслите свой дизайн.

person Tom Brunberg    schedule 20.11.2014
comment
calling Application.ProcessMessages Right after PopupMenu.Popup - Это ничего не изменит по указанной вами причине. Любой код после вызова TPopupMenu.Popup выполняется после завершения этого цикла отправленных событий (возврат к вызывающей стороне). - person Wolf; 20.01.2015
comment
@Wolf Почему бы тебе не попробовать. Я сделал. Поместите AP между PopupMenu1.Popup и FMsg := 'Process popup'; и убедитесь сами, что порядок назначений FMsg меняется, и, таким образом, FMsg содержит текст, который ожидал OP. - person Tom Brunberg; 20.01.2015
comment
Признаюсь, что мне следует более внимательно изучить этот вопрос, надеюсь, я сделаю это в ближайшее время. Но явный вызов Application.ProcessMessages постоянно тревожит меня, возможно, моя вина ;-) - person Wolf; 20.01.2015
comment
@Wolf A.P. также стоит на первом месте в моем списке вещей, которых следует избегать. Вот почему я сказал, что не рекомендую это в следующем предложении. - person Tom Brunberg; 20.01.2015