I want to limit a TCheckListBox.
I desire only 2 items should be checked, and all unchecked items will be disabled and grayed.
Since the checked / unchecked items are dynamic, i can not use a static itemIndex.
Here is what i tried, but i got "Out of chip bounds" error.
On click event of my CheckListBox ;
var
NumberOfCheckedItems, I: Integer;
begin
NumberOfCheckedItems := 0;
for I := 0 to CkLst1.Count - 1 do
begin
if CkLst1.Checked[I] then
NumberOfCheckedItems := NumberOfCheckedItems + 1;
end;
if NumberOfCheckedItems > 1 then
begin
CkLst1.Checked[I] := Enabled;
CkLst1.Enabled := FALSE;
CkLst1.AllowGrayed := TRUE;
end
else
begin
//no idea
end;
end;
This method should do the job
procedure DoCheckListBox( AChkLb : TCheckListBox; AMaxCheck : Integer );
var
LIdx : Integer;
LCheckCount : Integer;
begin
// counting
LCheckCount := 0;
for LIdx := 0 to AChkLb.Count - 1 do
begin
if AChkLb.Checked[LIdx] then
if LCheckCount = AMaxCheck then
AChkLb.Checked[LIdx] := False
else
Inc( LCheckCount );
end;
// enable/disable
for LIdx := 0 to AChkLb.Count - 1 do
AChkLb.ItemEnabled[LIdx] := AChkLb.Checked[LIdx] or ( LCheckCount < AMaxCheck );
end;
UPDATE
You better call this inside TCheckListBox.OnClickCheck event instead of OnClick event.
A double-click can affect the check-state but OnClick is not called.
OnClickCheck is called whenever the check-state changes.
Related
with TMainMenu we have AutoLineReduction property to hide doubled separators when menu item is hidden, how to do the same with ActionMainMenuBar and ActionManager?
I didn't find an internal method for this, but we can do it manually.
We have to add the OnPopup method to the ActionMainMenuBar:
procedure TFormMain.MenuBarPopup(Sender: TObject; Item: TCustomActionControl);
begin
// Make all separators visible
for var I := 0 to Item.ActionClient.Items.Count - 1 do begin
var Itm := Item.ActionClient.Items[I];
if (Itm.Caption = '-') then
Itm.Visible := True;
end;
// Hide doubled separators
for var I := 0 to Item.ActionClient.Items.Count - 1 do begin
var Itm := Item.ActionClient.Items[I];
if (Itm.Caption = '-') then begin // Search next separator
var bFound := False;
for var J := I + 1 to Item.ActionClient.Items.Count - 1 do begin
var Itm2 := Item.ActionClient.Items[J];
if Itm2.Visible then begin
bFound := (Itm2.Caption <> '-');
Break;
end;
end;
Itm.Visible := bFound;
end;
end;
end;
Is it very strange that this component does not contain such a property...
I need to make the TCheckColumn from the FMX.StringGrid to work from an integer value but I don't know how.
My code reads from a JSON request and translates it to a stringgrid. In the database the "boolean" field is stored as integer, so 0 for false and 1 for true.
This is the code that reads from the request:
procedure TDM.CarregaDados(aTable: string; aGrid: TStringGrid);
begin
TThread.CreateAnonymousThread(
procedure
var
str: string;
begin
aGrid.RowCount := 0;
REST.Response := nil;
REST.Resource := aTable;
REST.Method := rmGET;
REST.Params.ClearAndResetID;
REST.Execute;
RESTDSA.Response := REST.Response;
RESTDSA.DataSet := RESTDS;
RESTDSA.Active := true;
TThread.Synchronize(nil,
procedure
var
I: Integer;
begin
aGrid.BeginUpdate;
while not RESTDS.Eof do
begin
aGrid.RowCount := aGrid.RowCount + 1;
for I := 0 to RESTDS.FieldCount - 1 do
aGrid.Cells[I, aGrid.RowCount - 1] := RESTDS.Fields.Fields
[I].AsString;
RESTDS.Next;
end;
aGrid.EndUpdate;
end);
REST.ClearBody;
REST.Params.ClearAndResetID;
end).Start;
end;
REST is the TRESTRequest component,
RESTDS is the TFDMemTable,
RESTDSA is the TRESTRequestDataSetAdapter component,
aGrid is a TStringGrid and
aTable is the endpoint resource.
What I wanna know is how I can tweak this code to make it work with TCheckColumn in my grid. Yes, Of course I have a TIntegerColumn, a TStringColumn and a TCheckColumn previously added to the grid.
This is an example JSON response:
[
{
"ID" : 1,
"Descr" : "test",
"ischeck" : 0
},
{
"ID" : 2,
"Descr" : "test",
"ischeck" : 1
}
]
Well I know It's late, but I am a newbie here, and it's the first time I use FMX.TStringGrid without Livebindings.
I found a solution to this problem, with my own data
procedure TCsv4Presta.StringGrid1CellClick(const Column: TColumn;
const Row: Integer);
begin
case Column.Index of
0 : begin // my checkboxcolumn
StringGrid1.Cells[0,Row]:= BooltoStr(Not StrToBool(StringGrid1.Cells[0,Row]),true);
Column.UpdateCell(Row); // important to refresh checkbox
end;
end;
end;
just a problem with this onclick, you have to manage click in the cell but not on the checkbox
So I can suggest you a code like
while not RESTDS.Eof do
begin
aGrid.RowCount := aGrid.RowCount + 1;
for I := 0 to RESTDS.FieldCount - 1 do
begin
if aGrid.Columns[I] is TCheckBoxColumn then
begin
aGrid.Cells[I, aGrid.RowCount - 1] := BooltoStr(RESTDS.Fields.Fields
[I].AsString='1',true) ;
// Column.UpdateCell(Row);
end
else aGrid.Cells[I, aGrid.RowCount - 1] := RESTDS.Fields.Fields
[I].AsString;
end;
RESTDS.Next;
end;
Problem
My TListBox is getting blank when its last TListBoxItem is programatically checked. To illustrate it better, hereby what I mean by getting blank:
Context
I'm generating a list from a TJSONArray. Each item looks like {"event_code","event_name"}.
Then, I compare if the event_code is written on a second TJSONArray : json_response_available_events. If it does, the ListBoxItem will be checked.
Code
procedure TFormHome.TimerGetEventsTimer(Sender: TObject);
var
K : Integer;
Z : Integer;
ListCount : Integer;
AvailableList_Count: Integer;
lb_item: TListBoxItem;
event_code_first_array: string;
event_code : string;
event_name : string;
begin
// Disable this timer for now
TimerGetEvents.Enabled := false;
// Get List of Notifications
json_response_events := DM_Auth0.ServerMethods1Client.GetEventsCodeAndDescription(communication_token);
json_response_available_events := DM_Auth0.ServerMethods1Client.GetAllowedNotificationsList(communication_token, genset_id);
ListCount := json_response_events.Count -1;
AvailableList_Count := json_response_available_events.Count - 1;
for K := 0 to (ListCount) do
begin
// Get complete Event Code and Name
event_name := json_response_events.Items[K].toString;
// Get Event Code
event_code_first_array := StringReplace(event_name.Split([':'])[0], '"', '', [rfReplaceAll]);
// Get Event Name
event_name := StringReplace(event_name.Split([':'])[1], '"', '', [rfReplaceAll]);
// Create ListBoxItem
lb_item := TListBoxItem.Create(self);
lb_item.Parent := lb_notifications;
lb_item.Text := event_name;
lb_item.StyleLookup := 'listboxitemleftdetail';
// Check if this Item code is available
for Z := 0 to (AvailableList_Count) do
begin
if json_response_available_events.Items[Z] <> nil then
begin
// Get Event Code
event_code := json_response_available_events.Items[Z].toString;
// Format
event_code := StringReplace(event_code, '"', '', [rfReplaceAll]);
if event_code_first_array.Contains(event_code) then
begin
if K <= ListCount then
begin
lb_item.IsChecked := true;
lb_item.IsSelected := false;
end;
end;
end;
end;
end;
end;
Analysis
If we set to < only, it displays the list correctly but the last item will remain unchecked.
if K < ListCount then
begin
lb_item.IsChecked := true;
lb_item.IsSelected := false;
end;
I can even change it's properties when its = like
if K = ListCount then
begin
lb_item.Text := 'Deadpool for President';
end;
and lb_item.isChecked := false works fine, but when setting lb_item.isChecked := true it gets all weirdly blank.
Why is it happening? And if there's a better way to do what I'm doing, the help will be appreciated.
I have a form that has a TADVStringGrid. I am trying to add a combobox to some rows in a specific column (2); however, I can't get the data to show on the dropdown. I added the HasComboBox event, I set the DirectComboDrop, and it still did not show any data in the dropdown. They were just empty. I check the object that I am adding to the dropdown, and they had data. What am I missing here?
procedure UserForm.DisplayGrid(Sender: TObject);
var
J : Integer;
begin
... additional logic
...
if OutputList.Count > 2 then
begin
with UserGrid.Combobox do
begin
for J := 0 to OutputList.Count - 1 do
BEGIN
if not(OutputList[J] = '') then
begin
dValue := DropDownValue.Create;
dValue.ID := J + 1;
dvalue.Name := OutputList[J];
dvalue.TestValue := OutputList[J] + 'testvalue'; // where value will be a list to choose from
ListOfTest.Add(dValue); // this is a glabal variable where I for later reference
ItemIndex := dValue.ID;
end;
END;
end;
end;
//event
procedure UserForm.UserGridHasComboBox(Sender: TObject; ACol, ARow: Integer;
var HasComboBox: Boolean);
begin
HasComboBox := True;
end;
There is an event handle called EditorProp that needed to be added. Data that need to be added for a specific column have to be added when the EditorProp event is called. The piece of code below was moved into the editorprop event, and it's working fine since.
for J := 0 to OutputList.Count - 1 do
BEGIN
if not(OutputList[J] = '') then
begin
dValue := DropDownValue.Create;
dValue.ID := J + 1;
dvalue.Name := OutputList[J];
dvalue.TestValue := OutputList[J] + 'testvalue'; // where value will be a list to choose from
ListOfTest.Add(dValue); // this is a glabal variable where I for later reference
ItemIndex := dValue.ID;
end;
i have create 7 dynamic buttons in a scroll box. Each row need to have 2 buttons (number of buttons may change) only, but the result of the code below shows the first row with 2 buttons but all the rest in 2nd row, how should i fixed it to 2 buttons 1 row?
procedure TForm1.CreateDynamicBtn2;
var
abtn: TBitBtn;
i, j, iNum, iCount : integer;
begin
if ScrollBox2.ControlCount > 0 then begin
for j := ScrollBox2.ControlCount - 1 downto 0 do begin
with ScrollBox2.Controls[j] AS TBitBtn do begin
Free;
end;
end;
end;
iCount := 0;
for i := 0 to 6 do begin
iNum := i + 1;
abtn := TBitBtn.Create(self);
abtn.Parent := ScrollBox2;
abtn.Visible := True;
abtn.Caption := 'dynamic' + IntToStr(i);
if iNum*abtn.Width > (iCount+2)*abtn.Width then begin
iCount := iCount + 1;
abtn.Left := (iCount * abtn.Width) - abtn.Width;
abtn.Top := abtn.Height;
end else begin
abtn.Left := i * abtn.Width;
abtn.Top := 0;
end;
end;
end;
Because you are making things way too complicated?
abtn.Left := (i mod 2) * abtn.Width;
abtn.Top := Trunc((i div 2)) * abtn.Height;
Should do the trick nicely.