Implementazione del codice GUI per una specifica classe Window / Form

2

Terminologia

Elemento elemento / modulo - > Campi come lista di testo, caselle combo, pulsanti, ecc.

Problema

Ho un programma che fondamentalmente è un fat client che si interfaccia in un sistema che tiene traccia dei semafori.

In questo programma esiste un modulo. Il modulo contiene diverse sottomaschere. Come è adesso, alcune sottomaschere hanno le loro classi, e alcune delle sottomaschere sono completamente controllate dalla classe del modulo principale.

La classe del form principale ha un metodo validato che viene chiamato quando il modulo viene inviato e chiama i metodi di convalida all'interno delle sottomaschere, oltre a eseguire la convalida su alcuni degli elementi del modulo che non hanno le proprie classi.

Non sono venduto su questa architettura, poiché ritengo che dovrebbe essere coerente (ogni sottomaschera dovrebbe avere una sua classe, o nessuna sottomaschera dovrebbe avere la sua classe.

Il mio problema sta nell'implementazione degli avvisi di gestione. Al momento, quando un elemento viene convalidato, la convalida genera un errore o un avvertimento. Se si tratta di un errore, l'utente deve correggere la casella per soddisfare i requisiti di convalida dei moduli. Se si tratta di un avviso, l'utente deve essere informato di tale avviso e quindi inviare il modulo una seconda volta.

Se si verifica un avviso, ho creato un flag che verrà impostato. Prima che le informazioni contenute negli elementi del modulo possano essere accettate, il modulo controlla innanzitutto se sono stati generati errori. Nel caso in cui non ci siano errori, controlla gli avvisi. Se il flag di avviso è impostato, visualizza l'avviso. La prossima volta che viene chiamato questo metodo, il flag di avviso viene attivato all'interno del metodo di convalida.

Non mi piace molto questa implementazione, perché in pratica significa che hai questa bandiera canaglia che dovrebbe essere cancellata in base ai requisiti. Ho pensato di implementarlo come una macchina a stati, tuttavia ti imbatti nello stesso problema in cui lo stato del modulo verrebbe impostato in vari punti all'interno della classe in base ai requisiti (Uno dei campi modificati, ripristinato allo stato iniziale , ecc.)

L'altro problema che ho riscontrato è che il flag di avviso è di proprietà della classe form principale. Posso creare un puntatore al form principale dalla sottomaschera e quindi impostare il flag da lì.

Tutto questo sembra molto goffo, e sento che potrebbe creare molta confusione. Per me deve esserci un modo migliore per architettarlo.

EDIT: aggiunta di codice per il contesto

bool MainForm::callback_pushbutton_submit_clicked( const FormEvent&)
{
    if ( validate_all_forms() )
    {
        //display error
    }
    else if ( get_warning_displayed_flag() )
    {
        //display warning
    }
    else
    {
        //submit form
    }

}

bool MainForm::validate_all_forms()
{   
    bool error = false;
    bool display_warning = false;
    error |= subform1.validate();
    error |= subform2.validate();
    //...

    //perform some validation on subforms that are controlled within the main form
    if ( !(my_date_field.validate() )
    {
        display_warning = true;
    }
    //....

    if( error )
    {
        //format error message
        //clear warning flag
    }
    else if ( display_warning )
     if ( !get_display_warning_flag() )
     {
        //get warning message
     }
     invert_warning_display_flag()
}
return error;
    
posta Triplell89 26.06.2014 - 17:21
fonte

1 risposta

2

Cito la tua domanda e aggiungo del codice (è più facile parlarne in seguito):

In this program exists a form. The form contains several subforms. As it is right now, some of the subforms have their own classes, and some of the subforms are just controlled completely from the class of the main form.

struct subform { virtual bool validate() const = 0; };

struct warning { element& f; string message; }
struct error { /* subform or element reference list, and a message here */ };

The main form class has a validate method which is called when the form is submitted and calls validation methods within the subforms, as well as performing validation on some of the form elements that don't have their own classes.

class form {
    vector<unique_ptr<subform>> subforms;

    bool is_valid() const
    {
        auto sf_valid = [](const unique_ptr<subform>& sf){
            return sf->validate();
        });
        if(all_of(begin(subforms), end(subforms), sf_valid))
        {
            // custom *this validation code
            return true;
        }
        return false;
    }
    void update_data()
    {
        // update all data here, based on the content of the
        // forms and fields in *this
    }
public:
    void submit()
    {
        if(is_valid())
        {
             update_data();
             // submit form here (whatever that means)
        }            
    }

};

Questa architettura è scritta solo per il caso positivo. Spetta a te se desideri trattare warning e error come eccezioni, oppure no.

Se li tratti come eccezioni, pubblicali in subform::validate e in form::is_valid , e prendi e gestisci tutto ciò, in form :: submit () '.

Se li tratti come casi non eccezionali (ovvero parte del normale flusso di applicazioni e non errori effettivi), invece di restituire bool da subform::validate e form::is_valid , restituisci un tipo definito dall'utente che converte in bool e ha accessors per qualsiasi error (s) e warning (s) emessi.

In submit, sul ramo else o in un blocco catch , devi reimpostare i campi e le sottomaschete a cui si fa riferimento nelle istanze error o warning ricevute.

Modifica (spiegazione):

Hai menzionato di aver eliminato la bandiera per errore / successo. Questa implementazione suddivide la convalida dalla fase di commit (aggiornamento dei dati e invio) e la convalida è const (le funzioni non alterano lo stato e propagano le informazioni in base al valore di ritorno / lancio).

È quindi possibile (se necessario), rifattorizzare il codice di convalida personalizzato nel modulo in nuove sottomaschere.

    
risposta data 26.06.2014 - 18:45
fonte

Leggi altre domande sui tag