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 to AbstractQWidget::~AbstractQWidget()' In functionArticoli::~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 .cpp

    comunque void tblRight(const QPoint &pos, QTableWidget* tbl) rompe connect(tbl, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(tblRight(QPoint))); mantienilo void 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 qui connect(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 function AbstractQWidget::AbstractQWidget(QWidget*)': error: undefined reference tovtable for AbstractQWidget'
    In function Articoli::qt_metacast(char const*)': error: undefined reference toAbstractQWidget::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 Creator

    P.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 reimplementi

    protected 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!!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.