Proprietà
Controllo dell'input
TPanel


Nel paragrafo precedente si è preparata la TForm FrmScomposizione, cioè la parte fondamentale dell'interfaccia grafica dell'applicazione con l'utente (GUI: Graphic User Interface). Ma al momento l'applicazione non ha nessuna capacità né di input né di output.

L'applicazione deve essere in grado di ricevere dall'utente la comunicazione del numero naturale da scomporre in potenze di fattori primi e, dopo aver effettuato la scomposizione, comunicarla all'utente ed essere pronta a ripetere questa operazione.

Come nel progetto Saluto bisogna dotare l'interfaccia di un menù e associare ad ogni item dello stesso l'opportuna risposta da parte dell'applicazione. In questo caso il menù deve avere due items:

La possibilità di elaborare un nuovo input assume implicitamente che l'applicazione sia già in possesso di un numero precedentemente registrato. L'applicazione insomma deve nascere avendo già una variabile numero cui è già stato assegnato un valore.

La variabile numero deve essere una proprietà di FrmScomposizione.

Per dotare FrmScomposizione di questa proprietà bisogna commutare dall'ambiente grafico all'ambiente di editing e selezionare la sezione intestata UnitScomposizione.h in cui C++Builder ha confezionato la descrizione della classe TFrmScomposizione (FrmScomposizione è un oggetto di tale classe).

class TFrmScomposizione : public TForm
{
__published:    // IDE-managed Components
private:        // User declarations
public:         // User declarations
        __fastcall TFrmScomposizione(TComponent* Owner);
};

Inserire nella sezione public:, prima del costruttore TFrmScomposizione(TComponent* Owner) la proprietà numero che deve essere di tipo intero: il tipo intero, nel caso più semplice si dichiara con la parola chiave int, ma poiché si vogliono elaborare interi positivi abbastanza grandi si useranno i modificatori di tipo long e unsigned.

class TFrmScomposizione : public TForm
{
__published:    // IDE-managed Components
private:        // User declarations
public:         // User declarations
unsigned long int numero;
        __fastcall TFrmScomposizione(TComponent* Owner);
};

Per fare in modo che la proprietà numero nasca con un valore preassegnato si torna nell'ambiente grafico, nell'OI si seleziona FrmScomposizione e nella sezione Events all'evento On Create si associa il metodo CmdOnCreate. Premendo il tasto Invio si passa nuovamente nell'ambiente di editing, in cui appare pronta l'intestazione del metodo CmdOnCreate

void __fastcall TFrmScomposizione::CmdOnCreate(TObject *Sender)
{
  
}

Completare il metodo con l'istruzione che assegna alla proprietà numero il valore 1.

void __fastcall TFrmScomposizione::CmdOnCreate(TObject *Sender)
{
numero = 1; 
}

Se ora si esamina la dichiarazione della classe nel file UnitScomposizione.h si vede che C++Builder ha dotato automaticamente la classe del metodo appena definito.

class TFrmScomposizione : public TForm
{
__published:    // IDE-managed Components
void __fastcall CmdOnCreate(TObject *Sender);
private:        // User declarations
public:         // User declarations
        unsigned long numero;
        __fastcall TFrmScomposizione(TComponent* Owner);
};

Si torni ora alla definizione del menu. Si definisca, con i metodi già esposti, un menù principale e si inseriscano in esso gli items MnNuovoNumero con Caption &Nuovo Numero e MnScomposizione con Caption &Scomposizione.

All'evento OnClik di MnNuovoNumero associare il metodo CmdNuovoNumero e premere Invio. Si passa automaticamente all'ambiente di editing per completare il corpo del metodo CmdNuovoNumero

void __fastcall TFrmScomposizione::CmdNuovoNumero(TObject *Sender)
{

}

Per chiedere all'utente il numero da scomporre si usa la funzione InputQuery. Dato che questa funzione ammette come argomenti solo stringhe, mentre qui interessa ottenere un numero, è necessario, prima di invocare questa funzione, introdurre una variabile ausiliaria di tipo stringa in cui trasferire la rappresentazione tipografica (in caratteri stampabili) del numero e dai cui, ad input avvenuto con successo, riottenere il codice binario del valore del numero.

Le funzioni di C++Builder che operano queste conversioni sono IntToStr e StrToInt.

void __fastcall TFrmScomposizione::CmdNuovoNumero(TObject *Sender)
{
  AnsiString aux = IntToStr(numero);
  if (InputQuery("Scomposizione","Numero?",aux))
    numero = StrToInt(aux);
}

In questo metodo non è necessario dichiarare la variabile numero perché si tratta di una proprietà permanente dell'oggetto FrmScomposizione, esiste finché esiste l'oggetto ed è direttamente accessibile da tutti i suoi metodi.

E' invece necessario dichiarare la variabile aux perché é una variabile locale, viene creata solo nel metodo ed esiste solo finché il metodo è attivo.

Notare la sintassi dell'istruzione condizionale if:

if (condizione) azione;

L'azione viene fatta solo se la condizione argomento di if, che deve essere un valore booleano, è vera.

La struttura completa dell'istruzione condizionale è

if (condizione) azione1;
else azione2;

Se la condizione è vera viene eseguita azione1, altrimenti viene eseguita azione2.

Dopo che un'applicazione ha chiesto un input all'utente è bene che essa controlli se l'input ricevuto è appropriato e, nel caso non lo sia, lo rifiuti. Nel caso in esame l'input deve essere una stringa di caratteri che rappresenti un numero naturale maggiore di zero. Nel seguente esempio si propone una versione migliorata ('idiot proof') del metodo CmdNuovoNumero: leggere bene i commenti.

void __fastcall TFrmScomposizione::CmdNuovoNumero(TObject *Sender)
{
  AnsiString aux = IntToStr(numero);
  if (InputQuery("Scomposizione","Numero?",aux))
    {
      aux = aux.Trim(); //il metodo Trim() della classe AnsiString pulisce la stringa da tutti 
                        //i caratteri vuoti iniziali e finali
      if (aux[1]=='-') aux.Delete(1,1);
                        //aux[1] individua il primo carattere della stringa aux: 
                        //se è un meno, toglierlo
      if ((aux[1]<'1') || (aux[1]>'9'))
                        //le due sbarre verticali rappresentano il connettivo logico 'or' ('vel')
                        //se aux[1] non è una cifra compresa tra 1 e 9 
                        //rifiutare l'input
        {
          ShowMessage("Solo interi positivi.");
          return;
        }
      try               //provare le seguenti istruzioni
        {
          StrToInt(aux);
        }
      catch(...)    //se generano un errore qualunque
        {
          ShowMessage("Solo interi.");
          return;
        }
//a questo punto si può essere ragionevolmente sicuri che l'input sia valido
      numero = StrToInt(aux);
    } 
}

Per rendere più funzionale l'interfaccia FrmScomposizione la si può dotare di un componente che mostri sempre all'utente qual è il numero in elaborazione.

Un componente adeguato è TPanel.

Compilare, salvare e lanciare. L'interfaccia ha ora questo aspetto

interfaccia

Per fare in modo che che la scritta sul pannello PnNumero, cioè il valore della sua Caption venga aggiornato ad ogni input valido dell'utente, si completa il metodo CmdNuovoNumero con la nuova istruzione segnata in rosso:

void __fastcall TFrmScomposizione::CmdNuovoNumero(TObject *Sender)
{
  AnsiString aux = IntToStr(numero);
  if (InputQuery("Scomposizione","Numero?",aux))
    {
      aux = aux.Trim();
      if (aux[1]=='-') aux.Delete(1,1);
      if ((aux[1]<'1') || (aux[1]>'9'))
        {
          ShowMessage("Solo interi positivi.");
          return;
        }
      try
        {
          StrToInt(aux);
        }
      catch(...)
        {
          ShowMessage("Solo interi.");
          return;
        }
      numero = StrToInt(aux);
PnNumero->Caption = IntToStr(numero);
    }
}

prontuario

scomposizione1 scomposizione3

Valid XHTML 1.0