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

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

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

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

  • Посещение

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

    100

Весь контент Евгений Корепов

  1. Пытаюсь приручить THTTPClient в асинхронном режиме работы. Все работает чудесно, в некоторых проектах смело выкидывается значительная часть кода - потоки, очереди, таймеры и прочее. Но столкнулся с проблемой - есть десяток TImage, в которые нужно загрузить картинки скачанные по http (классическая задача с TListView к примеру). Вроде все хорошо, кроме идентификации закачанных картинок, закачка может завершится не в той последовательности, в которой она производилась, т.е. делаю десять вызовов FHTTPClient.BeginGet(DoEndDownload, URL, FDownloadStream), а в процедуре DoEndDownload получаю скачанную в FDownloadStream картинку. Как узнать к какому TImage относится скачанная картинка?
  2. Ошибся, правильно AllowSelection. А лучше приложите тестовый проект, так проще будет выяснить причину
  3. Проверьте свойства ListView - Selectable (вроде так называется)
  4. Кроме этого в TMultiView починили еще этот глюк - внимание в левую часть скриншота, эта вертикальная линия видна всегда, выглядит чудовищно уродски На втором скриншоте тоже приложение в Токио, никаких изменений не производилось, проект открыт как есть.
  5. Вроде нормально все, один из проектов перенес уже - впечатления пока положительные. Там что то с потоками UI изменения, вместо двух потоков (java и delphi) теперь один поток UI. Плюс куча плюшек по упрощению работы в потоках - вроде как TBitmap (и что то еще) можно без синхронизации изменять в разных потоках: Вот тут подробнее http://docwiki.embarcadero.com/RADStudio/Tokyo/en/What's_New#Multi-Threading_Support_for_TBitmap.2C_TCanvas_and_TContext3D Правда для большинства нововведений нет ни описания, ни примеров : Последние два пункта из серии "Сами найдите и разберитесь"
  6. Прозевал сегодня вебинар "Что нового в XE10.2 Tokyo", может есть у кого запись? Буду безмерно благодарен!
  7. Наткнулся на еще один нюанс - подсчет высоты текста будет неверным для невидимого ListView. Т.е. если ListView еще не разу не был показан на экране (находится на другой форме, в другом табе), то AFontObject:=(AListView.FindStyleResource('font') as TFontObject) вернет хрен знает что. Для того чтоб заработало для еще невидимого ListView, необходимо перед добавлением Item, вернее перед AItem.Adapter.ResetView(AItem), выполнить ListView.ApplyStyleLookup; Добавлю в первую тему.
  8. Версия fgx_0.7.1.118.zip нормально работает в Токио. Досконально не проверял, но явных глюков не замечено.
  9. Ярослав, а про линию можно подробнее? Это та которая вертикальная и всегда торчала в левом верхнем углу? Или что то другое? Для чего она вообще нужна была? Теперь ее действительно нет.
  10. Починили TMultiView.Enable в Tokyo, вот небольшой видео-пример: https://www.youtube.com/watch?v=T0gJwfiyRyY
  11. У большинства хостингов, светить портом sql сервера наружу считается ересью, что в принципе правильно. Поэтому обычная практика - ssh туннель до хостера и внутри него соединение с sql. Вот хороший пример настройки на мастерхосте https://masterhost.ru/support/hosting/work-with-data/program/#MySQL-tunnel Илья, если вы хотите из приложения коннектится по ssh и подключаться к sql, то лучше этого не делать - вам придется распространять вместе с приложением ключи (или логин с паролем) ssh,и предрекаю что через неделю ваш хостинг будет рассылать спам и майнить криптовалюту для злых хакеров.
  12. Рекомендую при первом запуске генерировать GUID (System.SysUtils.CreateGUID), записывать в файл и использовать его. Привязка к железу это хорошо, но требует дополнительных разрешений, не понятных пользователю. И китайцы рано или поздно выпустят что то такое, где ваш код работать не будет.
  13. Руки так и не дошли попробовать... Когда дойдут не знаю, сейчас все время уходит на борьбу с роскомнадзором и его каталогом для извращенцев реестром запрещенных сайтов, я пытаюсь блокировать эти 66 тысяч сайтов, но если вдруг что упускаю, роскомнадзор штрафует меня на 40 тысяч рублей. Скоро придется ипотеку брать на оплату штрафов...
  14. Добавьте проверку на наличие файла. Ваш код выдает ошибку, но вы не знаете причину ошибки - отсутствие файла или ошибка в процессе 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');
  15. Тоже было подобное дублирование по причине указанной 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 не известен этот нюанс, вот глюк и всплывает.
  16. Получите от медицинского центра разрешение на использование их логотипа. Можно на русском языке. Текст произвольный - поручаем Kitty изготовление приложения и разрешаем использование логотипов, торговых марок, фирменных наименований и т.д. в приложениях. Подробнее здесь https://play.google.com/intl/ru/about/ip-deception-spam/impersonation-ip/ И отправьте скан (pdf к примеру) этого письма в гугл, подробности тут https://support.google.com/googleplay/android-developer/answer/6320428 Последнее время все сложнее публиковать приложения, правила уже балансируют на грани маразма. Одно моё приложение заблокировали по причине того что я "выдавал" себя за магазин линолиума в какой то немецкой деревушке - логотип приложения был немного искаженной зеркальной копией логотипа этого магазина, так же отличались цвета - у магазина желтый, у приложения оранжевый. Вот такие дела... Так же сильно зависит от места модерации - если повезет попасть в британский офис, то вам досконально объяснят причину блокировки, приведут примеры правильного и не правильного решения вашего вопроса. Вот пример из моей практики: Если не повезет попасть в подмосковье - то вы не получите комментариев, апелляция будет проигнорирована и относится к вам будут как к ничтожеству. Российская специфика - мальчик получивший работу в Великом Гугле, благодаря двоюродному дяде, сам становится Великим. И естественно он обязан быть гавном, так у него в должностной инструкции написано ;-)
  17. Вот так напрямую в память: 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;
  18. При расчете высоты 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, иначе не получите правильный размер шрифта из стиля.
  19. Похоже я все победил! Вот код который отлично работает без костылей: 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 - теперь высота рассчитывается корректно.
  20. Я наступил на те же грабли что и уважаемый 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), то пример перестает работать, текст режется.
  21. To hide individual item is better to use the filtering feature TListView.ListViewFilter(Sender: TObject; const AFilter, AValue: string; var Accept: Boolean);
  22. Скрывать можно - с помощью фильтрации.
  23. У меня как раз DynamicAppearance, но в одном ListView должны быть разные итемы, вверху все просто Ключ-Значение, в транзакциях будут многострочные данные с разным цветом, зачеркиванием и т.д. В этом случае без динамического создания не обойтись. Если бы дизайнер ListView умел делать несколько моделей итема, было бы хорошо. Но мечты-мечты...
  24. Берлин апдейт 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, и то только для видимых итемов. Под виндой все работает хорошо. Под андроид так как на видео.
  25. С этим согласен. Но тут нужен java класс, компиляция его в jar, подключение jar к проекту - вот на это все у меня жуткая аллергия. Вчера пытался воспользоваться вашим bat-файлом, потом просто отдельными строками, в итоге психанул и все удалил :-) Особенно тяжело мне дается неясная необходимость во вложенных папках для класса, не понятно в какой именно папке запускать javac. Понимаю что создатели java любили линукс, и там засранные тысячами файлов папки, чудовищная иерархия вложенных папок и прочие чудеса считаются нормой. Но я воспитан в строгости и порядке, для меня в порядке вещей если исполняемый файл сам выясняет из какой папки был запущен и где искать свои *.ini, *.cfg, библиотеки и подобные файлы. Сейчас буду бороться с задвоенными вызовами будильника, видимо не до конца понимаю принципы работы сервиса в андроиде. AlarmManager вроде не при чем, в документации сказано что нельзя создать два одинаковых будильника на одно время. Или мне все же это удалось :-)
×
×
  • Создать...