Mika
Mika

Reputation: 1

Firemonkey: How do I use a TComboBox in a TStringGrid to make it work from the keyboard?

TComboBox in TStringGrid does not work when used from the keyboard. It does not update the Cells value.

I expected it to work from the keyboard when it works when I use the mouse. How should I change the code to make it work from the keyboard? Or is it a dead case?

Thanks Mika

void __fastcall TForm1::ChangeStringGridComboBox(TObject* Sender)
{
    TComboBox* combobox = dynamic_cast<TComboBox*>(Sender);
    if (combobox && combobox->ItemIndex > -1) {
        StringGrid1->Cells[StringGrid1->Col][StringGrid1->Row] =
            combobox->Items->Strings[combobox->ItemIndex];
    }
}

//---------------------------------------------------------------------------

void __fastcall TForm1::StringGrid1CreateCustomEditor(
    TObject* Sender, TColumn* const Column, TStyledControl*&Control)
{
    TComboBox* combobox = new TComboBox(this);

    if (Column == Column1) {
        Control = combobox;
        combobox->Items->Assign(Memo1->Lines);
        combobox->ItemIndex = combobox->Items->IndexOf(
            StringGrid1->Cells[StringGrid1->Col][StringGrid1->Row]);

        if (combobox->ItemIndex > -1) {
            StringGrid1->Cells[StringGrid1->Col][StringGrid1->Row] =
                combobox->Items->Strings[combobox->ItemIndex];
        }
        combobox->OnChange = &ChangeStringGridComboBox;
    }
}

Upvotes: 0

Views: 151

Answers (2)

Mika
Mika

Reputation: 1

With the following changes, TComboBox works fine:

ChangeStringGridComboBox

{
    ...
    temp = myComboBox->Items->Strings[myComboBox->ItemIndex];
}

StringGridEditingDone

{
    if (Column1 == StringGrid1->ColumnByIndex(ACol) && temp.Length()) {
    StringGrid1->Cells[StringGrid1->Col][StringGrid1->Row] = temp;
    temp = "";}
}

Upvotes: 0

Remy Lebeau
Remy Lebeau

Reputation: 597941

From Firemonkey: How do I use a TComboBox in a TStringGrid to make it work from the keyboard?:

To use a TComboBox in a TStringGrid and make it work from the keyboard, you can follow these steps:

  1. Place a TComboBox component on your form and set its Parent property to the TStringGrid.

  2. Set the TComboBox's Visible property to False.

  3. Handle the TStringGrid's OnSelectCell event. In the event handler, check if the current column of the selected cell is the column that the TComboBox is associated with. If it is, set the TComboBox's Left and Top properties to the coordinates of the selected cell, and set its Visible property to True.

  4. Handle the TStringGrid's OnKeyPress event. In the event handler, check if the key pressed is the down arrow key. If it is, and the TComboBox is visible, set the focus to the TComboBox.

  5. Handle the TComboBox's OnExit event. In the event handler, set the TComboBox's Visible property to False, and set the focus back to the TStringGrid.

  6. In the TComboBox's OnSelect event, you can get the selected value and assign it to the selected cell of the TStringGrid.

You can also create a custom component that inherits from TStringGrid and add the TComboBox and the necessary events to it.

Since you are creating the TComboBox as a custom InplaceEditor, most of that should already be handled for you by the TStringGrid. All you are really missing is the Key Press handler, eg:

// Unlike VCL, FMX does not expose access to TStringGrid's
// active Editor, so keep track of it manually...

protected:
    void __fastcall Notification(TComponent* AComponent, TOperation Operation) override;
private:
    TComboBox *myComboBox;

...

void __fastcall TForm1::StringGrid1CreateCustomEditor(
    TObject* Sender, TColumn* const Column, TStyledControl* &Control)
{
    if (Column == Column1) {
        myComboBox = new TComboBox(this);

        myComboBox->Items->Assign(Memo1->Lines);
        myComboBox->ItemIndex = myComboBox->Items->IndexOf(
            StringGrid1->Cells[StringGrid1->Col][StringGrid1->Row]);

        myComboBox->OnChange = &ChangeStringGridComboBox;

        Control = myComboBox;
    }
}

void __fastcall TForm1::ChangeStringGridComboBox(TObject* Sender)
{
    if (myComboBox->ItemIndex > -1) {
        StringGrid1->Cells[StringGrid1->Col][StringGrid1->Row] =
            myComboBox->Items->Strings[myComboBox->ItemIndex];
    }
}

void __fastcall TForm1::StringGrid1KeyPress(
    TObject* Sender, Word &Key, WideChar &KeyChar, TShiftState Shift)
{
    if ((Key == vkDown) && StringGrid1->EditorMode)
    {
        Key = 0;
        myComboBox->SetFocus();
    }
}

void __fastcall TForm1::Notification(TComponent* AComponent, TOperation Operation)
{
    TForm::Notification(AComponent, Operation);
    if ((Operation == TOperation::opRemove) && (AComponent == myComboBox)) {
        myComboBox = nullptr;
    }
}

Upvotes: 1

Related Questions