Solved Riutilizzare funzioni per componenti grafici
-
ciao!
ho varie finestre aabbastanza simili, tutte quanto meno con una QTableWidget.
su ogni QTableWidget devo applicare questo metodo:void Articoli::menuDestro() { if (ui->tblArticoli->rowCount() > 0) { connect(ui->tblArticoli, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); } }
al momento l'ho replicato in ogni QWidget, ma vorrei trovare il modo per metterlo in una classe apposita, in modo da non doverlo riscrivere in ogni QWidget (anche perchè ne ho altri di metodi che seguono questa logica).
il dubbio è su come richiamarlo se lo metto in una classe apposita.
mi dareste una dritta? -
inheritance...
crea una classe base tipo:
class AbstractArticoli : public QWidget{ public: AbstractArticoli(QWidget* parent = nullptr) :QWidget(parent) {} virtual ~AbstractArticoli() = 0; // impedisce di creare oggetti di questo tipo protected slots: void tblRight(QPoint val){ // fai qualcosa } protected: void menuDestro(QTableWidget* tbl) { if (tbl->rowCount() > 0) { connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); } } }; AbstractArticoli::~AbstractArticoli() = default;
e poi ereditala dal tuo widget invece di ereditare direttamente da QWidget
class Articoli : public AbstractArticoli{ // la tua classe };
-
@VRonin
ciao!
grazie, non ci avevo minimamente pensato in effetti.allora, questa la classe base:
#ifndef ABSTRACTQWIDGET_H #define ABSTRACTQWIDGET_H #include <QWidget> #include <QMenu> #include <QTableWidget> class AbstractQWidget : public QWidget { public: AbstractQWidget(QWidget *parent = nullptr) : QWidget(parent) {} virtual ~AbstractQWidget() = 0; protected slots: void tblRight(const QPoint &pos, QTableWidget* tbl) { point = pos; QMenu *menu = new QMenu(this); QAction* actionList = menu->addAction(QString("Listini articolo")); QAction* dtlArt = menu->addAction(QString("Dettaglio articolo")); menu->popup(tbl->viewport()->mapToGlobal(pos)); connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo())); } protected: QPoint point; void menuDestro(QTableWidget *tbl) { if (tbl->rowCount() > 0) { connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); } } }; //AbstractQWidget::~AbstractQWidget() = default; #endif // ABSTRACTQWIDGET_H
a questo punto ho impostato Articoli:
Articoli::Articoli(AbstractQWidget *parent) : AbstractQWidget(parent), ui(new Ui::Articoli) { ........... }
in fase di compilazione ottengo questi errori:
undefined reference toAbstractQWidget::~AbstractQWidget()' In function
Articoli::~Articoli()':
undefined reference to `AbstractQWidget::~AbstractQWidget()'non ho ben capito se e come devo ridefinire anche il distruttore della classe base!
-
@fermatqt said in Riutilizzare funzioni per componenti grafici:
non ho ben capito se e come devo ridefinire anche il distruttore della classe base!
l'hai commentato... e' il
AbstractQWidget::~AbstractQWidget() = default;
andrebbe nel file .cppcomunque
void tblRight(const QPoint &pos, QTableWidget* tbl)
rompeconnect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint)));
mantienilovoid tblRight(const QPoint &pos)
e usa, al suo interno,QTableWidget *tbl = qobject_cast<QTableWidget *>(sender());
-
@VRonin said in Riutilizzare funzioni per componenti grafici:
QTableWidget *tbl = qobject_cast<QTableWidget *>(sender());
si lo avevo commentato perchè mi dava un altro errore:
multiple definition of `AbstractQWidget::~AbstractQWidget()'questo il codice (comprensivo dell'altro tuo consiglio):
#ifndef ABSTRACTQWIDGET_H #define ABSTRACTQWIDGET_H #include <QWidget> #include <QMenu> #include <QTableWidget> class AbstractQWidget : public QWidget { public: AbstractQWidget(QWidget *parent = nullptr) : QWidget(parent) {} virtual ~AbstractQWidget() = 0; protected slots: void tblRight(const QPoint &pos) { QTableWidget *tbl = qobject_cast<QTableWidget *>(sender()); point = pos; QMenu *menu = new QMenu(this); QAction* actionList = menu->addAction(QString("Listini articolo")); QAction* dtlArt = menu->addAction(QString("Dettaglio articolo")); menu->popup(tbl->viewport()->mapToGlobal(pos)); connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo())); } protected: QPoint point; void menuDestro(QTableWidget *tbl) { if (tbl->rowCount() > 0) { connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); } } }; AbstractQWidget::~AbstractQWidget() = default; #endif // ABSTRACTQWIDGET_H
-
@fermatqt said in Riutilizzare funzioni per componenti grafici:
si lo avevo commentato perchè mi dava un altro errore:
multiple definition of `AbstractQWidget::~AbstractQWidget()'@VRonin said in Riutilizzare funzioni per componenti grafici:
andrebbe nel file .cpp
devi spostare quella linea nel file AbstractQWidget.cpp
-
scusami, non sono ancora pratico di ereditarietà e c++!
adesso il file di intestazione è così:
#ifndef ABSTRACTQWIDGET_H #define ABSTRACTQWIDGET_H #include <QWidget> #include <QMenu> #include <QTableWidget> class AbstractQWidget : public QWidget { public: AbstractQWidget(QWidget *parent = nullptr) : QWidget(parent) {} virtual ~AbstractQWidget() = 0; protected slots: void tblRight(QPoint point) { QTableWidget *tbl = qobject_cast<QTableWidget *>(sender()); QMenu *menu = new QMenu(this); QAction* actionList = menu->addAction(QString("Listini articolo")); QAction* dtlArt = menu->addAction(QString("Dettaglio articolo")); menu->popup(tbl->viewport()->mapToGlobal(point)); connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo())); } protected: QPoint point; void menuDestro(QTableWidget *tbl) { if (tbl->rowCount() > 0) { connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); } } }; #endif // ABSTRACTQWIDGET_H
a questo punto riesco a compilare ed avviare il programma.
però al momento in cui clicco col tasto destro sul mouse sulla QTableWidget:QObject::connect: No such slot Articoli::tblRight(QPoint) QObject::connect: (sender name: 'tblArticoli') QObject::connect: (receiver name: 'Articoli')
come se non vedesse lo slot!
-
strano... puoi vedere se con la nuova sintassi l'errore e' piu' comprensibile:
connect(tbl, &QTableWidget::customContextMenuRequested, this, &AbstractQWidget::tblRight);
anche
getListiniArticolo
manca in AbstractQWidget, chiaro se usi la nuova connect anche quiconnect(actionList, &QAction::triggered, this, &AbstractQWidget::getListiniArticolo);
Edit:
Mi sono accorto dell'errore piu' grave, manca
Q_OBJECT
, mea culpa!class AbstractQWidget : public QWidget { Q_OBJECT public: //il resto
questo dovrebbe risolvere il problema QObject::connect: No such slot Articoli::tblRight(QPoint), quello getListiniArticolo rimane
-
ciao!
ieri girovagando avevo già visto Q_OBJECT.
solo che se lo metto ottengo un'altra pletora di errori:
In functionAbstractQWidget::AbstractQWidget(QWidget*)': error: undefined reference to
vtable for AbstractQWidget'
In functionArticoli::qt_metacast(char const*)': error: undefined reference to
AbstractQWidget::qt_metacast(char const*)'
error: undefined reference to `AbstractQWidget::qt_metacall(QMetaObject::Call, int, void**)'
ecc....ho già provato a fare il clean e rebuild.
ma nulla da fare.
questo il codice:#ifndef ABSTRACTQWIDGET_H #define ABSTRACTQWIDGET_H #include <QWidget> #include <QMenu> #include <QTableWidget> class AbstractQWidget : public QWidget { Q_OBJECT public: AbstractQWidget(QWidget *parent = nullptr) : QWidget(parent) {} virtual ~AbstractQWidget() = 0; protected slots: void tblRight(QPoint point) { QTableWidget *tbl = qobject_cast<QTableWidget *>(sender()); QMenu *menu = new QMenu(this); QAction* actionList = menu->addAction(QString("Listini articolo")); QAction* dtlArt = menu->addAction(QString("Dettaglio articolo")); menu->popup(tbl->viewport()->mapToGlobal(point)); connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo())); } protected: QPoint point; void menuDestro(QTableWidget *tbl) { if (tbl->rowCount() > 0) { connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); } } }; #endif // ABSTRACTQWIDGET_H
-
@fermatqt said in Riutilizzare funzioni per componenti grafici:
ho già provato a fare il clean e rebuild.
purtroppo qmake non e' molto intelligente, devi ri-eseguirlo manualmente se cambi il .pro file o se inserisci un
Q_OBJECT
. Ti basta andare su build->run qmake in Qt CreatorP.S.
questo:connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo()));
fallira' per le regioni elencate sopra -
allora, dopo il Run qmake lo compila e lo avvia.
come dicevi te, però, non lanciava getListiniArticolo.
allora l'ho levato dalla classe Articoli, e l'ho messo nella classe base:#ifndef ABSTRACTQWIDGET_H #define ABSTRACTQWIDGET_H #include <QWidget> #include <QMenu> #include <QTableWidget> #include "listiniarticolo.h" class AbstractQWidget : public QWidget { Q_OBJECT public: AbstractQWidget(QWidget *parent = nullptr) : QWidget(parent) {} virtual ~AbstractQWidget() = 0; protected slots: void tblRight(QPoint point) { QTableWidget *tbl = qobject_cast<QTableWidget *>(sender()); QMenu *menu = new QMenu(this); QAction* actionList = menu->addAction(QString("Listini articolo")); //QAction* dtlArt = menu->addAction(QString("Dettaglio articolo")); menu->popup(tbl->viewport()->mapToGlobal(point)); connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo(tbl))); } void getListiniArticolo(QTableWidget *tbl) { int selRow = tbl->row(tbl->itemAt(point)); QString selArt = tbl->item(selRow, 1)->text(); ListiniArticolo *la = new ListiniArticolo(selArt); la->show(); } protected: QPoint point; void menuDestro(QTableWidget *tbl) { if (tbl->rowCount() > 0) { connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); } } }; #endif // ABSTRACTQWIDGET_H
ma ottengo sempre questo errore:
QObject::connect: No such slot Articoli::getListiniArticolo(tbl)
QObject::connect: (receiver name: 'Articoli')ho provato a fare il clean, rilanciare il qmake, ecc.
ma nulla, non lo vede. -
connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo(tbl)));
connect non funziona cosi'... http://doc.qt.io/qt-5/signalsandslots.html
fai cosi':
class AbstractQWidget : public QWidget { Q_OBJECT public: AbstractQWidget(QWidget *parent = nullptr) : QWidget(parent) {} virtual ~AbstractQWidget() = 0; protected slots: void tblRight(QPoint point) { QTableWidget *tbl = qobject_cast<QTableWidget *>(sender()); QMenu *menu = new QMenu(this); QAction* actionList = menu->addAction(QString("Listini articolo")); //QAction* dtlArt = menu->addAction(QString("Dettaglio articolo")); menu->popup(tbl->viewport()->mapToGlobal(point)); connect(actionList, &QAction::triggered, this, &AbstractQWidget::getListiniArticolo); } virtual void getListiniArticolo() = 0; protected: void getListiniArticoloTable(QTableWidget *tbl) { int selRow = tbl->row(tbl->itemAt(point)); QString selArt = tbl->item(selRow, 1)->text(); ListiniArticolo *la = new ListiniArticolo(selArt); la->show(); } protected: QPoint point; void menuDestro(QTableWidget *tbl) { if (tbl->rowCount() > 0) { connect(tbl, &QTableWidget::customContextMenuRequested, this, &AbstractQWidget::tblRight); } } }; #endif // ABSTRACTQWIDGET_H
poi in
Articoli
reimplementiprotected slots: virtual void getListiniArticolo() override {getListiniArticoloTable(ui->tblArticoli);}
-
ciao!
penso di aver capito meglio, ma come mi giro faccio casino :(allora:
#ifndef ABSTRACTQWIDGET_H #define ABSTRACTQWIDGET_H #include <QWidget> #include <QMenu> #include <QTableWidget> #include "listiniarticolo.h" class AbstractQWidget : public QWidget { Q_OBJECT public: AbstractQWidget(QWidget *parent = nullptr) : QWidget(parent) {} virtual ~AbstractQWidget() = 0; protected slots: void tblRight(QPoint point) { QTableWidget *tbl = qobject_cast<QTableWidget *>(sender()); QMenu *menu = new QMenu(this); QAction* actionList = menu->addAction(QString("Listini articolo")); //QAction* dtlArt = menu->addAction(QString("Dettaglio articolo")); menu->popup(tbl->viewport()->mapToGlobal(point)); //connect(actionList, SIGNAL(triggered()), this, SLOT(getListiniArticolo(tbl))); connect(actionList, &QAction::triggered, this, &AbstractQWidget::getListiniArticolo); } virtual void getListiniArticolo() = 0; protected: QPoint point; void menuDestro(QTableWidget *tbl) { if (tbl->rowCount() > 0) { //connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); connect(tbl, &QTableWidget::customContextMenuRequested, this, &AbstractQWidget::tblRight); } } void getListiniArticoloTable(QTableWidget *tbl) { int selRow = tbl->row(tbl->itemAt(point)); QString selArt = tbl->item(selRow, 1)->text(); ListiniArticolo *la = new ListiniArticolo(selArt); la->show(); } }; #endif // ABSTRACTQWIDGET_H
e fino a qui ok.
poi dentro articoli articoli.h:namespace Ui { class Articoli; } class Articoli : public AbstractQWidget { Q_OBJECT public: explicit Articoli(AbstractQWidget *parent = 0); virtual ~Articoli(); protected slots: virtual void getListiniArticolo() override { getListiniArticoloTable(ui->tblArticoli); } private slots: void on_btnCollezione_clicked(); void on_btnGiorni_clicked(); void txtSearch(QString search); //void getListiniArticolo(); void toUpper(const QString &text); private: Ui::Articoli *ui; Database *db; QStringList header; LoadingDialog pd; };
ma ottengo un errore:
error: invalid use of incomplete type ‘class Ui::Articoli’ getListiniArticoloTable(ui->tblArticoli);
forward declaration of ‘class Ui::Articoli’ class Articoli;ho provato a dare un'occhiata su google, ma non ne sono uscito.
credo di aver capito il problema, ma non so come risolverlo.
ho anche provato a cambiare il modificatore di accesso di Ui::Articoli *ui; -
non e' un vero problema solo un piccolo accorgimento tecnico. Invece di lasciare
protected slots: virtual void getListiniArticolo() override { getListiniArticoloTable(ui->tblArticoli); }
nel file .h, trasformalo in dichiarazione+implementazione, cioe'
Nel file .h:
protected slots: virtual void getListiniArticolo() override;
Nel file .cpp
void Articoli::getListiniArticolo(){ getListiniArticoloTable(ui->tblArticoli); }
Il problema e' dovuto al fatto che nel file .h
ui
non e' completamente definito -
perfetto, adesso funziona tutto.
mi alleno un pò su tutti gli altri metodi che devo "condividere", così capisco un pò meglio...grazie mille per l'aiuto!!