-
Постов
20 -
Зарегистрирован
-
Посещение
Сообщения, опубликованные Legit Coder
-
-
Привет, Я пытаюсь создать клиент для повторного получения данных в реальном времени из "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 { D�clarations priv�es } 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 { D�clarations 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
я хочу, чтобы данные отображались следующим образом:
-
я замечаю логику во время создания "FormCreate"и создания, все происходит в голове, как ты сказал.
Действительно, Спасибо! -
-
Спасибо за объяснение! Но я решил использовать ListView1.Selected, потому что мы должны указать вид выбора. Но, как вы и предположили, я заменил весь свой код, и теперь ничего не выбрано, ничего не появляется.
.это безумие, но я знаю, что если я буду упорствовать, я пойму свои недостатки и буду прогрессировать.
-
вот что я написал, это работает, но я думаю, что есть более профессиональный подход, не могли бы вы меня поправить?
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;
-
я потратил некоторое время , но я думаю, что есть вещи, которые я не закодировал. я не совсем понимаю твое решение. не забывайте, что я все еще учусь. Будьте снисходительны.
В 23.08.2022 в 12:03, krapotkin сказал:ShowSelectionList();
???
В 23.08.2022 в 12:03, krapotkin сказал:UpdateValueLabels();
я потратил некоторое время , но я думаю, что есть вещи, которые я не закодировал
-
-
После того, как выбор сделан, что мне делать, если я хочу измениться и выбрать другое значение? в пределах 2 TLabel?
-
В 29.07.2022 в 06:23, krapotkin сказал:
Label1.text := ListView ListItems[SelectedList[1]].Text
ты имеешь в виду
Label1.text := ListView1.Items[SelectedList[1]].Text
-
5 часов назад, krapotkin сказал:
я не знаю, откуда вы берете текст, который размещается в ListView но он же должен где-то храниться
вот оттуда его берём в методе UpdateLabelsTListView заполняется из API, и я делаю livebindings: https://api.apilayer.com/exchangerates_data/symbols
NB: я использую Delphi 11 и Firemonkey
-
В 19.07.2022 в 14:27, krapotkin сказал:
Кликнуть вы можете по одной строке ListView. Допустим, текст, который в этой строке, вы хотите разместить в Label1. А откуда берется текст в Label2 ???
в же TListView
-
хорошо, как я уже говорил в начале, У меня есть приложение с 2 TLabels, 1 TListView.
1. Когда я нажимаю на 1-й TLabel, я выбираю text в TListView и сохраняю его во 2-м TLabel.
2. Когда я нажимаю на 2-й TLabel, я выбираю другой текст, отличный от 1-го, в же TListView, и он сохраняется во 2-м TLabel.
Sorry for my bad Russian. извините за мой плохой русский язык
-
Я начинаю в delphi и не знаю, как это сделать, если мы хотим выбрать другой элемент, когда был выбран первый?
-
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;
-
У меня есть приложение с 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.
-
Как проанализировать json из websocket для отображения данных в реальном времени? (How to parse json from websocket to display realtime data?)
в Прочие вопросы
Опубликовано
да