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

Kast2k

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

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

  • Посещение

Сообщения, опубликованные Kast2k

  1. Вследствие асинхронной обработки железным сканером вызовов TJNASC.Stop и TJNASC.Stop проблема была решена добавлением 2 TTimer выполняющих эти вызовы.

    Возможно решение кривое, но работает чётко.

  2. Добрый день!

    Пишу программу для обработки результатов работы сканера Honeywell CT50 (Android 6).

    Сразу прошу прощения за простыни кода, упрощал изо всех сил.

    Главная форма:

      TMainForm = class(TForm)
        Label1: TLabel;
        btnSaveToStore: TButton;
        procedure FormCreate(Sender: TObject);
      private
        { Private declarations }
        FAutomaticMode:Boolean;
    
        procedure ActivateScanner;
      public
        property AutomaticMode: Boolean read FAutomaticMode write FAutomaticMode;
    
        procedure onBarCodeCompleteThreadSwitcher;
        procedure onBarCodeFailThreadSwitcher;
    
        procedure ShowInformationMessage(const AText:string);
        { Public declarations }
      end;
    
    uses
      FMX.Helpers.Android,  Androidapi.NativeActivity,  Androidapi.JNI.Widget,
      formScanTakeOnStore, PSTypes, PSVars;
    
    procedure TMainForm.ActivateScanner;
    begin
      RegisterDelphiNativeMethods;
      TJNASC.Activate;
      Log.d('Scanner ready');
    end;
    
    procedure TMainForm.btnSaveToStoreClick(Sender: TObject);
    begin
      Barcode.DelayInSeconds:=2;
      frmScanTakeOnStore:=TfrmScanTakeOnStore.Create(Application);  //правильный ли вызов? надо ли Free при выходе?
      frmScanTakeOnStore.Show;
    end;
    
    procedure TMainForm.FormCreate(Sender: TObject);
    begin
      Barcode:=TBarcode.Create;
      Barcode.DelayInSeconds:=2;
      ActivateScanner; 
    end;
    
    procedure TMainForm.onBarCodeCompleteThreadSwitcher;
    begin
      if AutomaticMode then
        TJNASC.Start
      else
        TJNASC.Stop;
    end;
    
    procedure TMainForm.onBarCodeFailThreadSwitcher;
    begin
    
    end;
    
    procedure TMainForm.ShowInformationMessage(const AText: string);
    begin
      CallInUiThread (
            procedure
            begin
              TJToast.JavaClass.makeText (TAndroidHelper.Context,
                  StrToJCharSequence(AText), TJToast.JavaClass.LENGTH_LONG).show;
            end
      );
    end;

    PSTypes.pas

    unit PSTypes;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ScrollBox,
      FMX.Memo, FMX.Controls.Presentation, FMX.StdCtrls,
      Androidapi.JNI.App,  Androidapi.JNI,  Androidapi.JNIBridge,  Androidapi.JNI.JavaTypes,
      DateUtils,  System.Character;
    
    type
      JNativeActivitySubclass = interface;
    
      JNativeActivitySubclassClass = interface(JActivityClass)
      ['{361C7073-E0A2-4A0D-B5E4-8403E5214275}']
        {Methods}
        //function init: JFMXNativeActivity; cdecl;
      end;
    
      [JavaSignature('com/winarhi/nativeactivitysubclass/NativeActivitySubclass')]
      JNativeActivitySubclass = interface(JActivity)
      ['{7141B1C4-508D-46F3-A767-E0BFCE22C9CE}']
        {Methods}
    //    procedure WA_75e_DoScan(paramBoolean :JBoolean);
        procedure WA_75e_Create_aidcManager;
        procedure WA_75e_Destroy_aidcManager;
        procedure WA_75eStart;
        procedure WA_75eStop;
      end;
      TJNativeActivitySubclass = class(TJavaGenericImport<JNativeActivitySubclassClass, JNativeActivitySubclass>)
      public
        procedure Activate;
        procedure DeActivate;
        procedure Start;
        procedure Stop;
      end;
    
      TBarcodeData=record
      end;
    
      TBarcodeResult=procedure(const BarcodeData:TBarcodeData) of object;
    
      TBarcode=class
      private
        FBarcodeData : TBarcodeData;
        FOnBarcodeResult : TBarcodeResult;
    
        procedure SetReceivedBarcodeData(const Value: string);
      public
        property OnBarcodeResult: TBarcodeResult read FOnBarcodeResult write FOnBarcodeResult;
      end;
    
    procedure RegisterDelphiNativeMethods;
    
    implementation
    
    uses
      FMX.Helpers.Android,
      Androidapi.NativeActivity, PSVars, formMain;
    
    { TJNativeActivitySubclass }
    
    procedure onBarCodeCompleteNative(PEnv: PJNIEnv; This: JNIObject; BarCode: JNIString); cdecl;
    begin
      PSVars.Barcode.ReceivedBarcodeData := JNIStringToString(PEnv, BarCode);
      TThread.Synchronize(TThread.CurrentThread, MainForm.onBarCodeCompleteThreadSwitcher);
    end;
    
    procedure onBarCodeFailNative(PEnv: PJNIEnv; This: JNIObject; BarCode: JNIString); cdecl;
    begin
    //  PSVars.Barcode.ReceivedBarcodeData := JNIStringToString(PEnv, BarCode);
      TThread.Synchronize(TThread.CurrentThread, MainForm.onBarCodeFailThreadSwitcher);
    end;
    
    procedure RegisterDelphiNativeMethods;
    var
      PEnv: PJNIEnv;
      ActivityClass: JNIClass;
      NativeMethods: array[0..1] of JNINativeMethod;
    begin
      Log.d('Starting the registration JNI stuff');
    
      PEnv := TJNIResolver.GetJNIEnv;
    
      Log.d('Registering interop methods');
    
      NativeMethods[0].Name := 'onBarCodeCompleteNative';
      NativeMethods[0].Signature := '(Ljava/lang/String;)V';
      NativeMethods[0].FnPtr := @onBarCodeCompleteNative;
    
      NativeMethods[1].Name := 'onBarCodeFailNative';
      NativeMethods[1].Signature := '()V';
      NativeMethods[1].FnPtr := @onBarCodeFailNative;
    
      ActivityClass := PEnv^.GetObjectClass(
        PEnv, PANativeActivity(System.DelphiActivity).clazz);
    
      PEnv^.RegisterNatives(PEnv, ActivityClass, @NativeMethods[0], 2);
    
      PEnv^.DeleteLocalRef(PEnv, ActivityClass);
    
      Log.d('Interop Methods Registered');
    end;
    
    procedure TJNativeActivitySubclass.Activate;
    begin
      Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75e_Create_aidcManager;
    end;
    
    procedure TJNativeActivitySubclass.DeActivate;
    begin
      Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75e_Destroy_aidcManager;
    end;
    
    procedure TJNativeActivitySubclass.Start;
    begin
      Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75eStart;
    end;
    
    procedure TJNativeActivitySubclass.Stop;
    begin
      Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75eStop;
    end;
    
    end.

    PSVars

    unit PSVars;
    
    interface
    
    uses
      PSTypes ;
    
    var
      Barcode:TBarcode;
      TJNASC:TJNativeActivitySubclass;
    
    implementation
    
    end.

     

    formScanTakeOnStore

    unit formScanTakeOnStore;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
      FMX.Controls.Presentation, FMX.StdCtrls, FMX.ScrollBox, FMX.Memo,
      Androidapi.JNI.App,  Androidapi.JNI,  Androidapi.JNIBridge,  Androidapi.JNI.JavaTypes,
      Androidapi.Helpers, FMX.DialogService, System.Rtti, FMX.Grid.Style,
      FMX.Grid, FMX.TextLayout, DateUtils, PSTypes, FMX.Objects;
    
    type
      TfrmScanTakeOnStore = class(TForm)
        Label1: TLabel;
        btnFinish: TButton;
        Panel1: TPanel;
        Panel2: TPanel;
        Panel3: TPanel;
        btnContinuous: TButton;
        btnManual: TButton;
        Panel4: TPanel;
        lblReceived: TLabel;
        StyleBook1: TStyleBook;
        btnTable: TButton;
        lblMaterial: TLabel;
        lblBankaCounts: TLabel;
        lblTotalLeft: TLabel;
        tmrSleep: TTimer;
        rectStatus: TRectangle;
        Button1: TButton;
        procedure btnFinishClick(Sender: TObject);
        procedure FormShow(Sender: TObject);
        procedure btnContinuousClick(Sender: TObject);
        procedure btnManualClick(Sender: TObject);
        procedure btnTableClick(Sender: TObject);
        procedure tmrSleepTimer(Sender: TObject);
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
        FNewDataExist:Boolean;
    
        BarcodeData:TBarcodeData;
    
        procedure OnBarcodeResult(const ABarcodeData:TBarcodeData);
        procedure CloseFrm(Sender: TObject; const AResult: TModalResult);
        procedure MaterialAddedNG(Sender: TObject; const AResult: TModalResult);
        procedure MaterialAddedOK(Sender: TObject; const AResult: TModalResult);
        procedure StopScannerAndColor(CL:Cardinal);
      public
        { Public declarations }
      end;
    
    var
      frmScanTakeOnStore: TfrmScanTakeOnStore;
    
    implementation
    
    uses
      FMX.Helpers.Android,  Androidapi.NativeActivity, formScanComplete, dmData, formAgreeAction,
      formScanTakeOnStoreTable, PSVars, formMain;
    
    {$R *.fmx}
    
    procedure TfrmScanTakeOnStore.btnContinuousClick(Sender: TObject);
    begin
      TJNASC.Start;
      btnContinuous.StyleLookup:='btnContinuousStyle1';
      btnManual.StyleLookup:='';
      MainForm.AutomaticMode:=True;
      MainForm.ShowInformationMessage('Automatic mode');
    end;
    
    procedure TfrmScanTakeOnStore.btnFinishClick(Sender: TObject);
    begin
    //  MainForm.SayTextToSpeech('Завершить приемку материалов на склад?');
      TDialogService.MessageDialog(
        'Завершить приемку материалов на склад?',
        TMsgDlgType.mtWarning,
        [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo],
        TMsgDlgBtn.mbNo,
        0,
        CloseFrm);
    end;
    
    procedure TfrmScanTakeOnStore.btnManualClick(Sender: TObject);
    begin
      TJNASC.Stop;
      btnManual.StyleLookup:='btnContinuousStyle1';
      btnContinuous.StyleLookup:='';
      MainForm.AutomaticMode:=False;
    end;
    
    procedure TfrmScanTakeOnStore.btnTableClick(Sender: TObject);
    begin
      CallInUIThread(procedure begin
        frmScanTakeOnStoreTable:=TfrmScanTakeOnStoreTable.Create(Application); //Free ???
        frmScanTakeOnStoreTable.Show;
      end);
    end;
    
    procedure TfrmScanTakeOnStore.Button1Click(Sender: TObject); //simulation
    var
      bc: TBarcodeData;
    begin
      bc.Parsed:=True;
      bc.KPJCode:='80604358';
      bc.LotName:='testlot';
      OnBarcodeResult(bc);
    end;
    
    procedure TfrmScanTakeOnStore.CloseFrm(Sender: TObject; const AResult: TModalResult);
    begin
      if AResult = mrYes then
        begin
          TJNASC.Stop;
          MainForm.AutomaticMode:=False;
          Close;
        end;
    end;
    
    procedure TfrmScanTakeOnStore.FormShow(Sender: TObject);
    begin
      Log.d('Pre-activate');
      tmrSleep.Interval:=Barcode.DelayInSeconds*1000;
    
      Barcode.LastScanTimeUnix:=DateTimeToUnix(Now);
      Barcode.OnBarcodeResult:=OnBarcodeResult;
    end;
    
    procedure TfrmScanTakeOnStore.MaterialAddedNG(Sender: TObject;
      const AResult: TModalResult);
    begin
      if AResult = mrYes then
        begin
          ///NG result parse
        end;
    end;
    
    procedure TfrmScanTakeOnStore.MaterialAddedOK(Sender: TObject;
      const AResult: TModalResult);
    begin
    
    end;
    
    procedure TfrmScanTakeOnStore.OnBarcodeResult(const ABarcodeData: TBarcodeData);
    begin
      if ABarcodeData.Parsed then
        begin
          StopScannerAndColor(TAlphaColors.Green);
        end
      else
        begin
          MainForm.ShowInformationMessage(ARNBarCode+' невозможно распознать.');
          StopScannerAndColor(TAlphaColors.Red);
        end;
    end;
    
    procedure TfrmScanTakeOnStore.StopScannerAndColor(CL: Cardinal);
    begin
      rectStatus.Fill.Color:=CL;
      TJNASC.Stop;
      TJNASC.DeActivate;
      Log.d('Scanner DeActivate');
      tmrSleep.Enabled:=True;
    end;
    
    procedure TfrmScanTakeOnStore.tmrSleepTimer(Sender: TObject);
    begin
      TJNASC.Activate;
      Log.d('Scanner ready');
      if MainForm.AutomaticMode then
        begin
          MainForm.ShowInformationMessage('Starting scanner');
    
          frmScanTakeOnStore.btnManual.OnClick(frmScanTakeOnStore.btnManual);
          Sleep(1000);
          frmScanTakeOnStore.btnContinuous.OnClick(frmScanTakeOnStore.btnContinuous);
    
          MainForm.ShowInformationMessage('Automatic mode');
        end;
      rectStatus.Fill.Color:=StrToInt('$FFE0E0E0');
      tmrSleep.Enabled:=False;
    end;
    
    end.

     

    Итак, при запуске основной формы сканер активируется и появляется возможность чтения.

    Для получения и обработки данных я открываю форму frmScanTakeOnStore и выставляю статус ручное сканирование.

    Процедуры TJNASC.Start, TJNASC.Stop отвечают за Автоматическое сканирование ВКЛ и Выкл соответственно. Автоматическое = сканер постоянно пытается считать баркод. Ручное = чтение по триггеру (кнопке на аппарате).

    Поступила задача, если сканер в Автоматическом режиме, то после каждого скнаирования надо делать паузу в 1-несколько секунд и выключать сканер, а потом активировать снова.

    Я решил сделать это через штатный таймер. Он отрабатывает нормально, но симуляция нажатия кнопок (знаю что так себе решение, но см дальше) не происходит. Т.е. если я закомментирую строку в OnTimer

          Sleep(1000);      frmScanTakeOnStore.btnContinuous.OnClick(frmScanTakeOnStore.btnContinuous);

    то кнопка btnManual станет подсвеченной. Если раскомментирую, то автоматическое чтение не активируется. НО! Если просто нажать на кнопку btnContinuous, то сканер запускает постоянное чтение.

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

      TJNASC.Stop;
      MainForm.AutomaticMode:=False;
      TJNASC.Start;
      MainForm.AutomaticMode:=True;

    Пробовал через CallInUIThread() = тоже самое

     

    Коллеги,

    Подскажите, пожалуйста, что я делаю не так? Может быть необходимо методы по иному вызывать или я упускаю какие-то пункты?

     

     

    Спасибо!

  3. Простите за беспокойство, разобрался.

    Надо было в главной форме вместо такого

     

    var
      f:TfrmScanWindow;
    begin
      f:=TfrmScanWindow.Create(nil);
      try
        f.Show;
      finally
    //    FreeAndNil(f);
      end;

    Указать как

    begin
      frmScanWindow:=TfrmScanWindow.Create(nil);
      try
        frmScanWindow.Show;
      finally
      end;

    И форму выкинуть из auto-create

  4. Добрый день!

    Delphi 10.2 Tokyo.

    С FMX разбираюсь всего пару-тройку недель и возможно пока не понимаю его принципов работы.

    Есть сканер на андроиде Honeywell.

    В FMX рисую для него приложение по получению и обработке штрих-кодов.

    Есть основная форма и вспомогательная (принимающая данные со сканера). Дочернюю форму вызываю так:

    procedure TMainForm.btnSaveToStoreClick(Sender: TObject);
    var
      f:TfrmScanWindow;
    begin
      f:=TfrmScanWindow.Create(Application);
      try
        f.Show;
      finally
    //    FreeAndNil(f);
      end;
    end;

    Далее, в дочерней форме следующий код:

     

    type
      JNativeActivitySubclass = interface;
    
      JNativeActivitySubclassClass = interface(JActivityClass)
      ['{829C77FB-08F1-4D19-9782-3C58EECAAAAA}']
        {Methods}
        //function init: JFMXNativeActivity; cdecl;
      end;
    
      [JavaSignature('com/winarhi/nativeactivitysubclass/NativeActivitySubclass')]
      JNativeActivitySubclass = interface(JActivity)
      ['{2FA559EC-D1D7-46AA-9C52-FEFC6B3AAAAA}']
        {Methods}
        procedure WA_75e_DoScan;
        procedure WA_75e_Create_aidcManager;
        procedure WA_75e_Destroy_aidcManager;
      end;
      TJNativeActivitySubclass = class(TJavaGenericImport<JNativeActivitySubclassClass, JNativeActivitySubclass>) end;
    
      TfrmScanWindow = class(TForm)
        Label1: TLabel;
        MemoData: TMemo;
        btnAgree: TButton;
        btnCancel: TButton;
        btnFinish: TButton;
        Panel1: TPanel;
        Panel2: TPanel;
        Timer1: TTimer;
        procedure btnFinishClick(Sender: TObject);
        procedure FormClose(Sender: TObject; var Action: TCloseAction);
        procedure FormShow(Sender: TObject);
        procedure Timer1Timer(Sender: TObject);
      private
        { Private declarations }
        ARNBarCode : string;
        procedure MemoAddText(const AText:string);
      public
        { Public declarations }
        procedure ActivateScanner;
        procedure RegisterDelphiNativeMethods;
        procedure onBarCodeCompleteThreadSwitcher;
        procedure onBarCodeFailThreadSwitcher;
      end;
    
    var
      frmScanWindow: TfrmScanWindow;
    
    implementation
    
    uses
      FMX.Helpers.Android,
      Androidapi.NativeActivity, formScanComplete;
    
    {$R *.fmx}
    
    procedure onBarCodeCompleteNative(PEnv: PJNIEnv; This: JNIObject; BarCode: JNIString); cdecl;
    begin
      frmScanWindow.MemoAddText('onBarCodeCompleteNative start'); // НЕ работает
      TThread.Synchronize(TThread.CurrentThread,
        procedure()
        begin
          frmScanWindow.MemoData.Lines.Add('onBarCodeCompleteNative start');
          frmScanWindow.MemoData.Repaint;
        end);  // НЕ работает
    //  Log.d('Thread (Main: %.8x, Current: %.8x, Java:%.8d (%2:.8x), POSIX:%.8x)',
    //    [MainThreadID, TThread.CurrentThread.ThreadID, TJThread.JavaClass.currentThread.getId]);
      frmScanWindow.ARNBarCode := JNIStringToString(PEnv, BarCode); // работает
      TThread.Synchronize(TThread.CurrentThread, frmScanWindow.onBarCodeCompleteThreadSwitcher); // НЕ работает
    end;
    
    
    procedure onBarCodeFailNative(PEnv: PJNIEnv; This: JNIObject; BarCode: JNIString); cdecl;
    begin
      frmScanWindow.MemoAddText('onBarCodeFailNative start'); // НЕ работает
    //  Log.d('Thread (Main: %.8x, Current: %.8x, Java:%.8d (%2:.8x), POSIX:%.8x)',
    //    [MainThreadID, TThread.CurrentThread.ThreadID, TJThread.JavaClass.currentThread.getId]);
      frmScanWindow.ARNBarCode := JNIStringToString(PEnv, BarCode); // работает
    //  Log.d('Calling Synchronize');
      TThread.Synchronize(TThread.CurrentThread, frmScanWindow.onBarCodeFailThreadSwitcher); // НЕ работает
    end;
    
    procedure TfrmScanWindow.ActivateScanner;
    begin
      RegisterDelphiNativeMethods;
      TJNativeActivitySubclass.Wrap(PANativeActivity(System.DelphiActivity)^.clazz).WA_75e_Create_aidcManager;
      MemoAddText('Activated'); // работает
    end;
    
    procedure TfrmScanWindow.FormShow(Sender: TObject);
    begin
      MemoAddText('Pre-activate');  // работает
      ActivateScanner;
    end;
    
    procedure TfrmScanWindow.MemoAddText(const AText: string);
    begin
      MemoData.Lines.BeginUpdate;
      try
        MemoData.Lines.Add(AText);
      finally
        MemoData.Lines.EndUpdate;
      end;
    end;
    
    procedure TfrmScanWindow.onBarCodeCompleteThreadSwitcher;
    begin
      MemoAddText('onBarCodeCompleteThreadSwitcher'); // НЕ работает
      MemoAddText(ARNBarCode);  // НЕ работает
      ShowMessage(ARNBarCode);  // работает
    end;
    
    procedure TfrmScanWindow.onBarCodeFailThreadSwitcher;
    begin
      MemoAddText('onBarCodeFailThreadSwitcher'); // НЕ работает
      MemoAddText('Barcode Scan Failed ' + ARNBarCode); // НЕ работает
    end;
    
    procedure TfrmScanWindow.RegisterDelphiNativeMethods;
    var
      PEnv: PJNIEnv;
      ActivityClass: JNIClass;
      NativeMethods: array[0..1] of JNINativeMethod;
    begin
      Log.d('Starting the registration JNI stuff');
      PEnv := TJNIResolver.GetJNIEnv;
    
      Log.d('Registering interop methods');
    
      NativeMethods[0].Name := 'onBarCodeCompleteNative';
      NativeMethods[0].Signature := '(Ljava/lang/String;)V';
      NativeMethods[0].FnPtr := @onBarCodeCompleteNative;
    
      NativeMethods[1].Name := 'onBarCodeFailNative';
      NativeMethods[1].Signature := '()V';
      NativeMethods[1].FnPtr := @onBarCodeFailNative;
    
      ActivityClass := PEnv^.GetObjectClass(
        PEnv, PANativeActivity(System.DelphiActivity).clazz);
    
      PEnv^.RegisterNatives(PEnv, ActivityClass, @NativeMethods[0], 2);
    
      PEnv^.DeleteLocalRef(PEnv, ActivityClass);
    
      Log.d('Interop Methods Registered');
    end;
    
    procedure TfrmScanWindow.Timer1Timer(Sender: TObject);
    begin
      MemoAddText(FormatDateTime('hh:nn:ss',Now)); // работает
    end;

    Поясните, пожалуйста, что я делаю не так.

    Если весь этот код вызывать в основной форме, то всё работает и в memo я вижу полученные данные баркода. При вызове из дочерней - нет.

    При попытке вызвать ShowModal я получаю ошибку Not implemented for this platform.

     

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