Aggiungere una QTableView ad una QTableWidget
-
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 );
-
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: 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:
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 inpaint
un controllo per tipo e colore e chiamarepainter->drawPixmap
con l'immagine giusta eopt.rect
per posizione e dimensioneIn 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 tipoPezzo
, 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 comePezzo
: 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 -
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 aconst 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 haOggettoScacchi::registroMosse
eOggettoScacchi::muovi(const Mossa&)
per registrare e riprodurre le mosse