-
Постов
568 -
Зарегистрирован
-
Посещение
-
Победитель дней
57
Активность репутации
-
ENERGY отреагировална sinuke в Что невозможно сделать на Delphi для Android?
продублирую сюда свое "исследование"
-
ENERGY отреагировална sinuke в Что невозможно сделать на Delphi для Android?
Про память возможно и не точно. Я в чатике проводил "исследование" месяца 1,5 назад...
-
ENERGY получил реакцию от Евгений Корепов в Как нарисовать круглый TImage
С помощью маски можно любую форму.TBitmap.CreateFromBitmapAndMask().
В результате получим изображение с прозрачностью, в данном случае звезда и прозрачный фон.
procedure TForm1.Button1Click(Sender: TObject); var ImageRes: TResourceStream; Result: TBitmap; tmpMS : TMemoryStream; begin ImageRes := TResourceStream.Create(HInstance, 'IMAGE', RT_RCDATA); try Image1.Bitmap.CreateFromStream(ImageRes); Image2.Bitmap.LoadFromFile('c:\temp\MaskedBitmap\Images\Mask.png'); Result := TBitmap.Create; Result.CreateFromBitmapAndMask(Image1.Bitmap, Image2.Bitmap); // applying alpha channel to Bitmap - workaround. If you can improve write here how tmpMS := TMemoryStream.Create; Result.SaveToStream(tmpMS); Result.LoadFromStream(tmpMS); tmpMS.Free; Image3.Bitmap.Assign(Result); finally ImageRes.Free; Result.Free; end; end;
MaskedBitmap.zip
-
ENERGY получил реакцию от Alex7wrt в Как нарисовать круглый TImage
С помощью маски можно любую форму.TBitmap.CreateFromBitmapAndMask().
В результате получим изображение с прозрачностью, в данном случае звезда и прозрачный фон.
procedure TForm1.Button1Click(Sender: TObject); var ImageRes: TResourceStream; Result: TBitmap; tmpMS : TMemoryStream; begin ImageRes := TResourceStream.Create(HInstance, 'IMAGE', RT_RCDATA); try Image1.Bitmap.CreateFromStream(ImageRes); Image2.Bitmap.LoadFromFile('c:\temp\MaskedBitmap\Images\Mask.png'); Result := TBitmap.Create; Result.CreateFromBitmapAndMask(Image1.Bitmap, Image2.Bitmap); // applying alpha channel to Bitmap - workaround. If you can improve write here how tmpMS := TMemoryStream.Create; Result.SaveToStream(tmpMS); Result.LoadFromStream(tmpMS); tmpMS.Free; Image3.Bitmap.Assign(Result); finally ImageRes.Free; Result.Free; end; end;
MaskedBitmap.zip
-
ENERGY получил реакцию от Tumaso в Как нарисовать круглый TImage
С помощью маски можно любую форму.TBitmap.CreateFromBitmapAndMask().
В результате получим изображение с прозрачностью, в данном случае звезда и прозрачный фон.
procedure TForm1.Button1Click(Sender: TObject); var ImageRes: TResourceStream; Result: TBitmap; tmpMS : TMemoryStream; begin ImageRes := TResourceStream.Create(HInstance, 'IMAGE', RT_RCDATA); try Image1.Bitmap.CreateFromStream(ImageRes); Image2.Bitmap.LoadFromFile('c:\temp\MaskedBitmap\Images\Mask.png'); Result := TBitmap.Create; Result.CreateFromBitmapAndMask(Image1.Bitmap, Image2.Bitmap); // applying alpha channel to Bitmap - workaround. If you can improve write here how tmpMS := TMemoryStream.Create; Result.SaveToStream(tmpMS); Result.LoadFromStream(tmpMS); tmpMS.Free; Image3.Bitmap.Assign(Result); finally ImageRes.Free; Result.Free; end; end;
MaskedBitmap.zip
-
ENERGY получил реакцию от Равиль Зарипов (ZuBy) в Как нарисовать круглый TImage
С помощью маски можно любую форму.TBitmap.CreateFromBitmapAndMask().
В результате получим изображение с прозрачностью, в данном случае звезда и прозрачный фон.
procedure TForm1.Button1Click(Sender: TObject); var ImageRes: TResourceStream; Result: TBitmap; tmpMS : TMemoryStream; begin ImageRes := TResourceStream.Create(HInstance, 'IMAGE', RT_RCDATA); try Image1.Bitmap.CreateFromStream(ImageRes); Image2.Bitmap.LoadFromFile('c:\temp\MaskedBitmap\Images\Mask.png'); Result := TBitmap.Create; Result.CreateFromBitmapAndMask(Image1.Bitmap, Image2.Bitmap); // applying alpha channel to Bitmap - workaround. If you can improve write here how tmpMS := TMemoryStream.Create; Result.SaveToStream(tmpMS); Result.LoadFromStream(tmpMS); tmpMS.Free; Image3.Bitmap.Assign(Result); finally ImageRes.Free; Result.Free; end; end;
MaskedBitmap.zip
-
ENERGY получил реакцию от FREEFAR в Как нарисовать круглый TImage
С помощью маски можно любую форму.TBitmap.CreateFromBitmapAndMask().
В результате получим изображение с прозрачностью, в данном случае звезда и прозрачный фон.
procedure TForm1.Button1Click(Sender: TObject); var ImageRes: TResourceStream; Result: TBitmap; tmpMS : TMemoryStream; begin ImageRes := TResourceStream.Create(HInstance, 'IMAGE', RT_RCDATA); try Image1.Bitmap.CreateFromStream(ImageRes); Image2.Bitmap.LoadFromFile('c:\temp\MaskedBitmap\Images\Mask.png'); Result := TBitmap.Create; Result.CreateFromBitmapAndMask(Image1.Bitmap, Image2.Bitmap); // applying alpha channel to Bitmap - workaround. If you can improve write here how tmpMS := TMemoryStream.Create; Result.SaveToStream(tmpMS); Result.LoadFromStream(tmpMS); tmpMS.Free; Image3.Bitmap.Assign(Result); finally ImageRes.Free; Result.Free; end; end;
MaskedBitmap.zip
-
ENERGY получил реакцию от Ingalime в Как нарисовать круглый TImage
С помощью маски можно любую форму.TBitmap.CreateFromBitmapAndMask().
В результате получим изображение с прозрачностью, в данном случае звезда и прозрачный фон.
procedure TForm1.Button1Click(Sender: TObject); var ImageRes: TResourceStream; Result: TBitmap; tmpMS : TMemoryStream; begin ImageRes := TResourceStream.Create(HInstance, 'IMAGE', RT_RCDATA); try Image1.Bitmap.CreateFromStream(ImageRes); Image2.Bitmap.LoadFromFile('c:\temp\MaskedBitmap\Images\Mask.png'); Result := TBitmap.Create; Result.CreateFromBitmapAndMask(Image1.Bitmap, Image2.Bitmap); // applying alpha channel to Bitmap - workaround. If you can improve write here how tmpMS := TMemoryStream.Create; Result.SaveToStream(tmpMS); Result.LoadFromStream(tmpMS); tmpMS.Free; Image3.Bitmap.Assign(Result); finally ImageRes.Free; Result.Free; end; end;
MaskedBitmap.zip
-
ENERGY отреагировална #WAMACO в Что невозможно сделать на Delphi для Android?
Сравнивать RAD надо не с нативными студиями разработки, а с Xamarin, например, там вообще тихий ужас...
Есть 1С:Мобильная платформа, там тоже можно собирать под Android, iOS - правда все в желтом цвете (про toolbar), но знаю людей, кто на этом столько денег заработал, что авторы нативных приложений и не видели еще...
Дело в направленности приложений и ДА, некоторые типы приложений (например, корпоративные) делаются быстрее.
Не надо рисовать виджет погоды на Delphi, не надо делать путеводитель по сортам кофе на Delphi. Делайте это нативными инструментами.
Востребованность в кроссплатформе есть и эта тенденция будет только усиливаться.
Сейчас это напоминает мне разговор в 1998 году о том, что все ПО под Windows надо писать на C++, потому что на других языках - НЕ НАТИВНО, МЕДЛЕННО РАБОТАЕТ, ПОДВИСАЕТ!
А потом, я пришел в одну контору и руководство провозгласило: ТОРМОЗИТ? Добавьте Гигагерц и ОЗУ - это дешевле и быстрее, нежели переписывать на нативных языках! Так вот, со временем так же будет и с мобилами! и уже очень скоро!
НЕ РАБОТАЕТ НА КИТАЙСКИХ СМАРТФОНАХ? выбросьте их и купите уже нормальные аппараты! это дешевле, нежели платить Kotlin разрабу!
-
ENERGY получил реакцию от FREEFAR в Что невозможно сделать на Delphi для Android?
Да конечно можно сделать красиво на FMX. просто народу влом разбираться с дизайном.
Тем более Android стиль сам по себе очень упрощен - прямоугольные кнопки, плоские иконки, минимум деталей.
-
ENERGY отреагировална FREEFAR в Что невозможно сделать на Delphi для Android?
Про красиво - вот наш прототип. Более менее UFriendly
-
ENERGY отреагировална FREEFAR в Что невозможно сделать на Delphi для Android?
А что на фмх нельзя сделать красиво ?
-
ENERGY получил реакцию от МихаилЪ чайковЪ в Что невозможно сделать на Delphi для Android?
Нет как раз таки. Berlin Update 2 более стабильный и там меньше багов FMX чем в Tokyo. В Токио от одного бага со сменой главного потока целая эпопея, с потерей производительности и проблем с анимацией - много что посыпалось. Была, а может еще и будет. Некоторые программисты с форума EMBT вообще считают Токио самой неудачной версией Delphi, в плане багов за всю ее историю.
-
ENERGY получил реакцию от AngryOwl в Что невозможно сделать на Delphi для Android?
Нет как раз таки. Berlin Update 2 более стабильный и там меньше багов FMX чем в Tokyo. В Токио от одного бага со сменой главного потока целая эпопея, с потерей производительности и проблем с анимацией - много что посыпалось. Была, а может еще и будет. Некоторые программисты с форума EMBT вообще считают Токио самой неудачной версией Delphi, в плане багов за всю ее историю.
-
ENERGY получил реакцию от Равиль Зарипов (ZuBy) в Что невозможно сделать на Delphi для Android?
Нет как раз таки. Berlin Update 2 более стабильный и там меньше багов FMX чем в Tokyo. В Токио от одного бага со сменой главного потока целая эпопея, с потерей производительности и проблем с анимацией - много что посыпалось. Была, а может еще и будет. Некоторые программисты с форума EMBT вообще считают Токио самой неудачной версией Delphi, в плане багов за всю ее историю.
-
ENERGY отреагировална Andrey Efimov в Что невозможно сделать на Delphi для Android?
Не обманывай людей . Это что: procedure onReceivePermissionsResult(const ASender: TObject; const AMessage: TMessage); ?
-
ENERGY получил реакцию от AngryOwl в Двигать объект по окружности (кругу) - Moving an object in a circular path
X := originX + cos(angle)*radius;
Y := originY + sin(angle)*radius;
-
ENERGY получил реакцию от Ingalime в Поиск контакта по номеру
Большое Вам спасибо Ярослав, за то что вносите большой вклад в развитие Mobile Delphi. Очень мало примеров и документации (причем на любом языке) по этому поводу, ваш сайт очень выручает.
Я попробовал демку c:\Program Files (x86)\Embarcadero\Studio\18.0\Samples\Object Pascal\Multi-Device Samples\Device Sensors and Services\Address Book\Contacts\Contacts_Delphi.dproj с TAddressBook .
Delphi 10 upd 1
Запускал на телефоне HTC - ни один контакт не загрузился - просто пустой список.
UPD: Вместо AddressBook1.AllContacts(Source, Contacts);
Нужно AddressBook1.AllContacts(nil, Contacts); тогда загружает все контакты.
Вся проблема в том, что он считывает сразу все контакты. А мне это не нужно.
Лучше использовать код для поиска конкретного номера, прекрасно находит работает (также работает и вставка нового контакта, здесь описал http://stackoverflow.com/questions/29782398/insert-contacts-in-android-with-delphi/41294891#41294891):
function TCore.IsNumberInAddressBook(const aNumber: string): boolean; var vCursor: JCursor; vQueryStr: string; begin Result := false; // will be: data1 LIKE '%+380501960000%' (with quotes) vQueryStr := JStringToString( TJCommonDataKinds_Phone.JavaClass.NORMALIZED_NUMBER) + ' LIKE ''%' + aNumber + '%'''; vCursor := TAndroidHelper.Activity.getContentResolver.query( TJCommonDataKinds_Phone.JavaClass.CONTENT_URI, nil, //projection String: A list of which columns to return. Passing null will return all columns, which is inefficient. StringToJString(vQueryStr), // String: A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI. nil, nil); // Query help: https://developer.android.com/reference/android/content/ContentResolver.html#query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) if vCursor <> nil then try Result := vCursor.getCount > 0; finally vCursor.close; end; end; // а это может пригодится while (cursor.moveToNext) do begin lbContactsList.Text := JStringToString(cursor.getString( cursor.getColumnIndex(StringToJString('DISPLAY_NAME')))); lbContactsList.Tag := cursor.getInt(cursor.getColumnIndex(StringToJString('_ID'))); // ListBox1.AddObject(ListBoxItem); end;
UPD: AllContacts находится в \source\fmx\FMX.AddressBook.Android.pas
А вообще для самообразования хотелось бы узнать как вызвать ContactsContract.PhoneLookup.CONTENT_FILTER_URI
И что это за конструкция такая Uri.withAppendedPath, ведь в будущем наверняка с ней придется сталкиваться. Если вы в курсе, расскажите пожалуйста.
-
ENERGY получил реакцию от x11 в [Статья]Как создать простой Android Broadcast Receiver. How to implement simplest Android Broadcast Receiver in Delphi
Мой вариант Broadcast Receiver, на мой взгляд наиболее оптимизирован и удачен. По сравнению с известным кодом от barisatalay .
Отличия -
исправлена утечка,
чуть быстрее работает, за счет того что создается один фильтр в него добавляется несколько Actions и одна регистрация на него,
нет лишних конвертирований с Jstring to string и обратно,
адаптирован под Delphi 10 (JFMXBroadcastReceiver) ,
упрощена работа с классом (не нужно помнить о регистрации и вызывать ее заранее) ,
и самое главное - может получать getResultCode текущего ресивера (к примеру он нужен при получении статуса смс сообщения и в других случаях.).
unit BroadcastReceiver; interface {$IFDEF ANDROID} uses Androidapi.JNI.Embarcadero, Androidapi.JNI.GraphicsContentViewText, Androidapi.helpers, Androidapi.JNIBridge, FMX.Helpers.Android, Androidapi.JNI.JavaTypes, System.Classes, System.SysUtils; type TBroadcastReceiver = class; TListener = class(TJavaLocal, JFMXBroadcastReceiverListener) private fOwner: TBroadcastReceiver; fReceiver: JFMXBroadcastReceiver; public constructor Create(aOwner: TBroadcastReceiver); destructor Destroy; override; procedure onReceive(context: JContext; intent: JIntent); cdecl; end; TOnReceive = procedure (aContext: JContext; aIntent: JIntent; aResultCode: integer) of object; TBroadcastReceiver = class private fListener : TListener; fRegistered: boolean; fOnReceive: TOnReceive; public constructor Create(aOnReceiveProc: TOnReceive); destructor Destroy; override; procedure AddActions(const Args: array of JString); procedure SendBroadcast(const aValue: string); end; {$ENDIF} implementation {$IFDEF ANDROID} { TBroadcastReceiver } constructor TBroadcastReceiver.Create(aOnReceiveProc: TOnReceive); begin inherited Create; fListener := TListener.Create(Self); fOnReceive := aOnReceiveProc; end; destructor TBroadcastReceiver.Destroy; begin fListener.Free; inherited; end; procedure TBroadcastReceiver.AddActions(const Args: array of JString); var vFilter: JIntentFilter; i: Integer; begin if fRegistered then TAndroidHelper.context.getApplicationContext.UnregisterReceiver(fListener.fReceiver); vFilter := TJIntentFilter.JavaClass.init; for i := 0 to High(Args) do vFilter.addAction(Args[i]); TAndroidHelper.context.getApplicationContext.registerReceiver(fListener.fReceiver, vFilter); fRegistered := true; end; procedure TBroadcastReceiver.SendBroadcast(const aValue: string); var Inx: JIntent; begin Inx := TJIntent.Create; Inx.setAction(StringToJString(aValue)); TAndroidHelper.Context.sendBroadcast(Inx); end; constructor TListener.Create(aOwner: TBroadcastReceiver); begin inherited Create; fOwner := aOwner; fReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self); end; destructor TListener.Destroy; begin TAndroidHelper.context.getApplicationContext.unregisterReceiver(fReceiver); inherited; end; // usually android call it from "UI thread" - it's not main Delphi thread procedure TListener.onReceive(context: JContext; intent: JIntent); begin if Assigned(fOwner.fOnReceive) then fOwner.fOnReceive(Context, Intent, fReceiver.getResultCode); end; {$ENDIF} end.
Как использовать
// указывать нужно сразу все нужные вам Actions в Add через запятую, не по одной. fBroadcast := TBroadcastReceiver.Create(OnReceiveBroadcast); fBroadcast.AddActions([StringToJString(SENT_ACTION)]); << Custom action ------------- // или например сразу несколько Actions fBroadcast.AddActions([TJIntent.JavaClass.ACTION_SCREEN_OFF, TJIntent.JavaClass.ACTION_SCREEN_ON]);
-
ENERGY получил реакцию от Ingalime в [Статья]Как создать простой Android Broadcast Receiver. How to implement simplest Android Broadcast Receiver in Delphi
Как создать простейший Android Broadcast Receiver.
Создайте класс, для приема Intent уведомлений:
uses Androidapi.JNIBridge, Androidapi.JNI.Embarcadero, Androidapi.JNI.GraphicsContentViewText; type TMyReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener) public constructor Create; procedure onReceive(context: JContext; intent: JIntent); cdecl; end; uses Androidapi.Helpers, Androidapi.JNI.JavaTypes; { TMyReceiver } constructor TMyReceiver.Create; begin inherited; end; procedure TMyReceiver.onReceive(context: JContext; intent: JIntent); begin Log.d('Broadcast Received = ' + JStringToString(intent.getAction)); end;
Регистрируем тип уведомлений и приемник в событиях формы:
type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { private } FMyListener: TMyReceiver; FBroadcastReceiver: JFMXBroadcastReceiver; public { public } end; procedure TForm1.FormCreate(Sender: TObject); var Filter: JIntentFilter; begin FMyListener := TMyReceiver.Create; FBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(FMyListener); Filter := TJIntentFilter.JavaClass.init; Filter.addAction(TJIntent.JavaClass.ACTION_SCREEN_OFF); Filter.addAction(TJIntent.JavaClass.ACTION_SCREEN_ON); TAndroidHelper.context.getApplicationContext.registerReceiver (FBroadcastReceiver, Filter); end; procedure TForm1.FormDestroy(Sender: TObject); begin TAndroidHelper.context.getApplicationContext.unregisterReceiver (FBroadcastReceiver); end; Все.
Теперь когда вы запустите программу и выключите\включите экран, лог покажет :
FMX: BroadcastSample: Broadcast Received = android.intent.action.SCREEN_OFF FMX: BroadcastSample: Broadcast Received = android.intent.action.SCREEN_ON Takashi Yamamoto
-
ENERGY получил реакцию от Виталий Иванов в [Статья]Как создать простой Android Broadcast Receiver. How to implement simplest Android Broadcast Receiver in Delphi
Мой вариант Broadcast Receiver, на мой взгляд наиболее оптимизирован и удачен. По сравнению с известным кодом от barisatalay .
Отличия -
исправлена утечка,
чуть быстрее работает, за счет того что создается один фильтр в него добавляется несколько Actions и одна регистрация на него,
нет лишних конвертирований с Jstring to string и обратно,
адаптирован под Delphi 10 (JFMXBroadcastReceiver) ,
упрощена работа с классом (не нужно помнить о регистрации и вызывать ее заранее) ,
и самое главное - может получать getResultCode текущего ресивера (к примеру он нужен при получении статуса смс сообщения и в других случаях.).
unit BroadcastReceiver; interface {$IFDEF ANDROID} uses Androidapi.JNI.Embarcadero, Androidapi.JNI.GraphicsContentViewText, Androidapi.helpers, Androidapi.JNIBridge, FMX.Helpers.Android, Androidapi.JNI.JavaTypes, System.Classes, System.SysUtils; type TBroadcastReceiver = class; TListener = class(TJavaLocal, JFMXBroadcastReceiverListener) private fOwner: TBroadcastReceiver; fReceiver: JFMXBroadcastReceiver; public constructor Create(aOwner: TBroadcastReceiver); destructor Destroy; override; procedure onReceive(context: JContext; intent: JIntent); cdecl; end; TOnReceive = procedure (aContext: JContext; aIntent: JIntent; aResultCode: integer) of object; TBroadcastReceiver = class private fListener : TListener; fRegistered: boolean; fOnReceive: TOnReceive; public constructor Create(aOnReceiveProc: TOnReceive); destructor Destroy; override; procedure AddActions(const Args: array of JString); procedure SendBroadcast(const aValue: string); end; {$ENDIF} implementation {$IFDEF ANDROID} { TBroadcastReceiver } constructor TBroadcastReceiver.Create(aOnReceiveProc: TOnReceive); begin inherited Create; fListener := TListener.Create(Self); fOnReceive := aOnReceiveProc; end; destructor TBroadcastReceiver.Destroy; begin fListener.Free; inherited; end; procedure TBroadcastReceiver.AddActions(const Args: array of JString); var vFilter: JIntentFilter; i: Integer; begin if fRegistered then TAndroidHelper.context.getApplicationContext.UnregisterReceiver(fListener.fReceiver); vFilter := TJIntentFilter.JavaClass.init; for i := 0 to High(Args) do vFilter.addAction(Args[i]); TAndroidHelper.context.getApplicationContext.registerReceiver(fListener.fReceiver, vFilter); fRegistered := true; end; procedure TBroadcastReceiver.SendBroadcast(const aValue: string); var Inx: JIntent; begin Inx := TJIntent.Create; Inx.setAction(StringToJString(aValue)); TAndroidHelper.Context.sendBroadcast(Inx); end; constructor TListener.Create(aOwner: TBroadcastReceiver); begin inherited Create; fOwner := aOwner; fReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self); end; destructor TListener.Destroy; begin TAndroidHelper.context.getApplicationContext.unregisterReceiver(fReceiver); inherited; end; // usually android call it from "UI thread" - it's not main Delphi thread procedure TListener.onReceive(context: JContext; intent: JIntent); begin if Assigned(fOwner.fOnReceive) then fOwner.fOnReceive(Context, Intent, fReceiver.getResultCode); end; {$ENDIF} end.
Как использовать
// указывать нужно сразу все нужные вам Actions в Add через запятую, не по одной. fBroadcast := TBroadcastReceiver.Create(OnReceiveBroadcast); fBroadcast.AddActions([StringToJString(SENT_ACTION)]); << Custom action ------------- // или например сразу несколько Actions fBroadcast.AddActions([TJIntent.JavaClass.ACTION_SCREEN_OFF, TJIntent.JavaClass.ACTION_SCREEN_ON]);
-
ENERGY получил реакцию от Kitty в Application for Windows CE
Зачем оно надо если сейчас ни одного нового телефона не выпускается с ОС Windows Phone (бывшая Win Mobile) и даже MS недавно перестала поддерживать Windows Phone.
https://itc.ua/news/microsoft-prekratila-podderzhku-windows-phone/
Microsoft уходит с рынка мобильных ОС,
-
-
ENERGY получил реакцию от brunnengi в Разница между Push и Сервисом
Когда приходит пуш - программа не запускается, до тех пор пока юзер не ткнет пальцем в этот пуш.
Если нужно в фоне что то делать и нужно это делать именно сейчас и этого нельзя сделать когда вернется пользователь и запустит программу, тогда нужен сервис. Лучше конечно стараться делать без сервисов, т.к. легче будет портировать на iOS.
-
ENERGY получил реакцию от Alisson R Oliveira в TListView Custom checkboxes (иконка чекбокс "избранное")
Огромное спасибо Равиль! Как хорошо что вы помогаете.
Итак для тех кто не знает, в TListView есть режим DynamicAppearance , который позволяет добавлять предустановленные элементы - картинки, текст, GlyphButon. В хелпе написано что их может быть любое количество.
Итак добавляем TListView, в панели Structure выбираем TListView > ItemAppearance > Item.
В инспекторе объектов выбрать свойство Appearance и комбобоксе Dynamic Appearance. Рядом в инспекторе появится свойство Objects - нажать на него и там уже добавляем нужные поля. Там же можно переименовать поле, в AppearanceObjectName чтобы позже использовать в RunTime. У меня периодически на этих этапах вылетает Catastrophic Failure и среду приходится терминировать с диспетчера (Berlin Update 2).
Дальше, жмем правой кнопкой мыши по ListView и выбираем Toggle Design Mode, где можно увидеть эти добавленные Custom поля и расставить их мышкой и указать выравнивание.
Это имя затем можно использовать в Runtime, для картинки это индекс в ImageList, который нужно указать в ListView таким образом (за это еще раз спасибо Равилю! :), почему это сделали так неочевидно и почему это не указано в мануале, остается загадкой..
Для TImageObjectAppearance с именем Star -
ListView1.Items.Add.Data['Star'] := Integer(1);
Например заполняем список с картинками с индексами 0 и 1:
procedure TForm5.FormShow(Sender: TObject); var I: Integer; begin for I := 0 to 9 do begin with ListView1.Items.Add do begin Text := 'Item ' + I.ToString; Data['Star'] := Integer(I mod 2 = 0); end; end; end; Переключаем с картинки с индексом 1 на 0 и наоборот. procedure TForm5.ListView1ItemClick(const Sender: TObject; const AItem: TListViewItem); begin AItem.Data['Star'] := AItem.Data['Star'].AsInteger xor 1; end ;