Riutilizzo di elementi dell'interfaccia utente tra due diversi QWidgets

2

Sto scrivendo un'utilità in C ++ con Qt che comunica con un dispositivo incorporato. Inizialmente il programma sarebbe stato utilizzato per tracciare i dati dal dispositivo, ma è stato aggiunto un nuovo requisito (non da me, nessun controllo su di esso). Quindi ora ha due modalità e quindi due classi:

  1. DevicePlotWindow
  2. DeviceDebugWindow

Entrambe le modalità fanno esattamente la stessa cosa tranne per l'output, ovvero i dati di plot e scrivono un messaggio di log sulla console di debug, rispettivamente.

Ecco dove diventa un po 'complicato. La seconda modalità era già uno strumento standalone esistente, che sarà deprecato e integrato in questo programma. La richiesta da parte degli utenti è di mantenere lo stesso aspetto e lo stesso aspetto del vecchio strumento.

Questo significa che nella mia utilità, ho due modalità funzionali molto simili, ma con un aspetto completamente diverso.

L'ho già implementato copiando e incollando gli elementi dell'interfaccia utente e le loro funzionalità in termini di comunicazione con il dispositivo. Ma odio rompere ASCIUTTO.

Qual è il modo migliore e più pulito per "condividere" gli elementi dell'interfaccia utente e i corrispondenti gestori di funzioni dei membri con entrambe le modalità (classi)? Sono a conoscenza dell'eredità, ma mi piacerebbe sapere cosa hanno in mente gli altri e il modo migliore per farlo.

Esempio:

class DevicePlotWindow : public QWidget {
    private:
        ...
        Plot plot_;
        QSpinBox address_;
        QSpinBox data_;

    public:
        ...
        void plot();
        void on_address_value_changed(int val);
        void on_data_value_changed(int val);
};

class DeviceDebugWindow : public QWidget {
    private:
        ...
        QPlainTextEdit console_;
        QSpinBox address_;
        QSpinBox data_;

    public:
        ...
        void write_console(QString const &msg);
        void on_address_value_changed(int val);
        void on_data_value_changed(int val);
};
    
posta ctzdev 31.01.2018 - 05:38
fonte

1 risposta

1

La soluzione più semplice che vedrei e che in genere vorrei utilizzare, se hai due classi che sono quasi identiche ma che differiscono solo nel modo in cui generano i dati, è una classe che ha ciò che è comune e dipende da un'astrazione per l'output.

Nonvedodavverounmodopiùdirettodiquello.OvviamenteIOutputpotrebbeessereunoopiùoggettifunzioneinC++rispettoaun'interfacciacomeunesempio,malostessotipodiideadibase.Edèpossibileutilizzarelacomposizioneperiniettareun'istanzadiunafinestraconl'outputterappropriatosullacostruzionechepuòmemorizzarecomemembroanzichélefinestredisottotitoli(cheporterebberoaunmaggioreaccoppiamento).Un'altraalternativaspecificaperC++èdirendereWindowunmodellodiclasseegenerareledueversionidellafinestra(unafinestradidisegno,unafinestradidebug),facendoancoraaffidamentosullastessainterfacciadibase/astrazione(anchelastessaideadibase).

Iltruccoprincipaleèprogettarequell'appropriatainterfacciaIOutput.Adesempio,seènecessarioarchiviareiwidgetQtperlaversione"debug" e aggiungerli al layout della finestra, potrebbe essere necessario passare il layout della finestra per aggiungervi eventuali widget appropriati e quindi chiamare un tipo astratto output di funzione per aggiornare il widget di outputter in modo appropriato. Oppure puoi facoltativamente restituire un QWidget in IOutput che la finestra aggiunge al suo layout. Qualcosa di simile. Hai bisogno di un modo per afferrare il widget per un outputter per la finestra da aggiungere al suo layout attraverso questa astrazione.

E allo stesso modo queste due funzioni:

    void plot();
    void write_console(QString const &msg);

Devi essere unificato in una output idea / firma. Diventano la funzione output dell'estratto analogico. Quindi vuoi passare qualcosa insieme che fornisca informazioni sufficienti per far sì che entrambi i produttori facciano le loro cose: per il plotter per tracciare i dati e per la versione di debug per convertirlo in una stringa e mostrarlo all'interno di un campo di testo.

Avrei bisogno di vedere un po 'più di codice per suggerire il modo più semplice per ottenere il design del IOutput analogico. Ma spero che tu abbia l'idea e possa vedere come farlo piuttosto rapidamente, ed è così che suggerirei di affrontare questo problema. Avete la finestra concreta e dipende da un'interfaccia di outputter astratta, e diversi outputter concreti possono sostituire le funzionalità appropriate richieste per uno specifico tipo di output.

What is the best, cleanest way to "share" the UI elements and their corresponding member function handlers with both modes (classes)?

Solo per questo tipo generale di problema, vedi se riesci a invertire un po 'il pensiero. Invece di pensare a come condividere lo stesso codice ridondante in due classi che vogliono condividere la maggior parte dello stesso codice, implementare il codice una volta e pensare a come creare un'astrazione che permetta alle parti uniche, non condivise, di divergere. Strategia simile se si sta rifattorizzando una lezione con il senno di poi. Invece di copiare e incollare il codice da qualche altra parte solo per cambiare un po ', vedi come puoi rifattorizzare la classe per evitare direttamente a seconda dei dettagli concreti per le parti che devono divergere mentre si crea un'astrazione da cui dipendere.

È la chiave per arrivare prima a questi tipi di astrazioni piuttosto che a posteriori. Per un esempio di tipo CS di base, invece di implementare un quicksort per due diverse strutture di dati ad accesso casuale e quindi cercare di capire come "condividere il codice", implementarlo una volta lontano da qualsiasi struttura dati specifica e mentre stai implementando , vieni con l'astrazione appropriata (concetto di iteratore ad accesso casuale, ad esempio) che gli consente di lavorare per qualsiasi struttura di dati conforme.

    
risposta data 31.01.2018 - 15:48
fonte

Leggi altre domande sui tag