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