Listbox does not show the changes made to the Dataset - delphi

I have a FMX ComboBox connected through LiveBindings to a ClientDataset. Everything works fine, until I needed to filter the data from the ClientDataset. After applying the filter, ComboBox.Items and ComboBox.ListItems are ok, i.e., it is the data contained in the filtered ClientDataset. But the data that the ComboBox listbox shows is always the same: the data that the ClientDataset contained the first time the listbox was displayed.
procedure TForm14.Button1Click(Sender: TObject);
begin
LinkFillControlToField1.Active := False;
ClientDataset1.Filter := 'TYPE = ''N''';
Clientdataset1.Filtered := not ClientDataset1.Filtered;
// Deactivate and Reactivate the link is necessary to refresh the data
LinkFillControlToField1.Active := True;
end;
In that code I change the filter to the ClientDataset and I deactivate the LinkFillControlToField and after applying the filter I activate it again to refresh the data. It works without problems with TListBox and other controls, but not with a TComboBox, although ComboBox.Items and ComboBox.ListItems do contain the correct data, but it is not the one shown in the combobox listbox.
Is there a way to solve this, using LiveBindings ? I have looked for properties and methods of the ComboBox (Repaint for example), the LinkFillControlToField and the BindSourceDB, but nothing has worked for me.
I use Delphi 10.4 Update 2, Firemonkey Windows application (32 or 64) running on Windows 10.
TIA.,
Ricardo

I had the same problem. My data source was TFireDAC TQuery. I submitted a change to a parma contained in the query.
My solution to my problem was to insert the line to explicitly clear the list of items.
if (SCM != NULL && SCM->qrySession->Active) {
SCM->qrySession->DisableControls();
// remove all the strings held in the combobox
// note cmbSessionList->Clear() doesn't work here.
cmbSessionList->Items->Clear();
SCM->qrySession->Close();
// ASSIGN PARAM to display or hide CLOSED sessions
SCM->qrySession->ParamByName("HIDECLOSED")->AsBoolean = fHideClosedSessions;
SCM->qrySession->Prepare();
SCM->qrySession->Open();
SCM->qrySession->EnableControls();
}

Related

How to get the values of TListView selected item in Firemonkey Delphi Rio

I have a TListView populated with data from TFDQuery using Livebindings.
I would like to get the values of the selected item like the item.text, itemheader.text, etc. I already figured out the selected item through listview1.itemindex but to get the values is a struggle to me. I am new with TListView and livebindings. I've spent over a day already looking for answers in the internet but looks too complicated for a very simple task. I know there is a straight method for this.
Anyone care to share some clues (codes) on how to get the values of listview selected item?
MORE DETAILS:
I am using the Livebindings dynamic appearance. I created items for my query fields and map them accordingly to my TListView.
It so happen that I did not use the default item.text but instead map fields to my created items like item.text1, item.text2, item.item3.
Hence, this is the reason why I am not getting the caption from the formula given by MartynA below.
Perhaps I am missing your point (in which case I'll delete this) but the following FMXcode works fine for me:
procedure TForm1.Button2Click(Sender: TObject);
var
Index : Integer;
begin
Index := ListView1.ItemIndex;
if Index >= 0 then
Caption := ListView1.Items[Index].Text;
// OR ShowMessage(ListView1.Items[Index].Text);
// OR Label1.Text := ListView1.Items[Index].Text;
end;

What has happened to ComboBox.Sorted := True; in Delphi 10.2?

Having recently received a 'Tumbleweed' badge for my last question, I am not sure whether I should be asking any more questions, but here goes.
I am populating a TComboBox with items from a sqlite table and this works fine. In my previous version of Delphi I was able to use ComboBox1.Sorted := True; to sort the items, but this seems to have disappeared in Delphi 10.2. I can sort the items in the table by applying a query and then populate the TComboBox from the sorted table. However, for curiosities sake I would like to find out how one now sorts items in a TComboBox. I have found some references to TComboBox(Sort:Compare) but have not succeeded in getting this to work to as of yet.
Can somebody please shed some light on this - many thanks
In Firemonkey you can populate a TComboBox instance either simply with the Items property of type TStrings or you add TListBoxItem instances with the form designer. But internally always TListBoxItem for the elements is used.
To use the TComboBox.Sort you need to provide an anonymous compare-function.
This is a simple example usage of TComboBox.Sort
cbxItems.Sort(
function (pLeft, pRight: TFMXObject): Integer
var
lLeft, lRight: TListBoxItem;
begin
lLeft := TListBoxItem(pLeft);
lRight := TListBoxItem(pRight);
Result := String.Compare(lLeft.Text, lRight.Text);
end
);

How to access data record after ListBox selected with LiveBindings

I have a TSQLDataset, Im using the livebindings to bind it to a listbox. When I click on the listbox item, I want to be able to access the other fields of data from the record, but I cannot figure out how to do it because I cannot get the dataset to the corresponding item.
I know that I could possibly take the ID Field and maybe assign it to Selected.Tag using live bindings but can't figure that out either, but if I could then I could have another a SQLQuery and then just return the result of the query
SELECT * FROM Dataset WHERE ID=(Tag value)
That would work, but I don't know how to get livebindings to set the items tag value when live bindings populates the Listbox.
Does anyone know how to make this work?
It is easier to link Tag property of the ListBox with the ID of the record.
There's a Sensor Info demo application from Embarcadero in XE5 Samples directory...
There you have OnItemClick = lbMainItemClick in TListBox events then you have to define the event handler:
procedure TfrmAboutSensors.lbMainItemClick(const Sender: TCustomListBox; const Item: TListBoxItem);
begin
if Assigned(Item.OnClick) then
Item.OnClick(Item);
end;
And then for every item on the list:
for LItem in LListBox do
begin
//LItem.ItemData.Accessory := TListBoxItemData.TAccessory.aDetail; // my code
//LItem.ItemData.Accessory := TListBoxItemData.TAccessory.aNone; // my code
LItem.OnClick := ListBoxItemClick;
end;
Please give us callback if that helps.

Tlistview - There is any component like Tlistview but with DB access?

I've been trying to make a creative thing to avoid the dbgrids, and i've found the Tlistview (using the one from alphaskins, tslistview), and seems to be a nice way!
The problem is, I don't want to code the event onclick on every tlistview to position a record/dataset according to the item I selected on the tlistview .. and I'm doing it with the tlistview item's caption.. and there could be records with the same names
Here is one of the codes I want to avoid:
with q_find_process do
begin
close;
sql.Clear;
sql.Add('Select * from t_process where process_name like '+quotedstr(streeview1.Selected.Text)+');
open;
end;
And no, I don't want to put the ID of the Record on the item caption..!
Any ideas?
Does anyone know other way of showing a lot of records without being only text text and more text? I don't know all components on the tool palette, maybe someone could suggest me other one..
I have sometimes used listviews which have been loaded from database tables - only for small amounts of data. I don't understand what you mean by I don't want to code the event onclick on every tlistview to position a record/dataset according to the item I selected on the tlistview, so I'm going to show you how I solved this problem.
Basically, I create a sub-item which holds the primary key of each record. All the user interface code uses two list views, and at the end, the database is updated. There is no interaction with the database between loading and storing (which might be where I avoid your 'onclick' problem). The widths of each fields are set in the Object Inspector; the final subitem's width is 0 (ie not displayed).
Loading the list view:
srclist.items.clear;
with qSrcList do
begin
close;
params[0].asdate:= dt; // use date of deposit
open;
while not eof do
begin
ListItem:= srclist.Items.Add;
ListItem.Caption:= fieldbyname ('kabnum').asstring;
ListItem.SubItems.Add (fieldbyname ('price').asstring);
ListItem.SubItems.Add (fieldbyname ('duedate').asstring);
ListItem.SubItems.Add (fieldbyname ('docket').asstring);
ListItem.SubItems.Add (fieldbyname ('id').asstring);
next
end;
close
end;
Saving data:
with dstlist do
for index:= 1 to items.count do
with qInsert do
begin
dstlist.itemindex:= index - 1;
lvitem:= dstlist.selected;
parambyname ('p1').asinteger:= deposit;
parambyname ('p2').asinteger:= strtoint (lvitem.SubItems[3]);
parambyname ('p3').asfloat:= strtofloat (lvitem.SubItems[0]);
execsql;
end;
I hope that this helps you. The context of this code (not that it matters too much) is in a financial application where the user wishes to populate a bank deposit form with cheques. SrcList holds the cheques which have yet to be deposited (there will only be a few per given date) and DstList holds the cheques which have already been connected to a given deposit form.

FM2 Object Repaint Issue

Good evening guys.
I'm currently designing a social networking client for Twitter and Facebook in Firemonkey FM2 (delphi) and I'm experiencing a frustrating issue. At present, I've only got the Twitter code in process, but the issue is related to the [re]drawing of visual objects.
I've created a custom-styled TListboxItem layout in a stylebook consisting of multiple child components such as TText, TButton, and TImage. I've already dealt with connecting to Twitter and retrieving feed details. Each item retrieved is added to a TListbox and styled using my custom ListboxItem style layout.
Now, the issue is related to updating information on items in the list that aren't visible. For example, the items that are visible in the list without scrolling show their information correctly. Those that aren't visible besides the final item in the list have several of their details not set/visible. When I scroll the list downwards, and then back up, there's often 1 of the items that was originally visible will now be missing it's information.
To explain this a little more, i've got a TImage (known as photo) which is used to show the photo of the person who posted the 'tweet'. I've got the standard TText (known as text) used to show the contents/text of the tweet itself. I've got 2 buttons (known as Like and Share) used to perform their respective functions. I've then finally got another TText (known as NameDate) used to show the name of the tweeter and the date the tweet was posted.
I'm using this code to create the object and modify the data it shows;
for i := 0 to TwitObj.Statuses.Count-1 do
begin
FeedItem := TListBoxItem.Create(LBFeed);
FeedItem.Parent := LBFeed;
FeedItem.StyleLookup := 'FeedItem';
FeedItem.WordWrap := True;
FeedItem.StyledSettings := [TStyledSetting.ssFamily, TStyledSetting.ssSize, TStyledSetting.ssStyle, TStyledSetting.ssFontColor, TStyledSetting.ssOther];
NameDate := Feeditem.FindStyleResource('txtnamedate') as TText;
Photo := FeedItem.FindStyleResource('photo') as TImage;
Like := FeedItem.FindStyleResource('btnlike') as TButton;
Share := FeedItem.FindStyleResource('btnshare') as TButton;
Share.Text := 'Retweet';
Like.Text := 'Favorite';
NameDate.Text := Twitobj.Statuses.Items[i].User.Name +
'(#'+TwitObj.Statuses.Items[i].User.ScreenName+
') - '+DateTimeToStr(TwitObj.Statuses.Items[i].CreatedAt);
FeedItem.Text := TwitObj.Statuses.Items[i].Text;
begin
if DirectoryExists('imagecache\') = false then CreateDir('imagecache\');
if FileExists('imagecache\'+TwitObj.Statuses.Items[i].User.ScreenName+'.jpg') = False then
begin
try
rcv := TMemoryStream.Create;
GtPhoto.URL := TwitObj.Statuses.Items[i].User.ImageURL;
GtPhoto.RcvdStream := rcv;
GtPhoto.Get;
rcv.SaveToFile('imagecache\'+TwitObj.Statuses.Items[i].User.ScreenName+'.jpg');
finally
Rcv.Free;
end;
end;
end;
Photo.Bitmap.LoadFromFile('imagecache\'+TwitObj.Statuses.Items[i].User.ScreenName+'.jpg');
GTPhoto is a standard ICS HTTP Client component, while TwitObj is my Twitter component. You can see that I'm saving the photo to a directory instead of streaming it. This was merely to check whether it was an issue with streams, but it's probably advisable to used a cache of some sort anyway.
The images download correctly, and the information for the relevant StyleResources in the custom ListBoxItem layout is updated as expected, but only for items that are visible without scrolling. If I scroll down the list, only the Text of each item is correct, while the other resources which were set at runtime have returned to the way they're designed in the stylebook (i.e. blank text, image, etc).
Am I missing something here? I understand the design intents of Bitmaps were changed in XE3 for the sake of performance, but surely Embarcadero wouldn't have overlooked something like this. Surely it's not expected for us to create each item inside the parent at runtime (and thus dealing with alignments and such) instead of using a stylebook resource, is it?
Any assistance or insight would be greatly appreciated.
FireMonkey can load and unload the style for a control at any moment. It was rather lax with this in FM1, but under FM2, styling elements are removed when a control is not visible and reapplied when it becomes visible again (in order to conserve memory, mainly in preparation for Mobile Studio).
What you need to do is override the ApplyStyle method. In it look up and set data in your style elements. This will probably mean that your control(s) need to cache what will be passed to the style.
Also note that if you are caching references to style elements (i.e. what you get back from FindStyleResource) then these will be freed when the style is unloaded and your pointers will be invalid. If so, you need to override FreeStyle and nil any pointers you may have cached.

Resources