TListView DynamicAppearance with TImageObjectAppearance will not view image when using LiveBindingsDesigner with TFDMemTable - c++builder

I am welcoming Embarcaderos efforts to make TListView more dynamically, and was exited to see Sarina Duponts post here where you could just link the imageindex to the TListView properties in LiveBindings Designer, and even the image property to a datafield (integer) when using DynamicAppearance and TImageObjectAppearance.
But... I tried, and did almost succeed.
In my challenge I have an application where I use TFDMemTable with TREST* function to populate the TFDMemTable. All works well if I don't use the DynamicAppearance and use i.e. ImageListItem and links the datafield I want to use to the imageindex property in TListView using LiveBindings Designer.
With DynamicApperance though, there are no imageindex property to link to, but Sarina Dupont says in here post that you could link the integer field directly to the image property (and IDE/compiler will figure it out).
Well... I figured following out: My data fields (semicreated from TREST* and TFDMemTable) are not neccesserely what they seems to be. Since I am using REST/JSON, the fieldtypes are "anonymized" to WideString, actually the FieldDefs->'dataitem'->DataType is set to "ftWideString". I tried to change this value to ftInteger in hope that this would help, but I did just get this errormessage: "FDMemtTable1: Type mismatch in field for 'datafield', exepecting: WideString actual: Integer".
So... I was nearly there, and I really want to use DynamicAppearance and view several images and textfields for each TListViewItem...
...or is it easier to make a ListViewItem 'Template' dynamically and populate it with data instead, and what is the best way to do that ?

I usually try to avoid LiveBindings. The fastest, most stable and easiest way is to add items using code.
ListView1->BeginUpdate();
try {
for (int i = 0; i < arrayOfThings->item.Length; i++) {
TListViewItem* item = ListView1->Items->Add();
item->Text = arrayOfThings->item[i]->item_name;
item->Data["itemName"] = TValue::From<UnicodeString>( arrayOfThings->item[i]->item_name);
item->Data["itemId"] = TValue::From<UnicodeString>( IntToStr( arrayOfThings->item[i]->id ));
item->Data["itemDate"] = TValue::From<UnicodeString>(arrayOfThings->item[i]->item_date);
// adding the image - imgClock is name of the image field [TImageObjectAppearance ] added to items in ItemAppearance in the TListView object that uses DynamicAppereance
const UnicodeString imgClock = L"imgClock";
dynamic_cast<TListItemImage*>(item->Objects->FindDrawable(imgClock))->Bitmap = //bitmap source;
}
} catch (...) {
}
ListView1->EndUpdate();

Related

Using CompareText() and AdvPopupMenu

I'm using C++Builder 10.3 with a VCL application for Windows. I'm trying to identify a specific item in an AdvPopupMenu by looping through the Items Caption and comparing the Caption to my search text using CompareText(). The Captions have an '&' in the Caption text which I believe is part of the ShortCut feature. This seems to prevent a match when comparing the text.
I have tried setting up the menu items two ways to try and remove the '&'.
//--#1 Menu Setup--
TMenuItem *NewMenuItem;
NewMenuItem = new TMenuItem(MainForm->AdvPopupMenu1);
TShortCut sc2;
sc2 = TextToShortCut("(None)");
NewMenuItem->Caption = "Google";
NewMenuItem->ShortCut = sc2;
//--#2 Menu Setup--
TMenuItem *NewMenuItem;
NewMenuItem = new TMenuItem(MainForm->AdvPopupMenu1);
NewMenuItem->Caption = "Google";
NewMenuItem->ShortCut = NULL;
Below is my loop to search for the AdvPopupMenu item.
UnicodeString SearchFor = "Google";
UnicodeString TestCaption;
for(int i=0; i<MainForm->AdvPopupMenu1->Items->Count; i++){
TestCaption= MainForm->AdvPopupMenu1->Items->Items[i]->Caption;
if(CompareText(SearchFor , TestCaption)==0 ){
//This CompareText always fails
//TestCaption looks like this "&Google" or this "G&oogle"
}
}
How can I setup the AdvPopupMenu Caption to contain no '&' and make the CompareText work?
The &s are important. Without these, keyboard users like myself will find your application more difficult to use.
I think your best solution is to use the StripHotkey function in the Vcl.Menus unit to remove the ampersand character before you pass the caption to CompareText. (In addition, instead of testing if CompareText returns 0, it's better to use the SameText function.)
That is, don't attempt to create the menu items without the ampersand character, and don't try to remove it from the menu items. Only remove the character from the string you pass to the comparison function.
Also notice that the ampersand character is not related to the ShortCut property. The ampersand character makes the next character underlined in the menu item caption, telling the user than he or she can press that key to activate the menu item, but only when the menu is open. On the other hand, the ShortCut property adds a right-aligned text like Ctrl+A or Shift+Ctrl+N or F2 to the menu item, and these shortcuts are available even when the menu isn't open. Hence, these are different features.

Can two item renderers be used for a grid column in Adobe flex?

I have a data grid with multiple columns among which one is for stock date. Based on the data i am getting from the backend,when a flag is disabled,i want the date to be displayed as a label,otherwise i want the start date to be editable date field. How can this be done? I have tried this below code but its takes the last rendered item as item renderer. Cause as i loop in,the condition for different records change and rendering it this way doesnt seem to work. Please help.
private function resultHandler_tbd(event:ResultEvent):void{
var myAC: ArrayCollection= event.result as ArrayCollection; //data from backend
myDataGridId.dataprovider= myAC;
for(var i:int=0;i<myAC.length;i++){
mylist=myAc[i];
if(mylist.tbdType=="Plan" && flag==true){
plnStartDate.itemrenderer= new ClassFactory(CustomCalenderRenderer);
}else
plnStartDate.itemrenderer = new ClassFactory(CustomLabelRenderer);
}
}
}
Have the "flag" property set in data for item renderer
Create a custom itemrenderer which will have both component, CustomCalenderRenderer and CustomLabelRenderer and binded with data.flag for includedInLayout or not
Thanks

Custom ListBox with LiveBindings

I'm trying to make a custom ListBox that has more details and a link with LiveBindings.
In bindlist I only see the standard fields: Text, Detail, Bitmap....
When trying to bind in the following code:
Item := bliMS.FillExpressions.AddExpression;
Item.ControlMemberName := 'SubTitle';
Item.SourceMemberName := 'PAY_NAME';
An exception is raised:
Project xxxxxx raised exception class EEvaluatorError with message 'Couldn't find SubTitle'.
How can I add the SubTitle name to my custom ListBox?
Your statement: Item.ControlMemberName := 'SubTitle'; won't work because there is no actual ControlMember / object / "field" in the ListBox/TList<ListViewItem> (actually, it's more correct to say that there is none in each of the ListBoxItem objects in the the Items TList actually) called 'SubTitle'.
Instead you have to use on of the built-in text objects (ControlMembers), of which, there are only 2:
Item.Text
Item.Detail
If you for some reason have to have a 'SubTitle' ControlMember, then you would need to create a custom ListBox or ListBoxItemAppearance object and register it.

RichEdit.PlainText seems to not affect anything

I'm trying to write something like rtf editor in BCB6 and I've encountered such problem while trying to add table to my RichEdit1:
RichEdit1->PlainText=true;
AnsiString ret=RichEdit1->Text;
ret.Insert(table, RichEdit1->SelStart);
RichEdit1->Text=ret;
RichEdit1->PlainText=false;
RichEdit1->Repaint();
This code adds formatted text (code of table) to the RichEdit1 instead of adding formatting code as plain text and displaying it like a table.
Am I doing it wrong, or it can be a problem with something else.
The PlainText property is only used by the Lines->LoadFrom...() and Lines->SaveTo...() methods, nothing else.
The Text property only operates on plain text. Reading the property extracts the RichEdit's textual content without formatting. Setting the property does not process RTF code at all, the RichEdit's textual content is replaced with the new text as-is.
If you want to insert RTF code into the RichEdit, especially if you don't want to overwrite the RichEdit's current content, you will have to use the EM_STREAMIN message directly. For example:
DWORD CALLBACK StreamInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
int numRead = reinterpret_cast<TStringStream*>(dwCookie)->Read(pbBuff, cb);
if (pcb) *pcb = numRead;
return 0;
}
TStringStream *strm = new TStringStream(table);
EDITSTREAM es = {0};
es.dwCookie = (DWORD_PTR) strm;
es.pfnCallback = &StreamInCallback;
SendMessage(RichEdit1->Handle, EM_STREAMIN, SF_RTF | SFF_SELECTION, reinterpret_cast<LPARAM>(&es));
delete strm;
Problem solved, formatting was not added because of table code was not in {} brackets, after adding them around table code and using SendMessage, program works well.

Fastest way to update a TListView

I have a TListView that gets populated with data collected over a network. To collect all the data takes around 50ms, to add it to the list takes around 5 seconds. My initial guess was that it was redrawing after every addition or something like that. What should I do to get the TListView to update as quickly as possible?
Columns and items are all added via code.
I tried using BeginUpdate and EndUpdate on the items of the list but that didn't make much difference. There are around 2000 entries that are added to the list.
Without seeing your actual code, there is no way to know for sure why your updates are that slow. However, if speed is an issue for you, especially with a lot of list items, you should put the TListView into virtual mode instead (set its OwnerData property to true) and store your status information elsewhere, not in the TListView itself (2000 items is a lot of overhead for a non-virtual ListView to handle). Then, simply call the ListView's Invalidate() or UpdateItems() method when needed to trigger repaints, and use the OnData event to provide the status data to TListView whenever it asks you for it. For example:
struct MyStatusInfo
{
String Status;
...
};
MyStatusInfo StatusItems[2000];
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
...
ListView1->Items->Count = 2000; // you don't use Add() with a virtual ListView
...
}
void __fastcalll TForm1::UpdateStatus(int Index, const String &Status, ...)
{
MyStatusInfo &Info = StatusItems[Item->Index];
Info.Status = Status;
...
ListView1->UpdateItems(Index, Index);
}
void __fastcall TForm1::ListView1Data(TObject *Sender, TListItem *Item)
{
MyStatusInfo &Info = StatusItems[Item->Index];
Item->Caption = Info.Status;
...
}
I'm not sure if that helps, since BeginUpdate didn't, but it worth trying:
1) Try filling it while Enabled = false, then enable it
2) Try building a TListItems and assign it directly to the TListView's Items properties

Resources