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

Belov.V.

Пользователи
  • Постов

    69
  • Зарегистрирован

  • Посещение

  • Победитель дней

    6

Активность репутации

  1. Like
    Belov.V. получил реакцию от Rusland в После активации TSearchBox не возвращается индекс нового добавленого элемента   
    Готового решения на просторах интернета не нашел. То, что напридумывал сам, оформил в виде хелпера к TListBox. Может кому пригодится.
    Реализовал только необходимые мне методы. И только для режима MultiSelectStyle=None
    Самое главное, что так индекс возвращается корректно.
    unit ListBoxHelper; interface uses FMX.Controls, FMX.Types, System.SysUtils, FMX.ListBox, FMX.SearchBox; // Создаем Helper для класса TListBox type TListBoxHelper = class helper for TListBox function ResetFilter : string; // возвращает старый фильтр function GetSearchBox : TSearchBox; // возвращает SearchBox function AddAndClearSelect(const S : string) : integer; // добавить, ничего не выбирать, фильтр очистить function AddAndSelect(const S : string) : integer; // добавить, выбрать, фильтр очистить function AddAndSaveOldSelect(const S : string) : integer; // добавить, сохранить выбор, фильтр очистить function AddAndSaveOldView(const S : string) : integer; // добавить, сохранить выбор и фильтр, вернуть номер добавленного в отфильтрованном списке, или -1 если не попадает в фильтр procedure DeleteItem(const i : integer = -1); // удалить по индексу. если индекс не указан то удалить выбранный end; implementation function TListBoxHelper.GetSearchBox : TSearchBox; var Child : TControl; FxmChild : TFmxObject; begin Result := nil; for Child in self.Controls do for FxmChild in Child.Controls do if FxmChild is TSearchBox then Exit( TSearchBox( FxmChild ) ); end; function TListBoxHelper.ResetFilter : string; var s : TListBoxItem; sb : TSearchBox; begin Result := EmptyStr; s := Selected; sb := GetSearchBox; if Assigned( sb ) then begin Result := sb.Text; sb.Text := EmptyStr; end; if Assigned( FilterPredicate ) then FilterPredicate := nil; if Assigned( s ) then ItemIndex := s.Index; end; function TListBoxHelper.AddAndClearSelect(const S : string) : integer; begin ClearSelection; ResetFilter; Result := Items.Add( s ); end; function TListBoxHelper.AddAndSelect(const S : string) : integer; begin Result := AddAndClearSelect( s ); if Result <> -1 then ItemIndex := Result; end; function TListBoxHelper.AddAndSaveOldSelect(const S : string) : integer; var sel : TListBoxItem; begin sel := Selected; Result := AddAndClearSelect( s ); if Assigned( sel ) then ItemIndex := sel.Index end; function TListBoxHelper.AddAndSaveOldView(const S : string) : integer; var sb : TSearchBox; iSel, iNew : TListBoxItem; flt : string; begin iSel := Selected; iNew := nil; ClearSelection; sb := GetSearchBox; flt := ResetFilter; // Result := Items.Add( s ); if Result <> -1 then iNew := ItemByIndex( Result ); // if flt <> EmptyStr then begin sb.Text := flt; if Assigned( iNew ) then Result := iNew.Index; end; if Assigned( iSel ) then ItemIndex := iSel.Index; end; procedure TListBoxHelper.DeleteItem(const i : integer = -1); var sb : TSearchBox; flt : string; iSel, iDel : TListBoxItem; begin if i > Count-1 then Exit; sb := GetSearchBox; if i > -1 then begin iSel := Selected; iDel := ItemByIndex( i ); end else begin iSel := nil; iDel := Selected; end; flt := ResetFilter; if Assigned( iDel ) then Items.Delete( iDel.Index ); // if flt <> EmptyStr then sb.Text := flt; if Assigned( iSel ) then ItemIndex := iSel.Index; end; end. Еще на XE7 есть глюк в режиме Sorted := True, при добавить одинаковые значения (или несколько одинаковых) и сразу выделении одного через IntemIndex.
    Но пока на выявление закономерностей и борьбу нет времени.
    ListBoxHelper.zip
  2. Like
    Belov.V. получил реакцию от Alex7wrt в Ошибка после закрытия приложения Android   
    MainActivity.finish; или SharedActivity.finish;
     
    Вот тут обсуждали: http://fire-monkey.ru/topic/1121-problema-pri-vykhode-iz-programmy/?p=5189
  3. Like
    Belov.V. получил реакцию от Alex7wrt в Кодировки языков в Android   
    Еще под андроид вот это можно использовать:
     
    System.SysUtils.SysLocale.DefaultLCID  // для Рус=ru_RU
  4. Like
    Belov.V. отреагировална Brovin Yaroslav в [iOS] Приложение запускается на iOS Simulator и тут же закрывается.   
    В большинстве случаев эта ошибка связана:
    С линковкой проекта с устаревшей версии SDK. То есть у вас в среде старые хедеры от iOS SDK. Этот случай обычно возникает при обновлении XCode.  С PAServer. Лечится перезапуском OSX или PAServer (с убиением всех дочерних процессов) С новыми требованиями Apple к формируемым файлам в пакете приложения. Entitlements. Тут нужно искать в официальных блогах статьи о том, как подправить этот файл для деплоя. Обычно касается старых версий среды и новых iOS SDK. С неправильной установкой XCode. При установки новой версии XCode может слететь активный путь, указывающий местонахождение текущей версии XCode. Проверить можно вызвав в консоле:
    xcode-select -p
  5. Like
    Belov.V. получил реакцию от HarrisNuh в После активации TSearchBox не возвращается индекс нового добавленого элемента   
    Столкнулся с такой ситуацией.   1) Заполняем TListBox; 2) Пользуемся поиском через TSearchBox; 3) Очищаем TSearchBox; 4) При попытке добавить любой новый элемент в TListBox, всегда возвращается индекс добавленного элемента "-1".   Накидал пример для экспериментов, упростив до безобразия (прикрепляю).   Как восстановить возможность получать индекс добавленного элемента?  
    Project1.zip
  6. Like
    Belov.V. отреагировална DirtyBorov в [TRESTRequest] Лучшая практика, когда нужно отправить несколько запросов через RESTRequest   
    По каким то причинам мне не удается прикрепить файл содержащий TWaitControl. Потому просто выложу его код полностью. Благо он совсем короткий. 
    Модуль универсальный. Его можно использовать не только для REST но и вообще для любых длительных операций которые нужно выполнять в потоках.
     
    Обратите внимание, что в конструктор передается TForm. Это экземпляр ГЛАВНОЙ формы приложения.  Это нужно потому что TWaitControl , будет перекрывать главную форму полупрозрачным квадратом, создавая эффект затемнения и заодно делая недоступным разные кнопки на форме.  Рекомендую создавать TWaitControl в событии OnCreate главной формы:
    TMainForm = class(TForm) private Wait: TWaitControl; end; procedure TMainForm.FormCreate(Sender: TObject); begin Application.OnException := OnException; Wait := TWaitControl.Create(Self); Wait.Title.Text := 'Ждите пожалуйста...'; end; unit Wait.Control; interface uses FMX.Forms, FMX.Objects, FMX.Types, FMX.Effects, FMX.StdCtrls, System.SysUtils, System.Classes, System.UITypes; type TWaitControl = class(TRectangle) private FWindow: TRectangle; FTitle: TLabel; FHadErrors: Boolean; FWaiting: Boolean; procedure DoErrorHandling(E: Exception; AOnError: TProc<TWaitControl, Exception>); procedure DoOnCompleted(AOnComplete: TProc<TWaitControl>); public constructor Create(MainForm: TForm); reintroduce; procedure Run(ATask: TProc<TWaitControl>; AOnComplete: TProc<TWaitControl> = nil; AOnError: TProc<TWaitControl, Exception> = nil); virtual; property Waiting: Boolean read FWaiting; property HadErrors: Boolean read FHadErrors; property Window: TRectangle read FWindow; property Title: TLabel read FTitle; end; implementation { TWaitControl } constructor TWaitControl.Create(MainForm: TForm); begin inherited Create(MainForm); Parent := MainForm; Align := TAlignLayout.Contents; Visible := False; Fill.Color := $4B000000; FWindow := TRectangle.Create(Self); FWindow.Parent := Self; FWindow.Fill.Color := $96000000; FWindow.Align := TAlignLayout.Center; FWindow.Width := 250; FWindow.Height := 65; FTitle := TLabel.Create(FWindow); FTitle.Parent := FWindow; FTitle.Align := TAlignLayout.Client; FTitle.StyledSettings := FTitle.StyledSettings - [TStyledSetting.Size, TStyledSetting.Style]; FTitle.TextSettings.Font.Size := 16; // FTitle.TextSettings.Font.Style := [TFontStyle.fsBold]; with TAniIndicator.Create(FWindow) do begin Parent := FWindow; Style := TAniIndicatorStyle.Circular; Align := TAlignLayout.Left; Margins.Left := 15; Margins.Top := 15; Margins.Right := 15; Margins.Bottom := 15; Width := Height; Enabled := True; end; with TShadowEffect.Create(FWindow) do Parent := FWindow; end; procedure TWaitControl.DoErrorHandling(E: Exception; AOnError: TProc<TWaitControl, Exception>); begin TThread.Synchronize(TThread.CurrentThread, procedure begin FWaiting := False; FHadErrors := True; Visible := False; if Assigned(AOnError) then AOnError(Self, E); end); end; procedure TWaitControl.DoOnCompleted(AOnComplete: TProc<TWaitControl>); begin TThread.Synchronize(nil, procedure begin FWaiting := False; Visible := False; if Assigned(AOnComplete) then AOnComplete(Self); end); end; procedure TWaitControl.Run; begin Visible := True; FWaiting := True; TThread.CreateAnonymousThread( procedure begin try FHadErrors := False; ATask(Self); DoOnCompleted(AOnComplete); except on E:Exception do DoErrorHandling(E, AOnError); end; // DoOnCompleted(AOnComplete); end).Start; end; end.
  7. Like
    Belov.V. отреагировална xenon54 в Как работает TImageList c TButton ?   
    Да как будто остальные кросс-платформенные студии разработки все такие прям пушистые, говна про всех навалом. Просто всегда кажется, что у других лучше чем у тебя...
    Ну и все таки она не наша
  8. Like
    Belov.V. отреагировална Brovin Yaroslav в Как работает TImageList c TButton ?   
    Автор TImageList'а вернется с отпуска после майских праздником, и я его попрошу вам ответить.
  9. Like
    Belov.V. получил реакцию от Евгений Корепов в После активации TSearchBox не возвращается индекс нового добавленого элемента   
    Готового решения на просторах интернета не нашел. То, что напридумывал сам, оформил в виде хелпера к TListBox. Может кому пригодится.
    Реализовал только необходимые мне методы. И только для режима MultiSelectStyle=None
    Самое главное, что так индекс возвращается корректно.
    unit ListBoxHelper; interface uses FMX.Controls, FMX.Types, System.SysUtils, FMX.ListBox, FMX.SearchBox; // Создаем Helper для класса TListBox type TListBoxHelper = class helper for TListBox function ResetFilter : string; // возвращает старый фильтр function GetSearchBox : TSearchBox; // возвращает SearchBox function AddAndClearSelect(const S : string) : integer; // добавить, ничего не выбирать, фильтр очистить function AddAndSelect(const S : string) : integer; // добавить, выбрать, фильтр очистить function AddAndSaveOldSelect(const S : string) : integer; // добавить, сохранить выбор, фильтр очистить function AddAndSaveOldView(const S : string) : integer; // добавить, сохранить выбор и фильтр, вернуть номер добавленного в отфильтрованном списке, или -1 если не попадает в фильтр procedure DeleteItem(const i : integer = -1); // удалить по индексу. если индекс не указан то удалить выбранный end; implementation function TListBoxHelper.GetSearchBox : TSearchBox; var Child : TControl; FxmChild : TFmxObject; begin Result := nil; for Child in self.Controls do for FxmChild in Child.Controls do if FxmChild is TSearchBox then Exit( TSearchBox( FxmChild ) ); end; function TListBoxHelper.ResetFilter : string; var s : TListBoxItem; sb : TSearchBox; begin Result := EmptyStr; s := Selected; sb := GetSearchBox; if Assigned( sb ) then begin Result := sb.Text; sb.Text := EmptyStr; end; if Assigned( FilterPredicate ) then FilterPredicate := nil; if Assigned( s ) then ItemIndex := s.Index; end; function TListBoxHelper.AddAndClearSelect(const S : string) : integer; begin ClearSelection; ResetFilter; Result := Items.Add( s ); end; function TListBoxHelper.AddAndSelect(const S : string) : integer; begin Result := AddAndClearSelect( s ); if Result <> -1 then ItemIndex := Result; end; function TListBoxHelper.AddAndSaveOldSelect(const S : string) : integer; var sel : TListBoxItem; begin sel := Selected; Result := AddAndClearSelect( s ); if Assigned( sel ) then ItemIndex := sel.Index end; function TListBoxHelper.AddAndSaveOldView(const S : string) : integer; var sb : TSearchBox; iSel, iNew : TListBoxItem; flt : string; begin iSel := Selected; iNew := nil; ClearSelection; sb := GetSearchBox; flt := ResetFilter; // Result := Items.Add( s ); if Result <> -1 then iNew := ItemByIndex( Result ); // if flt <> EmptyStr then begin sb.Text := flt; if Assigned( iNew ) then Result := iNew.Index; end; if Assigned( iSel ) then ItemIndex := iSel.Index; end; procedure TListBoxHelper.DeleteItem(const i : integer = -1); var sb : TSearchBox; flt : string; iSel, iDel : TListBoxItem; begin if i > Count-1 then Exit; sb := GetSearchBox; if i > -1 then begin iSel := Selected; iDel := ItemByIndex( i ); end else begin iSel := nil; iDel := Selected; end; flt := ResetFilter; if Assigned( iDel ) then Items.Delete( iDel.Index ); // if flt <> EmptyStr then sb.Text := flt; if Assigned( iSel ) then ItemIndex := iSel.Index; end; end. Еще на XE7 есть глюк в режиме Sorted := True, при добавить одинаковые значения (или несколько одинаковых) и сразу выделении одного через IntemIndex.
    Но пока на выявление закономерностей и борьбу нет времени.
    ListBoxHelper.zip
  10. Like
    Belov.V. получил реакцию от xenon54 в После активации TSearchBox не возвращается индекс нового добавленого элемента   
    Готового решения на просторах интернета не нашел. То, что напридумывал сам, оформил в виде хелпера к TListBox. Может кому пригодится.
    Реализовал только необходимые мне методы. И только для режима MultiSelectStyle=None
    Самое главное, что так индекс возвращается корректно.
    unit ListBoxHelper; interface uses FMX.Controls, FMX.Types, System.SysUtils, FMX.ListBox, FMX.SearchBox; // Создаем Helper для класса TListBox type TListBoxHelper = class helper for TListBox function ResetFilter : string; // возвращает старый фильтр function GetSearchBox : TSearchBox; // возвращает SearchBox function AddAndClearSelect(const S : string) : integer; // добавить, ничего не выбирать, фильтр очистить function AddAndSelect(const S : string) : integer; // добавить, выбрать, фильтр очистить function AddAndSaveOldSelect(const S : string) : integer; // добавить, сохранить выбор, фильтр очистить function AddAndSaveOldView(const S : string) : integer; // добавить, сохранить выбор и фильтр, вернуть номер добавленного в отфильтрованном списке, или -1 если не попадает в фильтр procedure DeleteItem(const i : integer = -1); // удалить по индексу. если индекс не указан то удалить выбранный end; implementation function TListBoxHelper.GetSearchBox : TSearchBox; var Child : TControl; FxmChild : TFmxObject; begin Result := nil; for Child in self.Controls do for FxmChild in Child.Controls do if FxmChild is TSearchBox then Exit( TSearchBox( FxmChild ) ); end; function TListBoxHelper.ResetFilter : string; var s : TListBoxItem; sb : TSearchBox; begin Result := EmptyStr; s := Selected; sb := GetSearchBox; if Assigned( sb ) then begin Result := sb.Text; sb.Text := EmptyStr; end; if Assigned( FilterPredicate ) then FilterPredicate := nil; if Assigned( s ) then ItemIndex := s.Index; end; function TListBoxHelper.AddAndClearSelect(const S : string) : integer; begin ClearSelection; ResetFilter; Result := Items.Add( s ); end; function TListBoxHelper.AddAndSelect(const S : string) : integer; begin Result := AddAndClearSelect( s ); if Result <> -1 then ItemIndex := Result; end; function TListBoxHelper.AddAndSaveOldSelect(const S : string) : integer; var sel : TListBoxItem; begin sel := Selected; Result := AddAndClearSelect( s ); if Assigned( sel ) then ItemIndex := sel.Index end; function TListBoxHelper.AddAndSaveOldView(const S : string) : integer; var sb : TSearchBox; iSel, iNew : TListBoxItem; flt : string; begin iSel := Selected; iNew := nil; ClearSelection; sb := GetSearchBox; flt := ResetFilter; // Result := Items.Add( s ); if Result <> -1 then iNew := ItemByIndex( Result ); // if flt <> EmptyStr then begin sb.Text := flt; if Assigned( iNew ) then Result := iNew.Index; end; if Assigned( iSel ) then ItemIndex := iSel.Index; end; procedure TListBoxHelper.DeleteItem(const i : integer = -1); var sb : TSearchBox; flt : string; iSel, iDel : TListBoxItem; begin if i > Count-1 then Exit; sb := GetSearchBox; if i > -1 then begin iSel := Selected; iDel := ItemByIndex( i ); end else begin iSel := nil; iDel := Selected; end; flt := ResetFilter; if Assigned( iDel ) then Items.Delete( iDel.Index ); // if flt <> EmptyStr then sb.Text := flt; if Assigned( iSel ) then ItemIndex := iSel.Index; end; end. Еще на XE7 есть глюк в режиме Sorted := True, при добавить одинаковые значения (или несколько одинаковых) и сразу выделении одного через IntemIndex.
    Но пока на выявление закономерностей и борьбу нет времени.
    ListBoxHelper.zip
  11. Like
    Belov.V. получил реакцию от sviat9440 в [Android] Возврат к предыдущей открытой форме по нажатию на кнопку Назад (Back)   
    Если на Андроиде в приложении Вы создаете новые формы ''newForm.Show" или newForm.ShowModal(procedure( ...., то кнопка "Назад" по умолчанию перемещает обратно между формами.
     
    Может быть имелось ввиду создание обработчика более сложного поведения внутри формы? В таком случае, при нажатии кнопки "Назад" (а так же "Menu") на форме срабатывает событие onKeyUp.Там-то и можно организовать обработку поведения:
    procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); begin ... // Обработка аппаратной клавиши "Back" if Key = vkHardwareBack then begin //ваш обработчик поведения .... Key := 0; // отмена стандартного действия
  12. Like
    Belov.V. получил реакцию от Kitty в Проблема при выходе из программы   
    MainActivity()->finish() или SharedActivity()->finish() должны выгружать приложение полностью (MainActivity.finish; - корневая активити, а SharedActivity.finish - ... пока к сожалению тоже только корневая).
     
    То, что Вы видите приложение в списке не значит, что оно загружено. Это список загруженных ранее, а не находящихся в памяти. К примеру, чтобы в списке не оставался, есть ключ для файла манифеста android:noHistory="false".
  13. Like
    Belov.V. получил реакцию от maxfad в Связь ListBox и SQLite. (Подобие справочника)   
    Вообще, дружеский совет :-)
    Почитайте про базы данных. В частности про язык SQL. Если в дальнейшем планируете писать программы с использованием  баз данных, в том числе и легких типа SQLite, узнаете много полезного. Про составные запросы и вьюхи. Правильно спроектированная структура таблиц, индексов, констрейнов и т.д. позволяет базе данных  жить "своей правильной жизнью". На тот же SQLite можно переложить часть заботы по поддержке целостности логической структуры. И код в итоге упрощается.
    Удачи!
  14. Like
    Belov.V. получил реакцию от Brovin Yaroslav в [Android] Возврат к предыдущей открытой форме по нажатию на кнопку Назад (Back)   
    В первом сообщении писал, что если 'новые формы ''newForm.Show" или newForm.ShowModal"...'
     
    Тогда да, только в обработчике нажатия клавиши анализировать состояние форм.
     
    Но по моему мнению (не для спора), Form1.Visible:=false; Form2.Visible:=true; не лучший стиль программирования. Для андроида в плане экономии ресурсов есть смысл создавать/убивать формы динамически. А если у Вас всего лишь панели интерфейса пользователя, и которые активно используются, то есть другие способы их отображения. Но все равно потребуется писать обработчик. Если без, то смотрите решение выше...
  15. Like
    Belov.V. получил реакцию от Brovin Yaroslav в [Android] Возврат к предыдущей открытой форме по нажатию на кнопку Назад (Back)   
    Если на Андроиде в приложении Вы создаете новые формы ''newForm.Show" или newForm.ShowModal(procedure( ...., то кнопка "Назад" по умолчанию перемещает обратно между формами.
     
    Может быть имелось ввиду создание обработчика более сложного поведения внутри формы? В таком случае, при нажатии кнопки "Назад" (а так же "Menu") на форме срабатывает событие onKeyUp.Там-то и можно организовать обработку поведения:
    procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); begin ... // Обработка аппаратной клавиши "Back" if Key = vkHardwareBack then begin //ваш обработчик поведения .... Key := 0; // отмена стандартного действия
  16. Like
    Belov.V. получил реакцию от xenon54 в [Android] Возврат к предыдущей открытой форме по нажатию на кнопку Назад (Back)   
    Если на Андроиде в приложении Вы создаете новые формы ''newForm.Show" или newForm.ShowModal(procedure( ...., то кнопка "Назад" по умолчанию перемещает обратно между формами.
     
    Может быть имелось ввиду создание обработчика более сложного поведения внутри формы? В таком случае, при нажатии кнопки "Назад" (а так же "Menu") на форме срабатывает событие onKeyUp.Там-то и можно организовать обработку поведения:
    procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState); begin ... // Обработка аппаратной клавиши "Back" if Key = vkHardwareBack then begin //ваш обработчик поведения .... Key := 0; // отмена стандартного действия
  17. Like
    Belov.V. отреагировална Satellite в [Android] При попытке отправить письмо через стандартное приложение, не передаётся EXTRA_EMAIL (Intent)   
    Разобрался, в общем только так передаётся нормально:
    procedure TfmSettings.CreateEmail(Const Recipient, Subject: string); var Intent: JIntent; JRecipient: TJavaObjectArray<JString>; begin JRecipient := TJavaObjectArray<JString>.Create(1); JRecipient.Items[0] := StringToJString(Recipient); Intent := TJIntent.Create; Intent.setAction(TJIntent.JavaClass.ACTION_SEND); Intent.setFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK); Intent.putExtra(TJIntent.JavaClass.EXTRA_EMAIL, JRecipient); Intent.putExtra(TJIntent.JavaClass.EXTRA_SUBJECT, StringToJString(Subject)); Intent.setType(StringToJString('vnd.android.cursor.dir/email')); SharedActivity.startActivity(Intent); end;
  18. Like
    Belov.V. отреагировална zonik в [Android] Обработка приложением неявного намерения (Intent)   
    Для получения «content» я сделал так
     

    var Intent: JIntent; Uri: Jnet_Uri; INStream: JInputStream; OUTStream: JOutputStream; outputfile: string; FFF: JFile; NumRead, NumWritten: Longint; Buffer: TJavaArray<Byte>; begin ... Intent := SharedActivity.getIntent; if (Pos('image/', JStringToString(Intent.getType))>0) or (Pos('audio/', JStringToString(Intent.getType))>0) or (Pos('video/', JStringToString(Intent.getType))>0) or (Pos('application/', JStringToString(Intent.getType))>0) or ('*/*' = JStringToString(Intent.getType)) then begin if JStringToString(Intent.getType) <> '' then begin Parcel := Intent.getParcelableExtra(TJIntent.JavaClass.EXTRA_STREAM); Uri := TJnet_Uri.Wrap(Parcel); if JStringToString(Uri.getScheme) = 'content' then begin if Pos('/mpeg', JStringToString(Intent.getType)) > 0 then outputfile := 'my.mp3' else if Pos('/jpeg', JStringToString(Intent.getType)) > 0 then outputfile := 'my.jpg' else outputfile := 'my.' + copy(JStringToString(Intent.getType), Pos('/', JStringToString(Intent.getType))+1, Length(JStringToString(Intent.getType)));//выдергиваем имя типа для того чтобы сделать его расширением //на случай если в Intent не уточнен тип, а указана *, например image/* if Pos('.*', outputfile) > 0 then outputfile := StringReplace(outputfile, '.*', '.tmp', [rfReplaceAll]); Buffer := TJavaArray<Byte>.Create(4096); INStream := SharedActivityContext.getContentResolver.openInputStream(Uri); try FFF := TJFile.JavaClass.init(StringToJString(<ИМЯ_ПАПКИ>), StringToJString(outputfile)); FFF.setWritable(true, false); OUTStream := TJFileOutputStream.JavaClass.init(FFF); repeat NumRead := inStream.read(buffer); if (NumRead <= 0) then Break; outStream.write(buffer, 0, NumRead); application.ProcessMessages; until NumRead <= 0; outStream.close; inStream.close; except on e: exception do raise Exception.CReate('Error. Can''t copy file'); end; end end end end может не самое оптимальное, но работает, в итоге у вас файл с именем outputfile и в папке <ИМЯ_ПАПКИ>
  19. Like
    Belov.V. получил реакцию от Евгений Корепов в [Android] Обработка приложением неявного намерения (Intent)   
    Регистрируем намерение через файл манифеста (ниже для файлов с типом xml). Для Android 3.2 адекватнее работал второй фильтр:
    <activity … <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:mimeType="text/xml" /> <data android:mimeType="application/xhtml+xml" /> </intent-filter> <!-- Для 3.2 --> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="file" /> <data android:mimeType="*/*" /> <data android:host="*" /> <data android:pathPattern=".*\\.xml" /> <data android:pathPattern=".*\\..*\\.xml" /> <data android:pathPattern=".*\\..*\\..*\\.xml" /> <data android:pathPattern=".*\\..*\\..*\\..*\\.xml" /> <data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.xml" /> </intent-filter> Регистрируем свой обработчик события для на событие смены состояния приложения:
    procedure TForm1.FormCreate(Sender: TObject); var ApplicationService: IFMXApplicationEventService; begin if TPlatformServices.Current.SupportsPlatformService(IFMXApplicationEventService, ApplicationService) then ApplicationService.SetApplicationEventHandler(ApplicationEventChanged); end; Оформляем обработчик.
    Получение файла можно перенести в Form1.onCreate, но я для экспериментов с activity делал тут:
    function TForm1.ApplicationEventChanged(AAppEvent: TApplicationEvent; AContext: TObject): Boolean; var intent : JIntent; fileFullPath : String; begin intent := SharedActivity.getIntent; // BecameActive if AAppEvent = TApplicationEvent.BecameActive then begin if Assigned(intent) and TJIntent.JavaClass.ACTION_VIEW.equals(intent.getAction) then begin fileFullPath := JStringToString(intent.getData.getPath); if FileExists(fileFullPath) then begin // обработка файла fileFullPath // ... end; end; end // завершаем Activity при переводе приложения в "Background" else if AAppEvent = TApplicationEvent.EnteredBackground then SharedActivity.finish; // Result := True; end; Хочу обратить внимание, что привел только сам принцип. Очень важно корректно завершить активность (при сворачивании приложения, отключении экрана и т.д. ), т.к. при повторном вызове активности будет вызываться последний из стека. И если его не закрывать будем получить предыдущий, не закрытый activity. А если за приложением зарегистрировано несколько Activity (приложение можно вызвать из ланчера или как в примере, для обработки файла по типу).... в общем тут есть с чем поиграться.   Для желающих посмотреть поведение и последовательность выкладываю пример, который формирует лог обработки. Нужно закоментировать:    else if AAppEvent = TApplicationEvent.EnteredBackground then SharedActivity.finish; И посмотреть что и когда приложение получает в SharedActivity и AAppEvent.   Ссылка в тему: http://developer.android.com/guide/topics/manifest/activity-element.html#     Что не получилось: 1) Некоторые программы отдают файл в схеме «content» (к примеру Gmail v5.1 отдает). Как в этом случае получить содержание файла не разобрался. Поэтому в фильтре ограничил вид контента "file" 2) Не смог добраться до стека Activity. Если приложение в памяти и повторно вызывается с новой activity - возможно вот тут это могло пригодиться. (activity ... android:launchMode="singleTop" в этом случае не помог).   ADD: было обсуждение, кто как закрывает приложения на андроид, чтобы не оставалось в памяти. Если добавлять SharedActivity.finish приложение 100% убирается из памяти.    
    Intent_Get-File.zip
  20. Like
    Belov.V. получил реакцию от xenon54 в Проблема при выходе из программы   
    [AlexG], и все же я не просто так предложил, т.к. поведение приложения под Android очень сильно зависит от многих факторов, к примеру от того же файла манифеста (не утверждаю, что у Вас так). Я третью неделю бьюсь с задачей корректного (по моему) поведения приложения и отсутствия зависаний при переключении между разными activity одного приложения. Так даже без изменения кода можно добиваться совершенно разного поведения программы.
     
    Кстати, так как FMX всегда возвращает ссылку на корневую активити. Пришла мысль завершать приложение с помощью:
    SharedActivity.finish;  Описания такого способа мне не попадалось. Но ради эксперимента подвесил на одно "тяжелое" приложений и те, с которыми играюсь сейчас. Пока вроде все корректно. Интересно у кого как, в особенности у кого были проблемы.
  21. Like
    Belov.V. получил реакцию от Марк в [TGrid] Как получить значение ячейки при использовании LiveBinding?   
    С того момента, как "стал рассматривать" TGrid непосредственно как компонент отображения существующих данных, работать с ним стало проще и приятнее. В похожих ситуация работаю непосредственно с данными (выборкой). То, что FDQuery и Grid связаны через LiveBinding, значения не имеет:
    FDQuery1.RecNo := Grid1.Selected+1; ... := FDQuery1.FieldByName['id'].AsInteger; //или по порядковому номеру: ... := FDQuery1.Fields.Fields[0].AsInteger; //или тип Variant: ... := FDQuery1['id'] //и т.д. В зависимости от необходимого способа реакции код можно подвесить на onClick, onMouseMove и т.д. по желанию.
  22. Like
    Belov.V. получил реакцию от AngryOwl в [TGrid] Как получить значение ячейки при использовании LiveBinding?   
    С того момента, как "стал рассматривать" TGrid непосредственно как компонент отображения существующих данных, работать с ним стало проще и приятнее. В похожих ситуация работаю непосредственно с данными (выборкой). То, что FDQuery и Grid связаны через LiveBinding, значения не имеет:
    FDQuery1.RecNo := Grid1.Selected+1; ... := FDQuery1.FieldByName['id'].AsInteger; //или по порядковому номеру: ... := FDQuery1.Fields.Fields[0].AsInteger; //или тип Variant: ... := FDQuery1['id'] //и т.д. В зависимости от необходимого способа реакции код можно подвесить на onClick, onMouseMove и т.д. по желанию.
  23. Like
    Belov.V. получил реакцию от Kitty в [TGrid] Как получить значение ячейки при использовании LiveBinding?   
    С того момента, как "стал рассматривать" TGrid непосредственно как компонент отображения существующих данных, работать с ним стало проще и приятнее. В похожих ситуация работаю непосредственно с данными (выборкой). То, что FDQuery и Grid связаны через LiveBinding, значения не имеет:
    FDQuery1.RecNo := Grid1.Selected+1; ... := FDQuery1.FieldByName['id'].AsInteger; //или по порядковому номеру: ... := FDQuery1.Fields.Fields[0].AsInteger; //или тип Variant: ... := FDQuery1['id'] //и т.д. В зависимости от необходимого способа реакции код можно подвесить на onClick, onMouseMove и т.д. по желанию.
  24. Like
    Belov.V. отреагировална haword в [TBannerAd] Можно ли разместить TBannerAd внутри другого FMX контрола?   
    и где правки? 
  25. Like
    Belov.V. отреагировална Brovin Yaroslav в AV при "Application.ProcessMessages" в событии MouseLeave на любом контроле   
    Добрый день,
     
    Проблема в том, что когда вы вызываете ProcessMessage в OnMouseLeave, то вы по сути прерываете логику обработки Hovered контрола (Тот, что находится под мышкой). То есть вызывая ProcessMessage вы запускаете новый прогон обработки сообщений заново, не закончив предыдущий. В итоге, новый запуск сбрасывает ссылки на объект Hovered. А после возвращения в обратно в первый ProcessMessage Hovered еще используется, но он уже nil. Тут и возникает AV.
    procedure TCommonCustomForm.SetHovered(const Value: IControl); begin if (Value <> FHovered) then begin if FHovered <> nil then begin FHovered.DoMouseLeave; // <Тут вы вызываете ProcessMessage и после выхода, тут будет nil FHovered.RemoveFreeNotify(Self); end; FHovered := Value; if FHovered <> nil then begin FHovered.AddFreeNotify(Self); FHovered.DoMouseEnter; end; end; end; Если очень хочется использовать ProcessMessage в таком месте, можете добавить проверку на нил, после:
    FHovered.DoMouseLeave; if FHovered <> nil then FHovered.RemoveFreeNotify(Self);
×
×
  • Создать...