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

Евгений Корепов

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

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

  • Посещение

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

    100

Сообщения, опубликованные Евгений Корепов

  1. Пытаюсь приручить THTTPClient в асинхронном режиме работы. Все работает чудесно, в некоторых проектах смело выкидывается значительная часть кода - потоки, очереди, таймеры и прочее.

    Но столкнулся с проблемой - есть десяток TImage, в которые нужно загрузить картинки скачанные по http (классическая задача с TListView к примеру). Вроде все хорошо, кроме идентификации закачанных картинок, закачка может завершится не в той последовательности, в которой она производилась, т.е. делаю десять вызовов FHTTPClient.BeginGet(DoEndDownload, URL, FDownloadStream), а в процедуре DoEndDownload получаю скачанную в FDownloadStream картинку. Как узнать к какому TImage относится скачанная картинка?

  2. Кроме этого в TMultiView починили еще этот глюк - внимание в левую часть скриншота, эта вертикальная линия видна всегда, выглядит чудовищно уродски

    На втором скриншоте тоже приложение в Токио, никаких изменений не производилось, проект открыт как есть.

     

    Screenshot_2017-02-11-10-02-46.png

    Screenshot_2017-03-29-07-51-08.png

  3. 7 часов назад, ENRGY сказал:

    Что там новенького ? Поломанная платформа Android из за многократного падения производительности?

    Вроде нормально все, один из проектов перенес уже - впечатления пока положительные. Там что то с потоками UI изменения, вместо двух потоков (java и delphi) теперь один поток UI. Плюс куча плюшек по упрощению работы в потоках - вроде как TBitmap (и что то еще) можно без синхронизации изменять в разных потоках:

    Цитата

    Multi-Threading Support for TBitmap, TCanvas and TContext3D

    • TBitmap: Complete multi-threading support. Can be created, destroyed, and modified in any thread without synchronizations.
    • TCanvas: Supports being used from multiple threads at once, but is internally serialized.
    • TContext3D: Supports being used from multiple threads at once, but is internally serialized

    Вот тут подробнее http://docwiki.embarcadero.com/RADStudio/Tokyo/en/What's_New#Multi-Threading_Support_for_TBitmap.2C_TCanvas_and_TContext3D

    Правда для большинства нововведений нет ни описания, ни примеров :

    Цитата

    Enhancements to TMultiView

    • Turn off user interaction with TMultiView using the Enabled property.
    • New options to manage border appearance in TMultiView. 
    • Bottom and top alignments for the docked panel mode in TMultiView.

    Последние два пункта из серии "Сами найдите и разберитесь"

  4. Наткнулся на еще один нюанс - подсчет высоты текста будет неверным для невидимого ListView. Т.е. если ListView еще не разу не был показан на экране (находится на другой форме, в другом табе), то AFontObject:=(AListView.FindStyleResource('font') as TFontObject) вернет хрен знает что. Для того чтоб заработало для еще невидимого ListView, необходимо перед добавлением Item, вернее перед AItem.Adapter.ResetView(AItem), выполнить ListView.ApplyStyleLookup;

    Добавлю в первую тему.

  5. 8 часов назад, Brovin Yaroslav сказал:

    Моя работа :) По просьбе трудящихся на этом форуме, сделал эту задачу. А еще добавил настройки, чтобы можно было линию убирать.

    Ярослав, а про линию можно подробнее? Это та которая вертикальная и всегда торчала в левом верхнем углу? Или что то другое? Для чего она вообще нужна была? Теперь ее действительно нет.

  6. В 23.03.2017 в 09:51, krapotkin сказал:

    вы точно уверены что простой запрос на соединение по порту 3306 не проходит?

    для туннеля инструкция например тут

    http://quintagroup.com/services/support/tutorials/mysql-linux

    У большинства хостингов, светить портом sql сервера наружу считается ересью, что в принципе правильно. Поэтому обычная практика - ssh туннель до хостера и внутри него соединение с sql. Вот хороший пример настройки на мастерхосте https://masterhost.ru/support/hosting/work-with-data/program/#MySQL-tunnel

    Илья, если вы хотите из приложения коннектится по ssh и подключаться к sql, то лучше этого не делать - вам придется распространять вместе с приложением ключи (или логин с паролем) ssh,и предрекаю что через неделю ваш хостинг будет рассылать спам и майнить криптовалюту для злых хакеров.

  7. 22 часа назад, SVTX сказал:

    Да я смотрел в эту сторону. Но пишут что у Китайских девайсов он одинаковый) не знаю насколько достоверна эта информация)

    Рекомендую при первом запуске генерировать GUID (System.SysUtils.CreateGUID), записывать в файл и использовать его. Привязка к железу это хорошо, но требует дополнительных разрешений, не понятных пользователю. И китайцы рано или поздно выпустят что то такое, где ваш код работать не будет.

  8. В 18.03.2017 в 16:52, rakhmet сказал:

    Чем в итоге всё закончилось?

    Руки так и не дошли попробовать... Когда дойдут не знаю, сейчас все время уходит на борьбу с роскомнадзором и его каталогом для извращенцев реестром запрещенных сайтов, я пытаюсь блокировать эти 66 тысяч сайтов, но если вдруг что упускаю, роскомнадзор штрафует меня на 40 тысяч рублей. Скоро придется ипотеку брать на оплату штрафов...

  9. Добавьте проверку на наличие файла. Ваш код выдает ошибку, но вы не знаете причину ошибки - отсутствие файла или ошибка в процессе LoadFromFile

      AFilePath:=System.IOutils.TPath.Combine(System.IOutils.TPath.GetDocumentsPath, 'Image_640x960.png');
      if TFile.Exists(AFilePath) then
        Image2.Bitmap.LoadFromFile(AFilePath)
      else
        ShowMessage('File not found');

     

  10. Тоже было подобное дублирование по причине указанной dante333. Костыль типа Kinvey не использовал, смысла использовать сторонний сервис, когда вопрос решается любым хостингом и двумя десятками строк на php? 

    Действительно при каждой установке создается новый токен. Вроде и при обновлении прошивки телефона новый токен и еще при нескольких условиях. По этой причине вставку в базу токена выполняю следующим запросом:

    INSERT INTO gcm_dixy (`DeviceID`, `DeviceToken`, `last_update`, `add_date`, `RequestCount`, `Active`) VALUES 
    ('$DeviceID','$DeviceToken', NOW(),NOW(), 1, 1) ON DUPLICATE KEY UPDATE 
    `DeviceToken` = '$DeviceToken', `last_update` = NOW(), `RequestCount` = `RequestCount` + 1, `Active` =  1

    Главное тут "ON DUPLICATE KEY UPDATE" , уникальный ключ в таблице - DeviceID, он никогда не меняется на устройстве.

    Видимо программистам из Kinvey не известен этот нюанс, вот глюк и всплывает.

  11. В 09.03.2017 в 20:08, Kitty сказал:

    Является ли нарушением такой вариант публикации?:

    Есть медицинский центр. Для медицинского центра созданы два приложения - одно для работников, второе для посетителей. Можно ли использовать в этих приложения одинаковые картинки (логотип, стартовая иконка). Одинаковые картинки в панели где надо указать 512x512 и 1024х500...

     

    Получите от медицинского центра разрешение на использование их логотипа. Можно на русском языке. Текст произвольный - поручаем Kitty изготовление приложения и разрешаем использование логотипов, торговых марок, фирменных наименований и т.д. в приложениях. 

    Подробнее здесь https://play.google.com/intl/ru/about/ip-deception-spam/impersonation-ip/ 

    И отправьте скан (pdf к примеру) этого письма в гугл, подробности тут https://support.google.com/googleplay/android-developer/answer/6320428

     

    Последнее время все сложнее публиковать приложения, правила уже балансируют на грани маразма. Одно моё приложение заблокировали по причине того что я "выдавал" себя за магазин линолиума в какой то немецкой деревушке - логотип приложения был немного искаженной зеркальной копией логотипа этого магазина, так же отличались цвета - у магазина желтый, у приложения оранжевый. Вот такие дела... 

    Так же сильно зависит от места модерации - если повезет попасть в британский офис, то вам досконально объяснят причину блокировки, приведут примеры правильного и не правильного решения вашего вопроса. Вот пример из моей практики:

    Цитата

    This is a notification that your application submission, TP-LINK Media Refresh, for package ID ru.flintnet.TPLinkMediaRefresh, has been rejected. If this submission was an update to an existing app, the version published prior to this update is still available on Google Play.
    Please address the issue described below, then submit an update with your changes.
    REASON FOR REJECTION: Violation of the spam provision of the Content Policy. Please refer to the keyword spam policy help article for more information.
    °    Do not use others' branding or product names at the start of your app title without permission. This implies association and is misleading for users. Instead, use "for [ product or brandinsert name ]." 
    °°    Incorrect: "Android MediaPlayer"
    °°    Correct: "MediaPlayer for Android"
    All submission rejections are tracked. Repeated rejections due to policy violations will result in app suspension, at which point this app will count as a strike against the good standing of your developer account and no longer be available on Google Play.

    Если не повезет попасть в подмосковье - то вы не получите комментариев, апелляция будет проигнорирована и относится к вам будут как к ничтожеству. Российская специфика - мальчик получивший работу в Великом Гугле, благодаря двоюродному дяде, сам становится Великим. И естественно он обязан быть гавном, так у него в должностной инструкции написано ;-)

  12. 10 часов назад, SerhioUser сказал:

    В общем работает так:

    WinExec("cmd /c aapt.exe dump badging path\\file.apk > text.txt", SW_HIDE);

    Запускается по тихому и создает text.txt, из которого можно выудить информацию о версии. Жаль, что нельзя этот файл получать напрямую в память, а не на диск - лишние операции, создающие тормоза.

    Вот так напрямую в память:

    function ShellExecuteMy(CommandLine: string; AWorkDir: string = 'C:\') : String;
    var
      SA: TSecurityAttributes;
      SI: TStartupInfo;
      PI: TProcessInformation;
      StdOutPipeRead, StdOutPipeWrite: THandle;
      WasOK: Boolean;
      Buffer: array[0..255] of AnsiChar;
      BytesRead: Cardinal;
      WorkDir: string;
      Handle: Boolean;
      AOutputLine : String;
    begin
      with SA do begin
        nLength := SizeOf(SA);
        bInheritHandle := True;
        lpSecurityDescriptor := nil;
      end;
      CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);
      try
        with SI do
        begin
          FillChar(SI, SizeOf(SI), 0);
          cb := SizeOf(SI);
          dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
          wShowWindow := SW_HIDE;
    //      wShowWindow := SW_MINIMIZE;
    //      wShowWindow := SW_NORMAL;
          hStdInput := GetStdHandle(STD_INPUT_HANDLE); // don't redirect stdin
          hStdOutput := StdOutPipeWrite;
          hStdError := StdOutPipeWrite;
        end;
        WorkDir := AWorkDir;
    //    Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CommandLine),
        Handle := CreateProcess(nil, PChar(CommandLine),
                                nil, nil, True, 0, nil,
                                PChar(WorkDir), SI, PI);
    //    Result:=PI;
        CloseHandle(StdOutPipeWrite);
      finally
        CloseHandle(StdOutPipeRead);
      end;
    
        if Handle then
          try
            repeat
    //          WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
              WasOK := ReadFile(StdOutPipeRead, Buffer, 50, BytesRead, nil);
              if BytesRead > 0 then
              begin
                Buffer[BytesRead] := #0;
                AOutputLine:=StrOemToAnsi(Buffer);
                Result :=Result + AOutputLine;
              end;
            until not WasOK or (BytesRead = 0);
            WaitForSingleObject(PI.hProcess, INFINITE);
          finally
            CloseHandle(PI.hThread);
            CloseHandle(PI.hProcess);
          end;
      finally
        CloseHandle(StdOutPipeRead);
      end;
    end;

    Функция читает пайп вывода и помещает в строку. 

    P.S. uses Winapi.Windows;

  13. При расчете высоты TListItemText приходилось использовать костыль - указывать размер шрифта отличный от 12 (например 12.01 и т.д.), если эти пренебречь, то расчет высоты не работал и текст или резался или высота итема оказывалась гораздо больше текста. Проблема в том, что на стадиях расчета высоты, к TListItemText еще не применен стиль, и параметры шрифта не соответствуют тому как будет выглядеть окончательный вариант на экране.

    Для правильного расчета высоты нужно выдернуть шрифт из стиля, делается это вот так:

    Var AFontObject : TFontObject;
        AListItemText : TListItemText;
    ...
      AListItemText:=TListItemText(AItem.View.FindDrawable(AName));
      if AListItemText=Nil then
        AListItemText:=TListItemText.Create(AItem);
      AFontObject:=(AListView.FindStyleResource('font') as TFontObject);
      if Assigned(AFontObject) then
        AListItemText.Font.Assign(AFontObject.Font);
    //Теперь вычисление высоты имеет смысл и не нужно задавать размер шрифта - он берется из стиля.
      AListItemText.Height:=CalculateHeight(AListItemText, AListView, FTextLayout);
    

    Или можно затолкать это действие в функцию вычисления высоты:

    function CalculateHeight(const AListItemText : TListItemText; const AListView : TListView; const FTextLayout : TTextLayout) : Single;
    Var AFontObject : TFontObject;
    begin
      FTextLayout.BeginUpdate;
      try
        FTextLayout.Text:=AListItemText.Text;
        FTextLayout.MaxSize:=TPointF.Create(AListItemText.Width, TTextLayout.MaxLayoutSize.Y);
        AFontObject:=(AListView.FindStyleResource('font') as TFontObject);
        if Assigned(AFontObject) then
          FTextLayout.Font.Assign(AFontObject.Font)
        else
          FTextLayout.Font.Assign(AListItemText.Font);
        FTextLayout.WordWrap:=AListItemText.WordWrap;
        FTextLayout.Trimming:=AListItemText.Trimming;
        FTextLayout.HorizontalAlign:=AListItemText.TextAlign;
        FTextLayout.VerticalAlign:=AListItemText.TextVertAlign;
      finally
        FTextLayout.EndUpdate;
      end;
    //  Result:=FTextLayout.Height * 1.4; // Теперь этот костыль не нужен
      Result:=FTextLayout.Height;
    end;

    Внимание! Если вы заполняете еще невидимый на экране ListView, не забудьте выполнить ListView.ApplyStyleLookup перед добавлением Items, иначе не получите правильный размер шрифта из стиля.

  14. Похоже я все победил! Вот код который отлично работает без костылей:

      function SetupTextObject(const AName, AText : String; AWidth, AHeight, X , Y : Single;
          AAlign, AVertAlign: TListItemAlign; ATextAlign, ATextVertAlign: TTextAlign) : TListItemText;
      begin
        Result:=TListItemText(AItem.View.FindDrawable(AName));
        if Result=Nil then
        begin
          Result:=TListItemText.Create(AItem);
        Result.Name:=AName;
        Result.Width:=AWidth;
        Result.Text:=AText;
        Result.PlaceOffset.X:=X;
        Result.PlaceOffset.Y:=Y;
        Result.Align:=AAlign;
        Result.VertAlign:=AVertAlign;
        Result.TextAlign:=ATextAlign;
        Result.TextVertAlign:=ATextVertAlign;
        if AHeight=-1 then
        begin
          if FListViewItemTextHeigh=-1 then
          begin
            // Ищем стилевой объект 'font' в ListView и присобачиваем его к нашему итему
            AFontObject:=(AListView.FindStyleResource('font') as TFontObject);
            if Assigned(AFontObject) then
              Result.Font.Assign(AFontObject.Font);
            FListViewItemTextHeigh:=GetTextHeight(Result, AWidth, AText);
            Result.Height:=FListViewItemTextHeigh;
          end
          else
            Result.Height:=FListViewItemTextHeigh;
        end
        else
          Result.Height:=AHeight;
        Result.Visible:=True;
        end;
      end;

    До применения шрифта из стиля Result.Font.Size=12, после Result.Font.Assign(AFontObject.Font) значение размера меняется на 18 - теперь высота рассчитывается корректно.

  15. Я наступил на те же грабли что и уважаемый HyperZen. Причем наступал я на эти грабли много раз раз, в каждой версии Delphi.

    Малюсенькое исправление решает проблему:

      function SetupTextObject(const AName, AText : String; AWidth, AHeight, X , Y : Single;
          AAlign, AVertAlign: TListItemAlign; ATextAlign, ATextVertAlign: TTextAlign) : TListItemText;
      begin
        Result:=TListItemText(AItem.View.FindDrawable(AName));
        if Result=Nil then
        begin
          Result:=TListItemText.Create(AItem);
        Result.Name:=AName;
        Result.Width:=AWidth;
    	//*********************************************************
        Result.Font.Size:=Result.Font.Size + 0.01; // Вот этот костыль заставляет все работать как задуманно.
    	//*********************************************************
        Result.Text:=AText;
        Result.PlaceOffset.X:=X;
        Result.PlaceOffset.Y:=Y;
        Result.Align:=AAlign;
        Result.VertAlign:=AVertAlign;
        Result.TextAlign:=ATextAlign;
        Result.TextVertAlign:=ATextVertAlign;
        if AHeight=-1 then
        begin
          if FListViewItemTextHeigh=-1 then // Так как везде один шрифт, то вычисляем высоту текста однократно
          begin
            FListViewItemTextHeigh:=GetTextHeight(Result, AWidth, AText);
            Result.Height:=FListViewItemTextHeigh;
          end
          else
            Result.Height:=FListViewItemTextHeigh;
        end
        else
          Result.Height:=AHeight;    
        end;
      end;

    Проблема в старинном глюке эмбаркадеровского ListView - вычисление высоты текста на этапе создания, или позднее не имеет смысла, потому как размер шрифта по умолчанию (обычно 12), перед отрисовкой превратиться во все что угодно, но не в 12, стиль применит свой размер шрифта и ваши расчеты высоты итема можно будет выкинуть. Победить глюк можно только установкой своего размера (обязательно отличного от 12 - цифра 12 "мудро" используется ембаркадерой как флаг означающий что можно применить стиль.

    Помню что задавал здесь этот вопрос не раз, но так и не получил ответа - как узнать размер шрифта из стиля, а не из FontSize????????????????!!!!!!!!!!!!!! Только с размерами шрифта из стиля имеет смысл расчитывать высоту.

    Даже в стандартых примерах эмбаркадыры этот скользкий момент старательно обходится и внимание на нем не концентрируется. Вот пример \Studio\18.0\Samples\Object Pascal\Multi-Device Samples\User Interface\ListView\VariableHeightItems:

        Drawable.Font.Size := 1; // Ensure that default font sizes do not play against us
        Drawable.Font.Size := 10 + Random(4) * 4;

    они делают хитро, вместо стандартный 12 пишут 1, а потом уже вписывают нужные значения. Если закомментировать эти две строчки (или написать Drawable.Font.Size := 12), то пример перестает работать, текст режется.

  16. 1 час назад, Равиль Зарипов (ZuBy) сказал:

    я уже стараюсь отойти от создания вручную объектов, есть же DynamicAppearance, все прекрасно работает и все шустро, никаких ресайзов не нужно делать

    У меня как раз DynamicAppearance, но в одном ListView должны быть разные итемы, вверху все просто Ключ-Значение, в транзакциях будут многострочные данные с разным цветом, зачеркиванием  и т.д.

    В этом случае без динамического создания не обойтись. Если бы дизайнер ListView умел делать несколько моделей итема, было бы хорошо. Но мечты-мечты...

  17. Берлин апдейт 2, Андроид. Сделал в своем приложении все по примеру уважаемого krapotkin. Но получил адовый писец. Для смеха записал видео:

    http://www.kayfolom.ru/2017_02_28_09_41_47.mp4

    Кнопка Refresh, в правом-верхнем углу, на самом деле выполняет Resize для ListView.

    ListView заполняется данными из нескольких json полученных с сервера, получается последовательное добавление секций. Вот пример заполнения одной из секций:

    procedure TFormMain.FillUserBalance(AJSON : TJSONObject);
    Var JSONValue : TJSONValue;
        I : Integer;
        AName, AValue : String;
        AItem : TListViewItem;
    begin
      if Not AJSON.TryGetValue('getuserbalance', JSONValue) then
        Exit;
      if Not JSONValue.TryGetValue('data', JSONValue) then
        Exit;
      AJSON:=JSONValue as TJSONObject;
      if Not Assigned(AJSON) then
        Exit;
      ListView.Items.Clear;
      AItem:=ListView.Items.Add;
      AItem.Purpose:=TListItemPurpose.Header;
      AItem.Text:='Balance ' + Setting.CurrentPool.Pool.Coin;
      for i := 0 to AJSON.Count-1 do
      begin
        AName:=AJSON.Pairs[I].JsonString.Value;
        if AJSON.TryGetValue(AName, JSONValue) Then
        begin
          FListViewUpdating:=True;
          AItem:=ListView.Items.Add;
          AItem.Data['Type']:='balance';
          AItem.Data['Name']:=AName;
          AValue:=JSONValue.Value;
          AItem.Data['Value']:=AValue;
          FListViewUpdating:=False;
          AItem.Adapter.ResetView(AItem);
        end;
      end;
    end;

    Создаю drawable в ListViewUpdatingObjects:

    procedure TFormMain.ListViewUpdatingObjects(const Sender: TObject;
      const AItem: TListViewItem; var AHandled: Boolean);
    Var AName, AValue, ADateAndTypeTransaction, AAmount, ATransactionOther, APaymentType  : TListItemText;
        AvailableWidth : single;
        AItemHeight : single;
        AItemType, ATransactionOtherString : String;
        S : String;
      function SetupTextObject(const AName, AText : String; AWidth, AHeight, X , Y : Single;
          AAlign, AVertAlign: TListItemAlign; ATextAlign, ATextVertAlign: TTextAlign) : TListItemText;
      begin
        Result:=TListItemText(AItem.View.FindDrawable(AName));
        if Result=Nil then
          Result:=TListItemText.Create(AItem);
        Result.Name:=AName;
        Result.Width:=AWidth;
        Result.Text:=AText;
        Result.PlaceOffset.X:=X;
        Result.PlaceOffset.Y:=Y;
        Result.Align:=AAlign;
        Result.VertAlign:=AVertAlign;
        Result.TextAlign:=ATextAlign;
        Result.TextVertAlign:=ATextVertAlign;
        if AHeight=-1 then
    //      Result.Height:=CalculateHeight(Result, Sender as TListView, FTextLayout)
          Result.Height:=GetTextHeight(Result, AWidth, AText)
        else
          Result.Height:=AHeight;
    //    Result.Visible:=True;
      end;
    begin
      if FListViewUpdating then  Exit;
      AvailableWidth:=TListView(Sender).Width - TListView(Sender).ItemSpaces.Left - TListView(Sender).ItemSpaces.Right;
    
      AItemType:=AItem.Data['Type'].AsString;
      if AItem.Purpose=TListItemPurpose.None Then
      begin
        if AItemType.Equals('balance') or AItemType.Equals('hashrate') or AItemType.Equals('worker')then
        begin
          AName:=SetupTextObject('Name', AItem.Data['Name'].AsString, AvailableWidth, -1, 0, 0,
            TListItemAlign.Leading, TListItemAlign.Leading, TTextAlign.Leading, TTextAlign.Leading);
          AItemHeight:=AName.Height;
          if AItem.Data['Type'].AsString='worker' then
          begin
            if AItem.Data['Value'].AsString.Equals('0') Then
              AName.TextColor:=TAlphaColorRec.Red
            else
              AName.TextColor:=TAlphaColorRec.Green;
          end;
          AValue:=SetupTextObject('Value', AItem.Data['Value'].AsString, AvailableWidth, -1, 0, 0,
            TListItemAlign.Trailing, TListItemAlign.Leading, TTextAlign.Trailing, TTextAlign.Leading);
          AItem.Height:=Round(AItemHeight + (Sender as TListView).ItemSpaces.Top +
            (Sender as TListView).ItemSpaces.Bottom);
        end;
    
        if AItem.Data['Type'].AsString='Transaction' then
        begin
          ADateAndTypeTransaction:=SetupTextObject('DateAndTypeTransaction',
            AItem.Data['Date'].AsString + ' ' + AItem.Data['TransactionType'].AsString,
            AvailableWidth, -1, 0, 0,
            TListItemAlign.Leading, TListItemAlign.Leading, TTextAlign.Leading, TTextAlign.Leading);
    
          AItemHeight:=ADateAndTypeTransaction.Height;
    
          AAmount:=SetupTextObject('Amount',
            AItem.Data['Amount'].AsString,
            AvailableWidth, -1, 0, 0,
            TListItemAlign.Trailing, TListItemAlign.Leading, TTextAlign.Trailing, TTextAlign.Leading);
    
          ATransactionOtherString:='';
          if Not AItem.Data['AmountFee'].AsString.IsEmpty then
            ATransactionOtherString:=ATransactionOtherString + 'Fee ' + AItem.Data['AmountFee'].AsString + ' ';
          if Not AItem.Data['AmountDonation'].AsString.IsEmpty then
            ATransactionOtherString:=ATransactionOtherString + 'Donat ' + AItem.Data['AmountDonation'].AsString + ' ';
          if Not AItem.Data['Confirmations'].AsString.IsEmpty then
            ATransactionOtherString:=ATransactionOtherString + 'Confirm ' + AItem.Data['Confirmations'].AsString;
    
          ATransactionOther:=SetupTextObject('TransactionOther', ATransactionOtherString,
            AvailableWidth, -1, 0, AItemHeight,
            TListItemAlign.Leading, TListItemAlign.Leading, TTextAlign.Leading, TTextAlign.Leading);
    
          AItem.Height:=Round(AItemHeight + ATransactionOther.Height +
            (Sender as TListView).ItemSpaces.Top + (Sender as TListView).ItemSpaces.Bottom);
          S:=AItem.Data['TransactionType'].AsString;
          if AItem.Data['TransactionType'].AsString.Contains('Debit') then
            AAmount.TextColor:=TAlphaColorRec.Blue;
          if AItem.Data['TransactionType'].AsString.Contains('Credit') then
            AAmount.TextColor:=TAlphaColorRec.Green;
        end;
        AHandled:=True;
      end;
    end;

    В итоге: все работает на порядок медленнее чем вариант с созданием drawable сразу, при заполнении данных. Для нормального подсчета высоты итемов помогает только Resize, и то только для видимых итемов.

    Под виндой все работает хорошо. Под андроид так как на видео.

  18. 36 минут назад, Andrey Efimov сказал:

    Только ещё не помешает мониторить перезагрузку телефона. А то пользователь перезагрузит устройство и всё, сломается его мониторинг (до момента пока он не перезапустит мониторинг)... Это если хочется почти нон-стоп и в автоматическом режиме.

    С этим согласен. Но тут нужен java класс, компиляция его в jar, подключение jar к проекту - вот на это все у меня жуткая аллергия. Вчера пытался воспользоваться вашим bat-файлом, потом просто отдельными строками, в итоге психанул и все удалил :-) Особенно тяжело мне дается неясная необходимость во вложенных папках для класса, не понятно в какой именно папке запускать javac. Понимаю что создатели java любили линукс, и там засранные тысячами файлов папки, чудовищная иерархия вложенных папок и прочие чудеса считаются нормой. Но я воспитан в строгости и порядке, для меня в порядке вещей если исполняемый файл сам выясняет из какой папки был запущен и где искать свои *.ini, *.cfg, библиотеки и подобные файлы. 

    Сейчас буду бороться с задвоенными вызовами будильника, видимо не до конца понимаю принципы работы сервиса в андроиде. AlarmManager вроде не при чем, в документации сказано что нельзя создать два одинаковых будильника на одно время. Или мне все же это удалось :-)

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