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

Legit Coder

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

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

  • Посещение

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

  1. Привет, Я пытаюсь создать клиент для повторного получения данных в реальном времени из "twelvedata.com " это возвращается с сервера websocket. Вот строка JSON

    2022-12-13T22:43:30.142Z <== {"event":"subscribe-status","status":"ok","success":[{"symbol":"USD/JPY","exchange":"PHYSICAL CURRENCY","mic_code":"PHYSICAL CURRENCY","country":"","type":"Physical Currency"},{"symbol":"BTC/USD","exchange":"Coinbase Pro","mic_code":"Coinbase Pro","country":"","type":"Digital Currency"},{"symbol":"ETH/BTC","exchange":"Huobi","mic_code":"Huobi","country":"","type":"Digital Currency"}],"fails":null}
    
    2022-12-13T22:43:30.541Z <== {"event":"price","symbol":"BTC/USD","currency_base":"Bitcoin","currency_quote":"US Dollar","exchange":"Coinbase Pro","type":"Digital Currency","timestamp":1670971410,"price":17722.7,"bid":17722.7,"ask":17722.7,"day_volume":38419}

    Я написал клиентский код Delphi, как показано ниже, чтобы получить объект Json, но он вернул статическое значение, и программа зависла.

    Спойлер

     

    unit UnitWebsocket;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,
      FMX.Controls.Presentation, FMX.Layouts, FMX.Objects, FMX.Memo.Types, Skia.FMX,
      FMX.ScrollBox, FMX.Memo, System.IOUtils, Ics.Fmx.OverbyteIcsWndControl,
      Ics.Fmx.OverbyteIcsWSocket, Bird.Socket.Client, FMX.WebBrowser;
    
    const
      // API  = 'wss://ws.twelvedata.com/v1/quotes/price?apikey=key';
      API  = '';
    
    type
      TMainUnit = class(TForm)
        Rectangle1: TRectangle;
        GridPanelLayout1: TGridPanelLayout;
        GridPanelLayout2: TGridPanelLayout;
        GridPanelLayout3: TGridPanelLayout;
        Connection: TLabel;
        OpenConnection: TCornerButton;
        CloseConnection: TCornerButton;
        Messages: TLabel;
        Subscribe: TCornerButton;
        Unsubscribe: TCornerButton;
        Reset: TCornerButton;
        Layout1: TLayout;
        Memo1: TMemo;
        Send: TCornerButton;
        Timer1: TTimer;
        GridPanelLayout4: TGridPanelLayout;
        GridPanelLayout5: TGridPanelLayout;
        Price: TLabel;
        Beautify: TCornerButton;
        Layout2: TLayout;
        DisplayMemo: TMemo;
        WebBrowser1: TWebBrowser;
        Splitter1: TSplitter;
        procedure SubscribeClick(Sender: TObject);
        procedure UnsubscribeClick(Sender: TObject);
        procedure ResetClick(Sender: TObject);
        procedure SendClick(Sender: TObject);
        procedure CloseConnectionClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure OpenConnectionClick(Sender: TObject);
    //    procedure BeautifyClick(Sender: TObject);
    //    procedure LoadCode(const ACode, AType: string; Wrapped: Boolean = False);
    //    procedure LoadError(const Msg: string);
      private
        { Dclarations prives }
        FBirdSocket: TBirdSocketClient;
        procedure StartCources;
        procedure Display(Msg : String);
        procedure SocketText(Sender: TObject; const iText: String);
        procedure FCources(const rowCount, colCount, srowCount, scolCount: integer);
        procedure Timer1Timer(Sender: TObject);
      public
        { Dclarations publiques }
      end;
    
    var
      MainUnit: TMainUnit;
    
    implementation
    
    {$R *.fmx}
    
    uses
      System.NetEncoding, System.Rtti, System.Math, System.JSON.Types, System.JSON.Builders, System.JSON.Readers, Common, Converters;
    
    procedure TMainUnit.CloseConnectionClick(Sender: TObject);
    begin
      try
        if not Assigned(FBirdSocket) then
          Exit;
        if FBirdSocket.Connected then
          FBirdSocket.Disconnect;
        FreeAndNil(FBirdSocket);
        DisplayMemo.Lines.Add('Websocket connection closed!');
    //    Timer1.Enabled := False;
        CloseConnection.Enabled := False;
        Send.Enabled := False;
        OpenConnection.Enabled := True;
      except
        on E:Exception do
          Display(E.Message);
      end
    end;
    
    {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
    { Display a message in our display memo. Delete lines to be sure to not     }
    { overflow the memo which may have a limited capacity.                      }
    procedure TMainUnit.Display(Msg : String);
    var
      I : Integer;
    begin
      DisplayMemo.Lines.BeginUpdate;
      try
        if DisplayMemo.Lines.Count > 200 then begin
          for I := 1 to 50 do
            DisplayMemo.Lines.Delete(0);
        end;
        DisplayMemo.Lines.Add(Format('%s <== %s', [FormatDateTime('dd/mm/yyyy hh:mm:ss', Now), Msg]));
      finally
        DisplayMemo.Lines.EndUpdate;
        DisplayMemo.GoToTextEnd;
      end;
    end;
    
    procedure TMainUnit.FCources(const rowCount, colCount, srowCount, scolCount: integer);
    var
      i,j: integer;
      trend: TSkSvg;
      aRect: TRectangle;
      bRect: TRectangle;
      aGridP: TGridPanelLayout;
      fLabel: TLabel;
      aControl, bControl, cControl, dControl : TControl;
    begin
    
    
      GridPanelLayout5.RowCollection.BeginUpdate;
      GridPanelLayout5.ColumnCollection.BeginUpdate;
    
      GridPanelLayout5.ControlCollection.Clear;
      GridPanelLayout5.RowCollection.Clear;
      GridPanelLayout5.ColumnCollection.Clear;
      
      for i := 0 to -1 + GridPanelLayout5.ControlsCount do
        GridPanelLayout5.Controls[0].Free;
    
      for i := 1 to rowCount do
        with GridPanelLayout5.RowCollection.Add do
        begin
          SizeStyle := TGridPanelLayout.TSizeStyle.Percent;
          Value := 100 / rowCount; //have cells evenly distributed
        end;
    
      for i := 1 to colCount do
        with GridPanelLayout5.ColumnCollection.Add do
        begin
          SizeStyle := TGridPanelLayout.TSizeStyle.Percent;
          Value := 100 / colCount; //have cells evenly distributed
        end;
    
      for i := 0 to -1 + rowCount * colCount do
      begin
        aRect := TRectangle.Create(self);
        aRect.Parent := GridPanelLayout5; //magic: place in the next empty cell
        aRect.Align := TAlignLayout.Client;
        aRect.Visible := true;
        aRect.Name := 'FCource' + IntToStr(i);
        aRect.Fill.Color := TAlphaColorRec.White;
        aRect.Margins.Rect := TRectF.Create(1,1,1,1);
        aRect.Stroke.Color := $FFE5E4E3;
        aRect.Stroke.Thickness := 0.7;
        aRect.XRadius := 7;
        aRect.YRadius := 7;
    
        bRect := TRectangle.Create(self);
        bRect.Parent := aRect;
        bRect.Align := TAlignLayout.left;
        bRect.Name := 'FTrend' + IntToStr(i);
        bRect.Fill.Color := $FFE6F4EA;
        bRect.Margins.Rect := TRectF.Create(3,3,3,3);
        bRect.Stroke.Kind := TBrushKind.None;
        bRect.Height := 30;
        bRect.Width := 30;
        bRect.XRadius := 7;
        bRect.YRadius := 7;
    
        trend := TSkSvg.Create(Self);
        trend.Svg.Source := TFile.ReadAllText('Assets\Trendup.svg'); // throws error, so put the file inside bin folder
        trend.Parent := bRect;
        trend.Align := TAlignLayout.Center;
        trend.Svg.OverrideColor := $FF137333;
        trend.Height := 21;
        trend.Width := 21;
    
        aGridP := TGridPanelLayout.Create(Self);
        with aGridP do
        begin
          aGridP.Parent := aRect;
          aGridP.Align := TAlignLayout.Client;
          aGridP.Margins.Left := 3;
    
          aGridP.RowCollection.BeginUpdate;
          aGridP.ColumnCollection.BeginUpdate;
    
          aGridP.ControlCollection.Clear;
          aGridP.RowCollection.Clear;
          aGridP.ColumnCollection.Clear;
    
          try
            // Make a loop in the columns using Avisoff and this seems to work in all platforms
            for j := 0 to -1 + aGridP.ControlsCount do
              aGridP.ControlCollection.Controls[j,0].DisposeOf;
            for j := 1 to srowCount do
              with aGridP.RowCollection.Add do
              begin
                SizeStyle := TGridPanelLayout.TSizeStyle.Percent;
                Value := 100 / srowCount; //have cells evenly distributed
              end;
            for j := 1 to colCount do
              with aGridP.ColumnCollection.Add do
              begin
                SizeStyle := TGridPanelLayout.TSizeStyle.Percent;
              end;
              // have specified cells values
              aGridP.ColumnCollection[0].Value:=60;
              aGridP.ColumnCollection[1].Value:=40;
    
            {$REGION 'Region loop'}
            for j := 0 to -1 + srowCount * scolCount do
            begin
              fLabel := TLabel.Create(Self);
              fLabel.Parent := aGridP;
              fLabel.Align :=  TAlignLayout.Client;
              // fLabel.AutoSize :=  true;
              fLabel.Margins.Right := 3;
              fLabel.Margins.Left := 3;
              fLabel.Margins.Top := 3;
              fLabel.Margins.Bottom := 3;
              aControl := aGridP.ControlCollection.Controls[0,0];
              if Assigned(aControl) AND (aControl IS TLabel) then
              begin
                TLabel(aControl).StyledSettings := TLabel(aControl).StyledSettings - [TStyledSetting.Style];
                TLabel(aControl).TextSettings.Font.Style := TLabel(aControl).TextSettings.Font.Style + [TFontStyle.fsBold];
                TLabel(aControl).Text := 'FTicker' + IntToStr(aGridP.ControlCollection.IndexOf(aControl));
              end;
    
              bControl := aGridP.ControlCollection.Controls[0,1];
              if Assigned(bControl) AND (bControl IS TLabel) then
              begin
                TLabel(bControl).Text := 'FxValue' + IntToStr(aGridP.ControlCollection.IndexOf(bControl));
              end;
    
              cControl := aGridP.ControlCollection.Controls[1,0];
              if Assigned(cControl) AND (cControl IS TLabel) then
              begin
                TLabel(cControl).Text := 'Percantage' + IntToStr(aGridP.ControlCollection.IndexOf(cControl));
                TLabel(cControl).TextAlign := TTextAlign.Trailing
              end;
    
              dControl := aGridP.ControlCollection.Controls[1,1];
              if Assigned(dControl) AND (dControl IS TLabel) then
              begin
                TLabel(dControl).Text := 'Change' + IntToStr(aGridP.ControlCollection.IndexOf(dControl));
                TLabel(dControl).TextAlign := TTextAlign.Trailing
              end;
            end;
            {$ENDREGION 'Region loop'}
    
            {$REGION 'Region JSONIterator'}
    
            {$ENDREGION 'Region JSONIterator'}
    
          finally
            aGridP.RowCollection.EndUpdate;
            aGridP.ColumnCollection.EndUpdate;
          end;
        end;
      end;
    
      GridPanelLayout5.RowCollection.EndUpdate;
      GridPanelLayout5.ColumnCollection.EndUpdate;
    end;
    
    procedure TMainUnit.StartCources;
    begin
      //
    end;
    
    procedure TMainUnit.FormCreate(Sender: TObject);
    begin
      {$IFDEF MSWINDOWS}
        ReportMemoryLeaksOnShutdown := (DebugHook <> 0);
      {$ENDIF}
      //  FBirdSocket.HeartBeatInterval := 17;
    
      Timer1 := TTimer.Create(Self);
      Timer1.Interval := 10000;
      Timer1.OnTimer := Timer1Timer;
      Timer1.Enabled := False;
      CloseConnection.Enabled := False;
      Send.Enabled := False;
    end;
    
    procedure TMainUnit.OpenConnectionClick(Sender: TObject);
    begin
      try
        if API= EmptyWideStr then
        begin
          ShowMessage('Register to TwelveDate and paste API key');
          Exit;
        end
        else
          FBirdSocket := TBirdSocketClient.New(API); 
    
        FBirdSocket.AddEventListener(TEventType.MESSAGE,
          procedure(const AText: string)
          begin
            Display(AText);
            SocketText(FBirdSocket, AText);
          end);
        FBirdSocket.Connect;
        FBirdSocket.AutoCreateHandler := True;
        DisplayMemo.Lines.Add('Websocket connection opened!');
        OpenConnection.Enabled := False;
        CloseConnection.Enabled := True;
    //    FBirdSocket.HeartBeatInterval := 70;
        Timer1.Enabled := True;
    
        FCources(3,2,2,2);
      except
        on E:Exception do
        begin
          FBirdSocket.Disconnect;
          FreeAndNil(FBirdSocket);
          Display(E.Message);
        end;
      end
    end;
    
    procedure TMainUnit.ResetClick(Sender: TObject);
    begin
      Memo1.Lines.Clear;
      Memo1.Lines.Text := '   {' +  sLineBreak +
                          '       "action": "reset"' +  sLineBreak +
                          '   }' +
                          '';
      Send.Enabled := True;
    end;
    
    procedure TMainUnit.SubscribeClick(Sender: TObject);
    begin
      Memo1.Lines.Clear;
      Memo1.Lines.Text := '   {' +  sLineBreak +
                          '       "action": "subscribe",' +  sLineBreak +
                          '       "params": {' +  sLineBreak +
                          '          "symbols": "EUR/USD,BTC/USD"' +  sLineBreak +
                          '       }' +  sLineBreak +
                          '   }' +
                          '';
      Send.Enabled := True;
    end;
    
    procedure TMainUnit.UnsubscribeClick(Sender: TObject);
    begin
      Memo1.Lines.Clear;
      Memo1.Lines.Text := '   {' +  sLineBreak +
                          '       "action": "unsubscribe",' +  sLineBreak +
                          '       "params": {' +  sLineBreak +
                          '          "symbols": "EUR/USD"' +  sLineBreak +
                          '       }' +  sLineBreak +
                          '   }' +
                          '';
      Send.Enabled := True;
    end;
    
    procedure TMainUnit.SendClick(Sender: TObject);
    begin
      FBirdSocket.Send(Memo1.lines.Text);
      StartCources;
    end;
    
    procedure TMainUnit.SocketText(Sender: TObject; const iText: String);
    begin
      var StringReader := TStringReader.Create(iText);
      var TextReader := TJsonTextReader.Create(StringReader);
      var Iterator := TJSONIterator.Create(TextReader);
      try
        Iterator.Recurse;
        while Iterator.Next do
        begin
          var cIterator := Iterator;
          if cIterator.Find('price') then
          begin
            Price.Text := cIterator.AsDouble.ToString;
          end;
        end;
      finally
        StringReader.DisposeOf;
        TextReader.DisposeOf;
        Iterator.DisposeOf;
      end;
    
    end;
    
    procedure TMainUnit.Timer1Timer(Sender: TObject);
    begin
      FBirdSocket.Send('{"action": "heartbeat"}');
    end;
    
    end.

    ПРИМЕЧАНИЕ: Я использую эту бесплатную библиотеку websocket bird-socket-client

    я хочу, чтобы данные отображались следующим образом:

    image.thumb.png.35243285a44e196571ab02f484f5afa1.png

    12dataClient.zip

  2. Спасибо за объяснение! Но я решил использовать ListView1.Selected, потому что мы должны указать вид выбора. Но, как вы и предположили, я заменил весь свой код, и теперь ничего не выбрано, ничего не появляется.

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

  3. вот что я написал, это работает, но я думаю, что есть более профессиональный подход, не могли бы вы меня поправить?

    procedure TForm1.ListView1ItemClick(const Sender: TObject;
      const AItem: TListViewItem);
    begin
    
      if FClickedButton = Base then
      begin
         FirstValue := TListViewItem(ListView1.Selected).Index; // SelectedList.Add(AItem.Index);
      end
      else
      begin
        SecondValue := TListViewItem(ListView1.Selected).Index; // SelectedList.Add(AItem.Index);
      end;
      UpdateValueLabels();
    
    end

    Это UpdateValueLabels()

    procedure TForm1.UpdateValueLabels();
    begin
      if Assigned(ListView1.Selected) then
        Base.text := IntToStr(FirstValue)
      else
        Base.text := '';
    
      if Assigned(ListView1.Selected) then
        Hypo.text := IntToStr(SecondValue)
      else
        Hypo.text := '';
    end;
  4. я потратил некоторое время , но я думаю, что есть вещи, которые я не закодировал. я не совсем понимаю твое решение. не забывайте, что я все еще учусь. Будьте снисходительны.

    В 23.08.2022 в 12:03, krapotkin сказал:
    ShowSelectionList();

    ???

    В 23.08.2022 в 12:03, krapotkin сказал:
    UpdateValueLabels();

    я потратил некоторое время , но я думаю, что есть вещи, которые я не закодировал

  5. 5 часов назад, krapotkin сказал:

    я не знаю, откуда вы берете текст, который размещается в ListView но он же должен где-то храниться
    вот оттуда его берём в методе UpdateLabels

    TListView заполняется из API, и я делаю livebindingshttps://api.apilayer.com/exchangerates_data/symbols

    NB: я использую Delphi 11 и Firemonkey

     

     

  6. хорошо, как я уже говорил в начале, У меня есть приложение с 2 TLabels, 1 TListView

    1. Когда я нажимаю на 1-й TLabel, я выбираю text в TListView и сохраняю его во 2-м TLabel.

    2. Когда я нажимаю на 2-й TLabel, я выбираю другой текст, отличный от 1-го, в же TListView, и он сохраняется во 2-м TLabel.

    Sorry for my bad Russian. извините за мой плохой русский язык

  7. Something like that ? что-то в этом роде?
    
    procedure TForm3.ListView1ItemClick(const Sender: TObject;
      const AItem: TListViewItem);
    var elvitem : TListViewItem;
        i,n : integer;
    begin
      n:=0;
      for i:=0 to ListView1.ItemCount-1 do
      begin
         if ListView1.Items[i].Purpose=TListItemPurpose.None then // it's an item 
         begin
            if ListView1.Items[i].Checked then
            begin
              inc(n);
              case n of
                1 : base.text:=ListView1.Items[i].Text;
                2 : begin
                      hypo.text:=ListView1.Items[i].Text;
                      break; // don't search more
                    end;
              end;
            end;
          end;
      end;
    end;

     

  8. У меня есть приложение с 2 TLabels, 1 TListView. Я хотел бы отобразить значение или (текст) содержимое TListViewItem внутри тегов TLabels образом, чтобы содержимое первой метки не могло быть одинаковым.

    Мой код :

     

    ....
      ListView1: TListView;
      Base: TLabel;
      Hypo: TLabel;
    ....
    
    procedure TMainForm.BaseClick(Sender: TObject);
    begin
       ListView1.Visible := True;
    end;
    
    procedure TMainForm.HypoClick(Sender: TObject);
    begin
       ListView1.Visible := True;
    end;    
    
    procedure TMainForm.ListView1ItemClick(const Sender: TObject;
       const AItem: TListViewItem);
    begin
       if Assigned(ListView1.Selected) then
    	begin
          Base.Text := TListViewItem(ListView1.Selected).Text;
        end else
          Hypo.Text := TListViewItem(ListView1.Selected).Text;
       
       ListView1.Visible := False;
    end;

    на изображении я хочу, чтобы XAG выделялся, когда я нажимаю на 1-ю TLabel, а другое значение также выбиралось как XAF, например, когда я нажимаю на 2-ю TLabel.

    WfYA7.png

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