kvantum Опубликовано 19 января, 2015 Поделиться Опубликовано 19 января, 2015 (изменено) Здравствуйте ! Опираясь на тему "Архитектура приложения под Андроид на основе TFrame" был создан тестовый пример приложения на Андроид, в котором переключаемые фреймы создаются (удаляются) динамически. Суть ошибки: если в Frame1 ввести текст в строку и нажать кнопку перехода к Frame2 (правый верхний угол) - возникает ошибка. При уничтожении текущего фрейма клавиатура скрывается автоматически методом HideKeyboard : if Assigned(fCurrentFrame) then begin HideKeyboard; fCurrentFrame.DisposeOf; fCurrentFrame:=nil; HideButtonsLayouts; end; Прошу помочь в исправлении ошибки. Пример и скриншоты во вложении. AndroidFramesTest.zip Изменено 19 января, 2015 пользователем Brovin Yaroslav Отформатировано Цитата Ссылка на комментарий
Alexey Lovchikov Опубликовано 20 января, 2015 Поделиться Опубликовано 20 января, 2015 Как я понял проблема возникает если при удалении фрейма когда у одного из элементов ввода данных стоит фокус. Я решил эту проблему следующим способом. Моя функция может переключать на следующий фрейм двумя способами. Первый с очищением из памяти старого фрейм, второй без очистки, это удобно когда необходимо вызвать какой нибудь маленький фрейм и при этом, чтоб данные предыдущего фрейм не потерялись. Я например использую вызов фрейм настройки и обновление конфигурации вторым способом При переключении на новый фрейм я вначале делаю очистку активного фокуса текущего фрейм (необходимо если используется переключение без очистки предыдущего фрейм) и очистку фокуса старого фрейм при помощи процедуры ControlsResetFocus, ее тело описано ниже function TfmMain.ActiveFrame(AFrameClass: TFrameClass; ADisposePrevFrame: Boolean): TFrame; var AFrame: TFrame; AIdx: Integer; begin if FFrame <> nil then begin //Сбрасываем форкус элементов текущего активного фрейма ControlsResetFocus(FFrame); //Если новый фрейм отличается от текущего if FFrame.ClassType <> AFrameClass then //Ишем старые фреймы созданные от этого класса для очистки for AIdx := 0 to ComponentCount - 1 do begin if Components[AIdx].ClassType = AFrameClass then begin AFrame := TFrame(Components[AIdx]); //Сбрасываем форкус элементов старого фрейма ControlsResetFocus(AFrame); //Освобождаем старый фрейм из памяти AFrame.Parent := nil; AFrame.DisposeOf; AFrame := nil; Break; end; end; end; if ADisposePrevFrame then begin if FFrame <> nil then begin FFrame.DisposeOf; FFrame := nil; end; FFrame := AFrameClass.Create(Self); FFrame.Parent := Self; FFrame.Align := TAlignLayout.Client; Result := FFrame; end else begin Result := AFrameClass.Create(Self); Result.Parent := Self; Result.Align := TAlignLayout.Client; end; mvMenu.HideMaster; Application.ProcessMessages; end; unit uFunctions; interface uses FMX.Controls, FMX.Edit; procedure KeyboardHide; procedure KeyboardShow(AEdit: TEdit); procedure ControlsResetFocus(Control: TControl); implementation uses FMX.Platform, FMX.VirtualKeyboard; procedure KeyboardHide; var KeyboardService: IFMXVirtualKeyboardService; begin // Запрашиваем сервис виртуальной клавиатуры if TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(KeyboardService)) then KeyboardService.HideVirtualKeyboard; end; procedure KeyboardShow(AEdit: TEdit); var KeyboardService: IFMXVirtualKeyboardService; begin // Запрашиваем сервис виртуальной клавиатуры if TPlatformServices.Current.SupportsPlatformService(IFMXVirtualKeyboardService, IInterface(KeyboardService)) then KeyboardService.ShowVirtualKeyboard(AEdit); end; procedure ControlsResetFocus(Control: TControl); procedure ResetFocus(SubControl: TControl); var AIdx: Integer; AControl: TControl; begin for AIdx := 0 to SubControl.ChildrenCount - 1 do if SubControl.Children.Items[AIdx] is TControl then begin AControl := SubControl.Children.Items[AIdx] as TControl; AControl.ResetFocus; if AControl.ChildrenCount > 0 then ResetFocus(AControl); end; SubControl.ResetFocus; end; begin KeyboardHide; ResetFocus(Control); end; end. Ниже приведен код очистки фреймов "Настройка" и "Обновление конфигурации" из памяти Настройка procedure TfrOptions.SaveClick(Sender: TObject); begin with fmMain do begin Options.UrlServer := edUrlServer.Text; Options.Save; ControlsResetFocus(Self); Self.Parent := nil; Self.DisposeOf; end; end; Обновление конфигурации procedure TfrLogin.StartUpdateCfgClick(Sender: TObject); var AFrame: TfrUpdateCfg; AStatus: TfrUpdateCfgStatus; begin with dmMainModule, fmMain do begin AStatus := ucsEndNormal; if InetConnectState then begin AFrame := TfrUpdateCfg(ActiveFrame(TfrUpdateCfg, False)); AStatus := AFrame.Start; ControlsResetFocus(AFrame); AFrame.Parent := nil; AFrame.DisposeOf; AFrame := nil; end; .... Цитата Ссылка на комментарий
Модераторы Andrey Efimov Опубликовано 20 января, 2015 Модераторы Поделиться Опубликовано 20 января, 2015 Вот, давно уже отрапортовал об этом поведении http://qc.embarcadero.com/wc/qcmain.aspx?d=127108 Цитата Ссылка на комментарий
kvantum Опубликовано 20 января, 2015 Автор Поделиться Опубликовано 20 января, 2015 Спасибо большое ! Цитата Ссылка на комментарий
Alexey Lovchikov Опубликовано 20 января, 2015 Поделиться Опубликовано 20 января, 2015 Рад помочь Цитата Ссылка на комментарий
kvantum Опубликовано 20 января, 2015 Автор Поделиться Опубликовано 20 января, 2015 Рад помочь Алексей, к сожалению ошибка осталась. Посмотрите пожалуйста код...AndroidFramesTest.zip Цитата Ссылка на комментарий
kvantum Опубликовано 20 января, 2015 Автор Поделиться Опубликовано 20 января, 2015 Вот, давно уже отрапортовал об этом поведении http://qc.embarcadero.com/wc/qcmain.aspx?d=127108 Embarcadero сообщило о каком-нибудь решении ? Цитата Ссылка на комментарий
Модераторы Andrey Efimov Опубликовано 21 января, 2015 Модераторы Поделиться Опубликовано 21 января, 2015 Вот, давно уже отрапортовал об этом поведении http://qc.embarcadero.com/wc/qcmain.aspx?d=127108 Embarcadero сообщило о каком-нибудь решении ? Нет, к сожалению, решения пока нет, иначе оно было бы по ссылке или в Update 1 для XE7, может в XE8… Цитата Ссылка на комментарий
Alexey Lovchikov Опубликовано 21 января, 2015 Поделиться Опубликовано 21 января, 2015 Подправил твою программу procedure ControlsResetFocus(Control: TControl); procedure ResetFocus(SubControl: TControl); var AIdx: Integer; AControl: TControl; begin for AIdx := 0 to SubControl.ChildrenCount - 1 do if SubControl.Children.Items[AIdx] is TControl then begin AControl := SubControl.Children.Items[AIdx] as TControl; AControl.ResetFocus; if AControl.ChildrenCount > 0 then ResetFocus(AControl); end; SubControl.ResetFocus; end; begin KeyboardHide; if Control <> nil then ResetFocus(Control); end; добавил проверку на nil в процедуре ControlsResetFocus if Control <> nil then ResetFocus(Control); Хотя, все равно через раз появляется ошибка Нужно ждать фикс Цитата Ссылка на комментарий
kvantum Опубликовано 21 января, 2015 Автор Поделиться Опубликовано 21 января, 2015 (изменено) Нужно ждать фикс Ну ... фикс ! Когда он будет ? Нужно ведь сейчас писать... Что если заменить TFrame формой TForm, что думаешь ? Вопрос задан здесь: http://fire-monkey.ru/topic/914-android-tform-ili-tframe/ Изменено 21 января, 2015 пользователем Andrey Yefimov поправил ссылку Цитата Ссылка на комментарий
Alexey Lovchikov Опубликовано 21 января, 2015 Поделиться Опубликовано 21 января, 2015 Мне по любому нужно эту ошибку обойти каким нибудь способом. Если я решу эту проблему сразу отпишусь Проверь у себя я определил константу FrameOrder которая отвечает за порядок переключения фреймов const FrameOrder: array[0..2] of TFrameClass = (TframeRegUser, TframeSetUser, TframeAuthUser); На кнопки далее и назад procedure TfrmMain.SpeedButton1Click(Sender: TObject); begin SetFrame(IfThen(fCurrentFrameIndex = 0, 2, fCurrentFrameIndex - 1)); end; procedure TfrmMain.SpeedButton2Click(Sender: TObject); begin SetFrame(IfThen(fCurrentFrameIndex = 2, 0, fCurrentFrameIndex + 1)); end; Изменил SetFrame, добавил пример получения данных с фрейм по одному имени стиля, то есть в хедер main формы передаю значение с lable фрейма procedure TfrmMain.SetFrame(AFrameIndex: Integer); var ALbl: TLabel; begin fCurrentFrameIndex := AFrameIndex; ALbl := TLabel(ActiveFrame(FrameOrder[fCurrentFrameIndex], true).FindStyleResource('description')); if ALbl <> nil then lbHeaderText.Text := ALbl.Text; end; изменил ControlsResetFocus, убрал скрытие клавиатуры procedure ControlsResetFocus(Control: TControl); procedure ResetFocus(SubControl: TControl); var AIdx: Integer; AControl: TControl; begin for AIdx := 0 to SubControl.ChildrenCount - 1 do if SubControl.Children.Items[AIdx] is TControl then begin AControl := SubControl.Children.Items[AIdx] as TControl; AControl.ResetFocus; if AControl.ChildrenCount > 0 then ResetFocus(AControl); end; SubControl.ResetFocus; end; begin ResetFocus(Control); end; AndroidFramesTest.zip Цитата Ссылка на комментарий
Кривяков Виталий Опубликовано 26 января, 2015 Поделиться Опубликовано 26 января, 2015 Добрый день! Судя по всему - проблема достаточно серьезная и исправить ее нелегко. Для примера - можно убрать сообщение об ошибке "Access violation..." для этого достаточно указать модификатор [weak] переменной vActiveCaret в модуле FMX.Types. было var vKBTimer: TTimer = nil; vActiveCaret: TCustomCaret = nil; vOldDisplayed: boolean = False; vShowVKProc: TShowVirtualKeyboard = nil; стало var vKBTimer: TTimer = nil; [weak] vActiveCaret: TCustomCaret = nil; vOldDisplayed: boolean = False; vShowVKProc: TShowVirtualKeyboard = nil; В ней залипает объект TCaret при уничтожении фрейма. Но далее происходят другие чудеса, причем, под iOS и Android чудеса разные. Судя по всему, хоть Ярослав и рекомендует динамическое создание фреймов, платформа на это пока неспособна. Для себя остановился на динамическом создании фреймов и их повторное использование, вместо уничтожения и последующего создания по необходимости. Цитата Ссылка на комментарий
ruslan Опубликовано 26 января, 2015 Поделиться Опубликовано 26 января, 2015 платформа пока много на что неспособна. и это печально боюсь если в хе8-9 ничего конкретно не исправят, придется менять fmx, а вместе с ним и Delphi, на что-то проверенное и надежное... а то как-то поднадоело искать баги, править исходники и ждать "манны небесной"... aleksandrguru 1 Цитата Ссылка на комментарий
xenon54 Опубликовано 26 января, 2015 Поделиться Опубликовано 26 января, 2015 Они вон чего изобрели. Цена, цена вменяемая... Цитата Ссылка на комментарий
aleksandrguru Опубликовано 28 января, 2015 Поделиться Опубликовано 28 января, 2015 тоже самое в другой обложке там все тоже самое и ошибки тоже Цитата Ссылка на комментарий
xenon54 Опубликовано 28 января, 2015 Поделиться Опубликовано 28 января, 2015 Дык понятное дело. Там просто VCL вырезали. Но разница в цене колоссальная. Цитата Ссылка на комментарий
Рекомендуемые сообщения
Присоединяйтесь к обсуждению
Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.