PDA

Visualizza la versione completa : [Qt - C++] Add-remove widget runtime


ing82
24-03-2017, 16:16
Vorrei realizzare una finestra in cui, al variare ad esempio dell'elemento selezionato di una ComboBox,
cambia il widget visualizzato. Il widget visualizzato, fa parte di una gerarchia di oggetti derivati da una classe base.

Forse con qualche riga di codice diventa piu' facile intendersi.


class Base: public QWidget
{
//questa e' la classe base coi suoi metodi
enum Type: unsigned int
{
_Derived1,//0
_Derived2,//1
_TypeNumber//2
}
}

class Derived1: public Base
{
//primo tipo di widget
}

class Derived2: public Base
{
//secondo tipo di widget
}

class WidgetContainer: public QWidget
//e' il widget che contiene la combobox e il widget 'variabile a runtime' da visualizzare
{
Q_OBJECT

public:

WidgetContainer(QWidget* parent = 0):
QWidget(parent),
mLayout(new QVBoxLayout(this)),
mComboBox(new QComboBox(this)),
mVariableWidget(new Derived1())
{
mLayout->addWidget(mComboBox);
mLayout->addWidget(mVariableWidget);

//cambio l'indice della combobox, cambia il widget wisualizzato
connect(mComboBox,SIGNAL(indexChanged(int)),this,c hangeWidget(int));

}

private slots:

void changeWidget(const int& index)
{
//pensavo di fare in questo modo:
// prima tolgo il widget dal layout
mLayout->removeWidget(mVariableWidget);
// poi lo cancello
delete mVariableWidget;
// poi creo il nuovo widget, ad esempio mediante il metodo static di una classe Factory, e durante la creazione dico che il parent del nuovo VariableWidget e' this
mVariableWidget = VariableWidgetFactory::make(index);
//aggiungo il nuovo widget appena creato al layout
mLayout->addWidget(mVariableWidget);
//vedi testo sotto per alcuni commenti
}

private:

QVBoxLayout* mLayout;

QComboBox* mCombobox;

Base* mVariableWidget;
}



Il dubbio e': se chi usa il programma, seleziona la combobox e poi con la rotella del mouse fa cambiare l'indice 'a raffica', devo altrettanto a raffica distruggere e creare oggetti e tornare a visualizzarli, cosa che non mi sembra ottimale.

Un'alternativa che mi veniva in mente e' la seguente:
io so a priori quanti sono i possibili widget da visualizzare, e cioe' tanti quanti il numero di classi derivate da Base: nell'esempio sopra ad esempio 2.

Nella classe ContainerWidget, al posto di Base* mVariableWidget, potre quindi mettere


Base* mVariableWidget[Base::_TypeNumber];

e aggiungere una variable che tiene l'indice del VariableWidget attualmente visualizzato

unsigned int mIndex;

Nel costruttore quindi, potrei fare:

mVariableWidget[Base::_Derived1](new Derived1()),
mVariableWidget[Base::_Derived2](nullptr)

poi


mLayout->addWidget(mVariableWidget[Base::_Derived1]);
mIndex = Base::_Derived1;

e visualizzare coerentemente la combobox sull'indice Base::_Derived1 e il widget associato.


Il metodo changeWidget potrebbe quindi diventare



void changeWidget(const int& index)
{
mLayout->removeWidget(mVariableWidget[mIndex]);
mVariableWidget[mIndex]->setVisible(false);//oppure uso ->hide(), fa qualche differenza?
if(!mVariableWidget[index])
{
//creo il nuov widget, e lo setto con parent this
}
mLayout->addWidget(mVariableWidget[index]);//in alternativa posso usare insertWidget, con l'indice relativo, se dopo il variable widget ce ne sono altri
if(!mVariableWidget[index]->isVisible())
{
mVariableWidget[index]->setVisible(true);
}
mIndex = index;
}


creando i widget solo se viene richiesto, una sola volta, avendoli a disposizione senza ricrearli se devono essere rivisualizzati, e distruggendoli, sempre una sola volta, solo alla fine.

Ci sono strade alternative?

Grazie

shodan
25-03-2017, 15:43
Non sono ferrato il QT, tuttavia la tua idea si chiama pattern FlyWeight.
Per quanto riguarda la creazione degli oggetti, personalmente opterei per crearli tutti all'inizio e non man mano che servono. Tanto prima o poi verranno creati tutti. Ciò che vorrei da una UI è responsività, non che proceda a strappi perché un oggetto è grosso da creare.
Ma è opinione puramente personale.

MItaly
27-03-2017, 01:30
In Qt normalmente questa cosa di solito viene gestita creando tutti i widget all'inizio dentro un QStackedWidget (http://doc.qt.io/qt-5/qstackedwidget.html).


The QStackedWidget class provides a stack of widgets where only one widget is visible at a time.
[...]
QStackedWidget provides no intrinsic means for the user to switch page. This is typically done through a QComboBox or a QListWidget that stores the titles of the QStackedWidget's pages. For example:


QComboBox *pageComboBox = new QComboBox;
pageComboBox->addItem(tr("Page 1"));
pageComboBox->addItem(tr("Page 2"));
pageComboBox->addItem(tr("Page 3"));
connect(pageComboBox, SIGNAL(activated(int)),
stackedWidget, SLOT(setCurrentIndex(int)));

Il combobox si limiterà a cambiare il currentIndex del QStackedWidget.

ing82
27-03-2017, 09:34
Grazie a tutti!


In Qt normalmente questa cosa di solito viene gestita creando tutti i widget all'inizio dentro un QStackedWidget (http://doc.qt.io/qt-5/qstackedwidget.html).

Il combobox si limiterà a cambiare il currentIndex del QStackedWidget.

Ne approfitto per una domanda ulteriore: ma dove trovo una 'panoramica' di tutto quello che e' possibile fare con Qt, o meglio, di quali problemi sono gia stati risolti da chi ha implementato il tutto, come in questo caso, senza intraprendere strade alternative contorte e relativa perdita di tempo?

Anche solo un elenco delle classi che compongono il sistema con la descrizione di cosa fanno e a cosa servono.

Cercavo un qualcosa di organizzato a partire dal generale (ad esempio Layout, e poi l'elenco dei vari layout implementati con le loro caratteristiche), Button, elenco dei Button e tutti i derivati e quando si usano, ecc (che in realta' per i due esempi che ho citato, Layout e Button, questo lavoro c'e', ma in un caso come il mio, io come faccio a sapere che e' gia' stata pensata una soluzione al problema, e quindi che classe devo cercare per leggermi la relativa documentazione?).

Sperando di esser stato spiegato ( :D ), grazie nuovamente!

ing82
30-03-2017, 11:06
Mi autoquoto perche' avevo risposto, ma dalla schermata del forum figurava come se non avessi mai risposto...

Grazie a tutti!



Ne approfitto per una domanda ulteriore: ma dove trovo una 'panoramica' di tutto quello che e' possibile fare con Qt, o meglio, di quali problemi sono gia stati risolti da chi ha implementato il tutto, come in questo caso, senza intraprendere strade alternative contorte e relativa perdita di tempo?

Anche solo un elenco delle classi che compongono il sistema con la descrizione di cosa fanno e a cosa servono.

Cercavo un qualcosa di organizzato a partire dal generale (ad esempio Layout, e poi l'elenco dei vari layout implementati con le loro caratteristiche), Button, elenco dei Button e tutti i derivati e quando si usano, ecc (che in realta' per i due esempi che ho citato, Layout e Button, questo lavoro c'e', ma in un caso come il mio, io come faccio a sapere che e' gia' stata pensata una soluzione al problema, e quindi che classe devo cercare per leggermi la relativa documentazione?).

Sperando di esser stato spiegato ( :D ), grazie nuovamente!

MItaly
30-03-2017, 12:36
Mm nella documentazione ufficiale c'è la lista di tutte le classi, poi tanto ovviamente lo fa l'esperienza... in questo caso specifico comunque (e in generale nel sapere che widget esistono già) mi ha aiutato il fatto di aver "giocato" tante volte nel designer, provando a vedere tutti i widget disponibili e come si comportano.

Loading