Mensaje    Asunto: InputBox / InputQuery con ComboBox Responder citando

El texto es un poco largo, así que perdone cualquier error tipográfico, ya que estoy usando el traductor de Google (como siempre lo hago) para traducir al español.

He estado pensando en una forma de proporcionar una lista de números para que el usuario elija a través de algo como InputBox o InputQuery.
La solución lógica, pensé, es encontrar una manera de poner un TComboBox en lugar del TEdit de estas ventanas. No he encontrado una forma sencilla de hacer esto.
Decidí mirar cómo están construidos. El código está en Object Pascal, en el archivo vcl \ dialogs.pas.
Noté que la versión anterior (el código) (C++ Builder 6) es más amigable, menos complicada que el compilador actual. El problema es que los cuadros de mensaje también salen a la antigua, dilatando la altura, a diferencia de los actuales que dilatan el ancho, cuando el Pie de la etiqueta crece más allá de la medida estándar.
Traduje el código anterior a C++, pero logré hacer algunas adaptaciones que permiten que los cuadros de mensajes se muestren tanto en el modelo BCB6 como en el BCB RAD actual.

Code:

Unit H:
Código:

// **************  GUARDE ESTE CÓDIGO CON NOMBRE: UnitClasses1.h
//---------------------------------------------------------------------------
#ifndef UnitClasses1H
#define UnitClasses1H
//---------------------------------------------------------------------------
class MyInputStrings
{
  private:
      TPoint  __fastcall GetAveCharSize( TCanvas  *Canvas );

  public:
   bool __fastcall CreateForm(TForm *owner, String const ACaption,
                       String APrompt, String &Value, short opcao);
   void __fastcall CreatePrompt(String APrompt, short opcao);
   void __fastcall CreateEdit( String Value, short opcao);
   void __fastcall CreateBtnOk( short opcao);
   void __fastcall CreateBtnCancel( short opcao);
};
//---------------------------------------------------------------------------
#endif



Unit cpp:
Código:

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

//******************* GUARDE ESTE CÓDIGO CON NOMBRE: UnitClasses1.cpp
#include <vcl.h>
#pragma hdrstop

#include "UnitClasses1.h"

#pragma package(smart_init)

TForm *Form;
TLabel *Prompt;
TEdit *Edit;
TComboBox *Combo;
TCheckBox *Check;
TButton * CompObj1;
TButton * CompObj2;
TPoint DialogUnits;
int ButtonTop, ButtonWidth, ButtonHeight;

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

TPoint  __fastcall MyInputStrings::GetAveCharSize( TCanvas  *Canvas )
 {
   int I;
   char Buffer[53];
   // esvazio o buffer de lixo
   memset(&Buffer[0], 0, sizeof(Buffer));
   TSize result;
   // coloca o abcdário Maiúsculo e minúsculo em Buffer
   for ( I = 0; I <= 25; I++) Buffer[I] = (unsigned char) (I + 65);
   for ( I = 0; I <= 25; I++) Buffer[I + 26] = (unsigned char) (I + 97);
   GetTextExtentPoint32A(Canvas->Handle, Buffer, 52, &result);
   result.cx = result.cx/52;
   return TPoint(result.cx, result.cy);
 }

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

bool __fastcall MyInputStrings::CreateForm(TForm *owner, String const ACaption,
                        String APrompt, String &Value, short opcao)
{
  try  {
   Form = new TForm(owner);
   Form->Canvas->Font = owner->Font;
   DialogUnits = GetAveCharSize(Form->Canvas);
   Form->BorderStyle = bsDialog;
   Form->Caption =  ACaption;
   if(opcao<3)  {
     Form->ClientWidth = MulDiv(230, DialogUnits.x, 4);
   }
   Form->Position = poScreenCenter;

   CreatePrompt(APrompt, opcao);
   CreateEdit(Value, opcao);
   CreateBtnOk(opcao);
   CreateBtnCancel(opcao);

   if ( Form->ShowModal() == mrOk )  {
     if(opcao==1)  {
      Value = Edit->Text;
     }
     else if(opcao>=2)  {
      Value = Combo->Text;
     }
     return  True;
   }
   else {
      if(opcao==4 && Check->Checked)   {
       Value = "";
      }
      return false;
   }
  }
  __finally  {  delete Form;  }

}

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

void __fastcall MyInputStrings::CreatePrompt(String APrompt, short opcao)
{
    Prompt = new TLabel(Form);
      {
        Prompt->Parent = Form;
        Prompt->Caption = APrompt;
        Prompt->Left = MulDiv(8, DialogUnits.x, 4);
      Prompt->Top = MulDiv(8, DialogUnits.y, 8);
      if(opcao==1 || opcao==2)  {
         Prompt->Constraints->MaxWidth = MulDiv(214, DialogUnits.x, 4);
      }
      else  {
         Prompt->Constraints->MaxWidth = MulDiv(314, DialogUnits.x, 4);
      }
      Prompt->WordWrap = true;
     }
}

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

void __fastcall MyInputStrings::CreateEdit( String Value, short opcao)
{
   if(opcao == 1 ) {
     Edit = new TEdit(Form);
     {
        Edit->Parent = Form;
        Edit->Left = Prompt->Left;
        Edit->Top = Prompt->Top + Prompt->Height + 5;
      Edit->Width = MulDiv(214, DialogUnits.x, 4);
        Edit->MaxLength = 255;
      Edit->Text = Value;
      Edit->SelectAll();
     }
   }
   else if (opcao >= 2)  {
     Combo = new TComboBox(Form);
     {
      Combo->Parent = Form;
      if(opcao==2)  {
         Combo->Left = Prompt->Left;
         Combo->Top = Prompt->Top + Prompt->Height + 5;
      }
      else if (opcao > 2)  {
         Combo->Left = Prompt->Left + Prompt->Width + 5;
         Combo->Top = Prompt->Top;
        }
      Combo->Width = MulDiv(214, DialogUnits.x, 4);
      Combo->Style = csDropDownList;
      TStringList *l = new TStringList();
        try{
          l->Text = Value;
         Combo->Items->AddStrings(l);
         if(Combo->Items->Count<50)  {
            Combo->DropDownCount = Combo->Items->Count;
         }
         else  {
            Combo->DropDownCount = 50;
         }
        }
        __finally {
            delete l;
        }
        Combo->ItemIndex = 0;
        Combo->SelectAll();
     }
     if(opcao==4)  {
     Check = new TCheckBox(Form);
     {
      Check->Parent = Form;
      Check->Left = Prompt->Left;
      Check->Top = Prompt->Top + Prompt->Height + 15;
      Check->Caption = "Esvaziar string.";
     }

      }
   }
}

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

void __fastcall MyInputStrings::CreateBtnOk( short opcao )
{

     if(opcao==1) {
     ButtonTop = Edit->Top + Edit->Height + 15;
     }
     else if(opcao>=2) {
     ButtonTop = Combo->Top + Combo->Height + 15;
     }
     ButtonWidth = MulDiv(50, DialogUnits.x, 4);
     ButtonHeight = MulDiv(14, DialogUnits.y, 8);
     CompObj1 = new TButton(Form);
      {
        CompObj1->Parent = Form;
        CompObj1->Caption = "OK";
        CompObj1->ModalResult = mrOk;
      CompObj1->Default = True;
      if(opcao<=2)  {
         CompObj1->SetBounds(MulDiv(118, DialogUnits.x, 4), ButtonTop, ButtonWidth, ButtonHeight);
      }
     }
}

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

void __fastcall MyInputStrings::CreateBtnCancel(short opcao)
{
     CompObj2 = new TButton(Form);
      {
        CompObj2->Parent = Form;
        CompObj2->Caption = "Cancelar";
        CompObj2->ModalResult = mrCancel;
      CompObj2->Cancel = True;
      if(opcao==1)  {
         CompObj2->SetBounds(MulDiv(172, DialogUnits.x, 4), Edit->Top +
                        Edit->Height + 15, ButtonWidth, ButtonHeight);
      }
      else if(opcao==2)  {
         CompObj2->SetBounds(MulDiv(172, DialogUnits.x, 4), Combo->Top +
                        Combo->Height + 15, ButtonWidth, ButtonHeight);
      }
      else if( opcao>2)  {
         CompObj2->SetBounds(Prompt->Left+Prompt->Width+5+Combo->Width-ButtonWidth, Combo->Top + Combo->Height + 15,  ButtonWidth, ButtonHeight);
         CompObj1->SetBounds(CompObj2->Left - ButtonWidth - ButtonHeight/2, ButtonTop, ButtonWidth, ButtonHeight);
         Form->ClientWidth = MulDiv(230 , DialogUnits.x, 4) + Prompt->Width;
         Form->ClientHeight = CompObj2->Top + CompObj2->Height + 13;
      }
      if(opcao==4)  {
         Form->ClientHeight = CompObj2->Top + Prompt->Height + 22;
      }
      else  {
         Form->ClientHeight = CompObj2->Top + CompObj2->Height + 13;
        }
     }
}
//---------------------------------------------------------------------------


InputQuery y InputBox editables convirtiendo el código que crea el TInputQuery en el archivo
C:\Program Files (x86)\Borland\CBuilder6\Source\vcl\dialogs.pas

Los dos primeros ejemplos siguen el patrón BCB6 con cuadros de mensaje que dilatan la altura, a medida que se aumenta el título de la etiqueta;
los dos últimos ejemplos siguen el patrón más reciente, con una dilatación del ancho a medida que crece el título de la etiqueta.

El único ejemplo con TEdit es el primero. Los otros tuvieron este componente reemplazado por TComboBox, agregando una nueva funcionalidad admirable a InputQuery.

La diferencia entre InputQuery y InputBox es el valor de retorno: InputBox devuelve String, mientras que InputQuery devuelve bool. Otra diferencia es que InputQuery puede cambiar el valor de una cadena pasada como argumento, mientras que InputBox no.

Los cuatro primeros ejemplos (y posiblemente únicos) se basan en InputQuery. Para convertir cualquiera a InputBox, simplemente trabaje con el valor de retorno. Es simple.

//==============

Definimos el estilo de MyImputQuery según el archivo numérico que le pasemos:

Código:

1, 2, 3 o 4


1 crea una ImpuQuery en el patrón BCB6, solo un poco más grande que el predeterminado.

2 crea una ImpuQuery con las mismas dimensiones que la anterior, pero usa un TComboBox en lugar de TEdit. Se puede aplicar estilo a TComboBox en el código que lo crea. Al igual que el anterior, crece en altura.

3 crea una ImpuQuery con ComboBox estilo RAD. Crece en ancho (ancho).

El 4 es el mismo que el anterior, pero tiene un TCheckBox que brinda la opción de vaciar la cadena pasada como argumento, en caso de que se haga clic en el botón "cancelar".

Todos los Comboboxes se pueden diseñar en los códigos que los crean.

Para llenar los elementos de los cuadros combinados, pase, como argumento, una sola cadena con todos los elementos separados por \n

Ejemplo:

Código:

   String str = "item 1\nitem 2\nitem 3\nitem 4";
   MyInputStrings *InputStrings;
   InputStrings->CreateForm(Form1,  "Input Box", "Prompt... ", str, 2);
   ShowMessage(str);



Si desea crear una cadena más fácil de leer, puede hacerlo así:

Código:

   String str = (String)
            "Item 1" + "\n" +
            "Item 2" + "\n" +
            "Item 3" + "\n" +
            "Item 4";



Si va a pasar una secuencia de números para que se elija uno, puede usar un bucle:

Código:

   Int num;
   String p = "1";

   for(int i=2; i<=100; i++)  {
     p = (String) p + '\n' + IntToStr(i);
   }

   bool bl =
     InputStrings->CreateForm(Form1,
               "Input Strings",
               "Escolha um número",
               p,
               4);

   if(bl==false)  {
      ShowMessage("Operação cancelada.");
      return "";
   }

   num = StrToInt(p);
   
   ...



Coloque los archivos UnitClasses1.h y UnitClasses1.cpp en una carpeta del proyecto;

Menú:

Project -> Add to Project...

Busque los archivos y agregue UnitClasses1.cpp

guardar

Incluya el archivo UnitClasses1.h en la unidad que llamará a MyInputQuery. Por ejemplo, en Unit1.h:


Código:

...
#include <Vcl.Buttons.hpp>
//---------------------------------------------------------------------------
#include "UnitClasses1.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
...



Si va a utilizar el cuadro de entrada de mensajes solo en este formulario, puede declarar el objeto de esa clase en la parte privada de la unidad h
Si se usa en otros formularios, declare en la parte pública:


Código:

private:   // User declarations
   MyInputStrings *InputStrings;  // aquí

public:      // User declarations
   __fastcall TForm3(TComponent* Owner);
   ...
   MyInputStrings *InputStrings;  // o aquí