Перейти к содержанию
Fire Monkey от А до Я
  • 0

[XE7] [TEdit] [Отклонение] Не срабатывает событие OnClick у TEdit


d7d1cd

Вопрос

Привет всем.

 

Столкнулся то ли с багом XE7, то ли с не знанием. Проект FMX под Windows. На форме Edit1, создаю событие Edit1Click. При запуске приложения и щелчке на Edit1 событие Edit1Click не вызывается. В чем причина?

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

Если Edit1.Enable:=True, используй событие OnEnter.

У меня при щелчке на поле ввода, должно вызваться окно, в котором происходит ввод данных (делаю проект в стиле MetropolisUI для установки на планшет). Далее эти введенные данные заносятся в поле ввода, на котором был произведен щелчок. Если использовать Ваш совет, то окно ввода данных будет вызываться при занесении данных в "щелкаемое" поле ввода, а этого не должно быть. И почему не работает событие OnClick???

Ссылка на комментарий
  • 0

 

 

Ваш совет, то окно ввода данных будет вызываться при занесении данных в "щелкаемое" поле ввода, а этого не должно быть. И почему не работает событие OnClick???

Событие onEnter срабатывает один раз при получении фокуса, с чего вы взяли, что будет срабатывать каждый раз и какой каждый раз не понятно!

Почему не срабатывает OnClick мы не знаем, давайте код!!! Трасировку делали?

Ссылка на комментарий
  • 0

Прикладываю проект. При щелчке на поле ввода в событии OnEnter создается и вызывается другая форма, на которой тоже есть поле ввода. После закрытия второй формы, текст из ее поля ввода копируется в поле ввода первой формы. При попытке закрытия второй формы, она вызывается снова. Мне не понятно почему так происходит. В проекте на VCL все работает идеально. И OnClick работает, в отличие от FMX.

Test.zip

Ссылка на комментарий
  • 0

я проект даже смотреть не буду, вы прежде чем такие панические сообщения писать потрасируйте своё приложение.

Из вашего сообщения и так ясно в чём ошибка

 При щелчке на поле ввода в событии OnEnter создается и вызывается другая форма, на которой тоже есть поле ввода. После закрытия второй формы, текст из ее поля ввода копируется в поле ввода первой формы. При попытке закрытия второй формы, она вызывается снова

 

После закрытия вторйо формы в эдите опять срабатыает onEnter потому как он опять получает фокус. Да и советую уйти от реализации приложения в кучу форм делайте всё на одной форме... Вызывайте лайаут или ещё какойнить компонент...

Ссылка на комментарий
  • 0

Теперь ясно почему срабатывает повторный вызов второй формы. Спасибо. Но вопрос темы открыт: почему не вызывается событие OnClick? И параллельный вопрос: почему в проекте на VCL все работает как надо и повторного вызова второй формы не происходит (используется событие OnEnter)?

Ссылка на комментарий
  • 0

Я не силён в C++ Buildere, но на мой взгляд чото вы делаете не так) 

void Form2Execute(TEdit *Edit)
{
 Form2 = new TForm2(Application);
 Form2->ShowModal();
 Edit->Text = Form2->Edit1->Text;
 delete Form2;
}

Зачем? Разве нельзя написать в первой форме Form2->Show или ShowModal ?

Да и потом зачем тут delete Form2?

 

void __fastcall TForm1::Edit1Click(TObject *Sender)
{
 Form2Execute(Edit1);       // Этот код не вызывается при щелчке на Edit1!!!
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1Enter(TObject *Sender)
{
 Form2Execute(Edit1);
}

Вызов одинаковый, трасирутей, поставте брек поинты в этих процедурах, каков буде трезультат?

Ссылка на комментарий
  • 0

Первый код - это создание второй формы вручную, а не автоматически. Это экономит память, когда вторая форма не используется. delete - это оператор освобождения памяти, выделенной оператором new.

Трассировку делал. Брекпоинт на функции Edit1Click не срабатывает при клике на поле ввода.

P.S. На TLabel тоже не работает событие OnClick...

Ссылка на комментарий
  • 0

Что-то гуру FMX молчат... Неужели подобная ошибка только у меня? Если кому-то не сложно, проверьте у себя, работает ли событие OnClick у компонентов Edit и Label.

Ссылка на комментарий
  • 0
procedure TForm1.FormCreate(Sender: TObject);
begin
  label1.HitTest:=true;
end;
или сразу задать компоненту HitTest на true в PropertiesTLabel по-умолчанию HitTest на false стоит)
 
С TEdit так не прокатило (по-умолчанию на true стоит даже)
 
Добавлено позднее:
У TEdit OnMouseDown работает. Он подойдёт?
 
------------------------
 
О, у Вас C++ Builder, а я на Delphi писал. Ну я думаю адаптируете? Просто я на билдере не пишу, но если надо будет погляжу, думаю там достаточно просто, что скорее всего не надо будет)
Изменено пользователем Igor
Ссылка на комментарий
  • 0

С Label понял свою ошибку - свойство HitTest. С Edit понятно, что можно использовать события OnMouseDown, OnMouseUp. А если в приложении будет необходимость сделать прокручивание списка тех же Edit-ов? Тогда при прикосновении сразу вызовется OnMouseDown, а при окончании прокручивания и отпускании пальца вызовется OnMouseUp. Однако ни тот ни другой обработчик не должен вызываться.

Вопрос открыт: почему не работает событие OnClick?

Ссылка на комментарий
  • 0

Не знаю почему не пашет OnClick, по-моему баг/фича. Но не пойму чем не устраивает OnMouseDown или OnMouseUp. Поясните пожалуйста. Честно не могу сходу представить что-нибудь что нельзя нормально реализовать в OnMouseDown/OnMouseUp против OnClick.

 

Взять например глобальную переменную типа Boolean по-умолчанию значимую false, при OnMouseDown делать её true, при OnMouseUp проверять true ли она, и если да, то обрабатывать + ставить на false (на случай если нажал в одном месте, а отпустил на итеме). На вскидку предположу что я только что описал собственно OnClick как он есть (updt хотя всё таки судя по всему не совсем так) . Только что проверил с TLabel, при клике по нему происходят OnMouseDown, OnClick и OnMouseUp (в такой последовательности).

 

 

Добавлено позднее:

 

Вообще MouseDown и MouseUp даже интереснее с точки зрения разработчика в том числе и из-за:

Button: TMouseButton; Shift: TShiftState; X, Y: Single

которых нет у OnClick.

 

updt по поводу использования флажка boolean правда может быть ещё такой вариант: 1. делается Down на итеме, ставиться true 2. делается Up вне итема, true остаётся 3. делается Down вне итема 4. делается Up в итеме  - что приведёт с срабатыванию механизма, хотя действия были не правильные; но можно предусмотреть что-то типо, что если Up делается вне итема после Down на итеме, то true меняется на false, но хоть звучит это просто - сделать это в одном лишь Up'е формы будет недостаточно, придётся везде делать, на всех итемах кроме данного, и то может я не всего предусмотрел, но может быть и наоборот можно как-то проще сделать.

 

updt2 придумал ещё вариант, как мне казалось получше, рабочий) использовать событие OnExit для того чтобы избежать описанного выше глюка (в событии ставить флаг на false), вначале на Label протестил, работало хорошо, но с Edit не прокатило,  его OnExit работает иначе (с OnMouseLeave тоже не сработало, каретка ввода остаётся в TEdit, возможно в этом дело, хотя вероятно это тоже можно как-то обойти).

 

Есть правда у меня ещё одно предположение, пока всё это делал на XE7, надо проверить в XE6 Update 1 и XE7 Update 1, может там работает OnClick.

 

updt3 Ура OnClick на TEdit работает в XE6 Update 1, вероятно это баг XE7, XE7 Update 1 не имею, так что проверить на нём не могу, короче говоря либо делать в XE6 Update 1 (без апдейта не знаю как там) либо ставить Update 1 на XE7 и смотреть как там, если у Вас XE7 без апдейта, либо посмотреть Embarcaderoвские фиксы на офф сайте, может там правили.

 

P.S.: Единственный момент ещё, всё это проверял на Delphi, не знаю какая зависимость этих вещей от Delphi/С++ Builder.

Ссылка на комментарий
  • 0

На С++Builder XE7 Update 1 OnClick тоже не работает. Я скромно надеюсь, что на нашу тему уже обратит внимание Бровин Ярослав. Потому что изобрести костыль для решения проблемы можно почти всегда...

Ссылка на комментарий
  • 0
  • Администраторы

Добрый день,
 
Это ошибка, ее устранили в будущей новой версии среды. Для обхода проблемы в других версиях среды, нужно использовать следующий подход:

var
  StyledPresentation: TStyledControl;
begin
  StyledPresentation := nil;
  if Edit1.HasPresentationProxy then
    StyledPresentation := Edit1.PresentationProxy.Receiver as TStyledControl;
  if StyledPresentation <> nil then
    StyledPresentation.OnClick := Edit1Click; // <-- программно задать свой обработчик
end;

Код для С++ Builder:

void __fastcall TForm2::FormCreate(TObject *Sender)
{
	TStyledControl* styledPresentation;
	if (Edit1->HasPresentationProxy()) {
		styledPresentation = dynamic_cast<TStyledControl*>(Edit1->PresentationProxy->Receiver);
		styledPresentation->OnClick = Edit1Click; // <-- программно задать свой обработчик
	}
}
Ссылка на комментарий
  • 0

... задам вам тот же вопрос чем вас не устраивает OnEnter?

Я пишу приложение на планшет под Windows в стиле Metropolis. Для ввода текста я решил использовать свое диалоговое окно. Работать оно будет так: при нажатии пальцем на поле ввода, сверху экрана выпадет небольшое окно с полем ввода и кнопками ОК и Отмена, снизу экрана появится сенсорная клавиатура. Остальная часть экрана затемнится. После ввода текста и нажатия ОК, введенный текст будет вставлен в первоначальное поле ввода.

Таким образом, если использовать событие OnEnter, то окно ввода текста вызовется снова при нажатии ОК, так как поле ввода снова получит фокус (сами мне это объяснили). Понятно, что все это можно отследить. Просто событие OnClick подошло бы идеально.

Использование отдельного окна обосновано тем, что сенсорная клавиатура закрывает почти весь экран и зачастую не видно что ты вводишь в поле.

Ссылка на комментарий
  • 0

Ярослав, спасибо за решение. Интересная вещь получается: Embarcadero допустили ошибку и исправляют ее в следующей версии, а пользователи текущих версий должны использовать костыли? А почему не выпускается обновление, закрывающее ошибку? Тогда с уверенностью можно сказать, что ошибки делаются преднамеренно, потом выпускается новая версия без этой ошибки, но наверняка с другой. Новая версия - новая покупка. Так на исправлении одних ошибок можно делать деньги.

На семинаре по продуктам Embarcadero в Нижнем Новгороде программисты сетовали на то, что линейка средств разработки от Microsoft более продвигается. Я не использовал их средства, но судя по Windows могу предположить, что если бы в их продукте обнаружилась подобная ошибка, то они выпустили бы заплатку, а не новую версию среды. Думаю в этом есть своя доля причины успеха мелкомягких на поприще средств разработки.

P.S. Но может быть я не прав и все таки будет выпущен Update2...

Ссылка на комментарий
  • 0
  • Администраторы

Да, конечно, код для С++ Builder (При ControlType = Styled):

void __fastcall TForm2::FormCreate(TObject *Sender)
{
    TStyledControl* styledPresentation;
    if (Edit1->HasPresentationProxy()) {
	   styledPresentation = dynamic_cast<TStyledControl*>(Edit1->PresentationProxy->Receiver);
	   styledPresentation->OnClick = Edit1Click; // <-- программно задать свой обработчик
    }
}
Ссылка на комментарий
  • 0
  • Администраторы

d7d1cd,

  1. Вопросы касательно обновлений увы не в моей компетенции.
  2. На счет "преднамеренных ошибок" могу вас успокоить, это не так.
Ссылка на комментарий
  • 0

Ярослав, благодарю за код. И тут же вопрос. В этом коде назначается обработчик события OnClick для конкретного Edit-а. А как быть, если у меня их много? Надеюсь не для каждого прописывать приведенный Вами код?

Ссылка на комментарий
  • 0
  • Администраторы

Для каждого, где требуется OnClick. Чтобы облегчить работу, можно вынести мой код в отдельную процедуру типа 

SetEditOnClick(AEdit: TEdit; AOnClick: TNotifyEvent);

и ее вызывать для требуемых эдитов.

Ссылка на комментарий
  • 0

Ясно. Сейчас экспериментирую. Создал функцию с одним параметром типа TObject и назначил ее обработчиком события OnClick. При щелчке на Edit происходит вызов моей функции, однако в параметр этой функции передается не указатель Edit-a на котором был произведен щелчок, а что-то другое. Почему так происходит и как решить эту проблему?

Ссылка на комментарий
  • 0
  • Администраторы

Для Delphi:

var
  EditControl: TControl;
  SenderEdit: TEdit;
begin
  if Sender is TStyledEdit then
  begin
    EditControl := TStyledEdit(Sender).PresentedControl;
    SenderEdit := EditControl as TEdit;
  end;
end; 

Для C++ Builder

#include <FMX.Edit.Style.hpp>
TStyledEdit* styledEdit = dynamic_cast<TStyledEdit*>(Sender);
if (styledEdit) {
	TEdit* edit = dynamic_cast<TEdit*>(styledEdit->PresentedControl);
}

P.S. Но это только нужно для устранения этой проблемы. В исправленной версии это не понадобиться.

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...