Aggiungere una QTableView ad una QTableWidget



  • Buongiorno.
    Ho una QTableWidget ed una QTableView sul mio form. Dovrei, da programma, aggiungere una riga nella QTableWidget e copiarvi dentro l'intera QTableView. Mi dite come possa riuscirci ?
    Grazie.



  • ATTENZIONE

    Se usi questo metodo su tante righe la performance del programma si compromette fortemente.


    #include <QStyledItemDelegate>
    #include <QPainter>
    class TableDelegate : public QStyledItemDelegate{
        Q_DISABLE_COPY(TableDelegate)
    public:
        explicit TableDelegate(QObject* parent = Q_NULLPTR)
            :QStyledItemDelegate(parent)
            , m_baseWid(new QTableView)
        {}
        ~TableDelegate(){
            delete m_baseWid;
        }
        void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE{
            Q_UNUSED(index);
            m_baseWid->resize(option.rect.size());
            QPixmap pixmap(option.rect.size());
            m_baseWid->render(&pixmap);
            painter->drawPixmap(option.rect,pixmap);
        }
        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE{
            Q_UNUSED(option);
            Q_UNUSED(index);
            return m_baseWid->sizeHint();
        }
        void setModel(QAbstractItemModel* mdl){m_baseWid->setModel(mdl);}
        QAbstractItemModel* model() const {return m_baseWid->model();}
    private:
        QTableView* m_baseWid;
    };
    
    const int newRow = tableWidget->model()->rowCount();
    tableWidget->model().insertRow(newRow );
    tableWidget->setSpan(newRow,0,1,tableWidget->model()->columnCount());
    TableDelegate* tableViewDelegate = new TableDelegate(tableWidget);
    tableViewDelegate->setModel(tableView->model());
    tableWidget->setItemDelegateForRow(newRow,tableViewDelegate );
    


  • Imbranato che sono. Ho scritto in questo thread quanto avrei dovuto scrivere in quello degli scacchi.



  • Mi trovo al seguente punto.
    Sul mio Form ho una QTableView che riempio da programma tramite un QStandardItemModel e poi, con un pulsante, vorrei trasferirla interamente in una seconda QTableView nella quale conto di accodarne più di una.
    Se nella creazione del modello inserisco l'istruzione "m_model->setData(m_model->index(riga, colonna), QVariant::fromValue(tempPezzo));", poi col trasferimento nella seconda tabella ottengo questa immagine:0_1521043547024_Schermata del 2018-03-14 17-05-28.png sembra quindi che il contenuto della tabella non venga trasferito e non trasferisce neppure la formattazione delle celle. Se al posto di quella istruzione metto queste 3 istruzioni:

    QStandardItem *item = new QStandardItem();
    item->setData(QVariant(QPixmap::fromImage(ImmaginePezzi[i][j])), Qt::DecorationRole);
    m_model->setItem(riga, colonna, item);
    

    la situazione cambia: ho come vorrei una costruzione grafica dei pezzi degli scacchi, ma non funzionano le mosse e, nel trasferimento, mi trasferisce anche le immagini, ma non la formattazione. Ecco come si presenta:
    0_1521044031171_Schermata del 2018-03-14 17-13-20.png
    Se la pazienza di VRonin non è ancora ancora satura...
    vorrei mantenere le icone dei pezzi grandi almeno nella scacchiera di sinistra, ma dovrei poterli muovere, cosa che mi consente di farlo solo se i pezzi sono di un carattere unicode. Inoltre nel trasferirli a destra, come posso fare per conservare la formattazione delle celle ?
    Mi vergogno per non poterti lasciare in pace.



  • @bvox123 said in Aggiungere una QTableView ad una QTableWidget:

    sembra quindi che il contenuto della tabella non venga trasferito e non trasferisce neppure la formattazione delle celle.

    Viene trasferito, semplicemente non sa come farlo vedere a schermo. Ti sei dimenticato di settare il delegate.

    cosa che mi consente di farlo solo se i pezzi sono di un carattere unicode

    No, non e' vero. Io ho usato i caratteri unicode nel delegate solo per non stare a cercare e includere immagini. Ti basta eliminare displayText nel delegate e aggiungere in paint un controllo per tipo e colore e chiamare painter->drawPixmap con l'immagine giusta e opt.rect per posizione e dimensione

    In pratica il punto centrale qui e' che i dati non hanno nulla a che fare con la loro rappresentazione su schermo. I dati sono rappresentati da QVariant che contengono oggetti di tipo Pezzo, il delegate poi e' quello che si prende la briga di leggere quel pezzo e rappresentarlo come vuole su schermo



  • Ma quanto era bello programmare quando il linguaggio dei computers era costituito da 100 massimo 200 vocaboli. I files si trattavano in modo sequenziale o con ricerche ad indice. I database e le classi sono sicuramente una cosa molto potente che ha reso la programmazione più veloce, ma questo vale solo per chi ne ha piena padronanza. La miriade di classi prodotte, che si intersecano fra loro quasi cinicamente, ne rende la comprensione pressoché impossibile a chi non accetta di seguire corsi appositi per comprenderne la logica sottostante. Per me che non ho la conoscenza e logica di quelle classi il tutto è estremamente ostico. Sono depresso. Cosa potrà mai significare "settare il delegate" ? e poi, perchè inserendo nell'item del modello le immagini queste vengono poi trasferite, mentre inserendo un testo non avviene così ? Ho provafo a vedere dove si possa invocare il metodo displaytext, ma non viene mai richiamato, è solo definito nei due delegate, tra l'altro in modo diverso fra loro, visto che in una delle due dichiarazioni c'è il parametro Q_DECL_OVERRIDE e nell'altro no. Mi chiedo, ma esiste per me la possibilità di seguire corsi online in italiano o, al più, testi anche in solo inglese (purtroppo) non particolarmente complessi che spieghino le classi di Qt in modo progressivo, consentendo ad un incompetente come me di acquisire una padronanza sufficiente per poter andare avanti ?



  • @bvox123 said in Aggiungere una QTableView ad una QTableWidget:

    Ma quanto era bello programmare quando il linguaggio dei computers era costituito da 100 massimo 200 vocaboli. I files si trattavano in modo sequenziale o con ricerche ad indice.

    era un inferno :)

    Cosa potrà mai significare "settare il delegate" ?

    QTableView::setItemDelegate

    perchè inserendo nell'item del modello le immagini queste vengono poi trasferite, mentre inserendo un testo non avviene così ?

    Credo che questo sia il punto centrale che non ti e' chiaro.
    Nel mio modello non inserisco ne testo ne immagini.
    Il modello se ne frega di come i dati vengono rappresentati a video. lui contiene i dati come Pezzo: ne testo, ne immagini.

    Ho provafo a vedere dove si possa invocare il metodo displaytext, ma non viene mai richiamato

    Viene chiamato dalla view. Il sistema model/view/delegate si divide i compiti in questo modo:

    • Il modello contiene i dati per ogni cella
    • la view decide come le singole celle vengono disposte (a tabella, ad albero, a cerchio)
    • il delegate si prende cura di rappresentare a schermo una singola cella

    Nel tuo caso: il modello contiene i Pezzo, la view li dispone a tabella, il delegate controlla che tipo e colore la pedina sia e la rappresenta.

    Se scarichi l'ultima versione del programma ho risolto un paio di bugs e separato il modello dall'interfaccia grafica

    è solo definito nei due delegate

    C'e' solo un delegate. Uno e' l'header che contiene le dichiarazioni e l'altro e' il cpp file che contiene l'implementazione

    Mi chiedo, ma esiste per me la possibilità di seguire corsi online in italiano o, al più, testi anche in solo inglese (purtroppo) non particolarmente complessi che spieghino le classi di Qt in modo progressivo, consentendo ad un incompetente come me di acquisire una padronanza sufficiente per poter andare avanti ?

    Model/View e' un concetto piuttosto avanzato, I testi su cui ho imparato sono:

    Il secondo contiene una sezione molto dettagliata su model/view



  • Se vuoi immagini invece di caratteri cambia:

    pezzodelegate.h

    #ifndef PEZZODELEGATE_H
    #define PEZZODELEGATE_H
    #include <QStyledItemDelegate>
    #include <QHash>
    #include "pezzo.h"
    class PezzoDelegate : public QStyledItemDelegate
    {
        Q_OBJECT
        Q_DISABLE_COPY(PezzoDelegate)
    public:
        QString displayText(const QVariant &value, const QLocale &locale) const Q_DECL_OVERRIDE;
        explicit PezzoDelegate(QObject* parent = Q_NULLPTR);
        void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const Q_DECL_OVERRIDE;
    private:
        QPixmap m_baseMovibile;
        QPixmap m_baseMangiabile;
        const QHash<quint16,QPixmap> m_pixmapCache;
        static quint16 hashKey(Pezzo::Colore col,Pezzo::Tipo typ);
    };
    
    #endif // PEZZODELEGATE_H
    

    pezzodelegate.cpp

    #include "pezzodelegate.h"
    #include "pezzo.h"
    #include "scacchiglobal.h"
    #include <QApplication>
    #include <QPainter>
    QString PezzoDelegate::displayText(const QVariant &value, const QLocale &locale) const{
        Q_UNUSED(locale)
        Q_UNUSED(value)
        return QString();
    }
    
    PezzoDelegate::PezzoDelegate(QObject *parent)
        : QStyledItemDelegate(parent)
        ,m_baseMangiabile(50,50)
        ,m_baseMovibile(50,50)
        , m_pixmapCache({
                std::make_pair(hashKey(Pezzo::Colore::Bianco,Pezzo::Tipo::Pedone),QPixmap("ImmaginePedoneBianco.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Nero,Pezzo::Tipo::Pedone),QPixmap("ImmaginePedoneNero.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Bianco,Pezzo::Tipo::Torre),QPixmap("ImmagineTorreBianca.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Nero,Pezzo::Tipo::Torre),QPixmap("ImmagineTorreNera.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Bianco,Pezzo::Tipo::Cavallo),QPixmap("ImmagineCavalloBianco.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Nero,Pezzo::Tipo::Cavallo),QPixmap("ImmagineCavalloNero.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Bianco,Pezzo::Tipo::Alfiere),QPixmap("ImmagineAlfiereBianco.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Nero,Pezzo::Tipo::Alfiere),QPixmap("ImmagineAlfiereNero.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Bianco,Pezzo::Tipo::Re),QPixmap("ImmagineReBianco.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Nero,Pezzo::Tipo::Re),QPixmap("ImmagineReNero.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Bianco,Pezzo::Tipo::Regina),QPixmap("ImmagineReginaBianca.png"))
                ,std::make_pair(hashKey(Pezzo::Colore::Nero,Pezzo::Tipo::Regina),QPixmap("ImmagineReginaNera.png"))
              })
    {
        QPainter baseMangiabilePainter(&m_baseMangiabile);
        baseMangiabilePainter.setPen(QPen(QBrush(Qt::red),10));
        baseMangiabilePainter.drawRect(5,5,40,40);
        QPainter baseMovibilePainter(&m_baseMovibile);
        baseMovibilePainter.setPen(QPen(QBrush(QColor(108, 161, 247)),10));
        baseMovibilePainter.drawRect(5,5,40,40);
    }
    
    void PezzoDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
        Q_ASSERT(index.isValid());
        QStyleOptionViewItem opt = option;
        initStyleOption(&opt, index);
        if(index.data(ScaccoRole).toInt()==CellaScacco)
            opt.backgroundBrush = QBrush(Qt::red);
        switch(index.data(StatusCellRole).toInt()){
        case PezzoSelezionato:
            opt.backgroundBrush = QBrush(QColor(108, 161, 247));
            break;
        case CellaVuotaMuovibile:
            opt.backgroundBrush = QBrush(m_baseMovibile.scaled(option.rect.size()));
            break;
        case CellaMangiabile:
            opt.backgroundBrush = QBrush(m_baseMangiabile.scaled(option.rect.size()));
            break;
        default:
            break;
        }
        const QWidget *widget = option.widget;
        QStyle *style = widget ? widget->style() : QApplication::style();
        style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
        const Pezzo tempPezzo = index.data().value<Pezzo>();
        if(tempPezzo.valido())
            painter->drawPixmap(opt.rect, m_pixmapCache.value(hashKey(tempPezzo.colore,tempPezzo.tipo)).scaled(opt.rect.size()));
    }
    
    quint16 PezzoDelegate::hashKey(Pezzo::Colore col, Pezzo::Tipo typ){
        return (static_cast<quint16>(col) << 8) | static_cast<quint16>(typ);
    }
    

    Ovviamente devi sostiturire "ImmaginePedoneBianco.png" etc con i percorsi alle immagini che vuoi



  • Grazie. Comunque di delegate ce ne sono 2: PezzoDelegate e TableDelegate.



  • Con la modifica che mi hai suggerito ieri per poter inserire immagini degli scacchi nella tabella a schermo, vedo che il costruttore di PezzoDelegate contiene una sfilza di parametri che indirizzano alle immagini opportune. Ma io dovrei prima caricarle in una tabella di Image e non ho la possibilità di farlo nel corpo del costruttore, perché fra i parametri si aspetta che siano già caricate.
    Come potrei fare per caricarle prima che venga invocato il PezzoDelegate ?



  • @bvox123 said in Aggiungere una QTableView ad una QTableWidget:

    Ma io dovrei prima caricarle in una tabella di Image

    QHash<quint16,QPixmap> e' una tabella di images.

    in ogni caso ti basta togliere const davanti a const QHash<quint16,QPixmap> m_pixmapCache; e poi puoi assegnare le immagini quando vuoi.

    @bvox123 said in Aggiungere una QTableView ad una QTableWidget:

    Comunque di delegate ce ne sono 2: PezzoDelegate e TableDelegate.

    Si, sono solo rimbabmbito, stavo guardando solo a progetto su github

    P.S.
    Visto quello che stai pensando di fare, l'ultima versione che ho caricato su github ha OggettoScacchi::registroMosse e OggettoScacchi::muovi(const Mossa&) per registrare e riprodurre le mosse


Log in to reply
 

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