PDA

View Full Version : QtableWidget UNDO



afro_cv
15th August 2011, 15:44
Is there any sign like editingFinished () to a cell QTableWidget?

I am doing a program, when editing a cell value of a QTableWidget, if a valid value changes its value is changed, otherwise the value remains.

PS: Sorry for my english

wysota
15th August 2011, 16:08
If you want to do it this way then provide a custom delegate for your widget and in the createEditor() method connect to appropriate signals of the editor. But in general it'd be much easier to either reimplement the setModelData() method in the delegate or reimplement QTableWidgetItem::setData(). The cleanest solution would be to use model-based approach and implement QAbstractItemModel::setData() properly.

afro_cv
15th August 2011, 18:13
You can make a mini example for i see?

wysota
15th August 2011, 18:18
An example of what?

afro_cv
21st August 2011, 00:20
an example of how i can make that. Because i dont understand how

wysota
21st August 2011, 08:12
What is exactly that you don't know how to do?

afro_cv
30th August 2011, 22:37
#ifndef MUDACELULA_H
#define MUDACELULA_H
#include <QAbstractItemModel>
#include <QMessageBox>
class mudaCelula: public QAbstractItemModel
{

Q_OBJECT

public:
mudaCelula(QObject *parent=0);
virtual bool setData ( const QModelIndex & index, const QVariant & value, int role = Qt::EditRole ) ;
short int isUnique(QString pesq);
};

#endif // MUDACELULA_H








#include "mudacelula.h"
#include<QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
mudaCelula::mudaCelula(QObject *parent):QAbstractItemModel(parent)
{
}

bool mudaCelula::setData ( const QModelIndex & index, const QVariant & value, int role )
{
if(!isUnique("SELECT COUNT(*) FROM M_CASEIRA WHERE UPPER(DESIG_CASEIRA)=UPPER(\""+value.toString()+"\");"))
{ QMessageBox a;
a.setText("A designação caseira introduzida já existe.");
a.exec();
return false;
}
else{
emit dataChanged(index,index);
return true;
}
}


short int mudaCelula::isUnique(QString pesq)
{

if (QSqlDatabase::database().isOpen())
{
QSqlQuery resPesq;

if( resPesq.exec(pesq))
{
bool consegui=resPesq.next();
if( consegui && (!resPesq.record().value(0).toInt()))
return 1;
}

}

return 0;

}



This is that class you tell me to re-implemente to put in tablewidget.setmodel();

You can see wath is wrong?


mudacelula.h:6: because the following virtual functions are pure within 'mudaCelula':

BDNUTRI-build Desktop\..\..\..\QtSDK\Desktop\Qt\4.7.3\mingw\incl ude\QtCore\qabstractitemmodel.h:171: virtual QModelIndex QAbstractItemModel::index(int, int, const QModelIndex&) const

BDNUTRI-build-desktop\..\..\..\QtSDK\Desktop\Qt\4.7.3\mingw\incl ude\QtCore\qabstractitemmodel.h:182: virtual QVariant QAbstractItemModel::data(const QModelIndex&, int) const

BDNUTRI-build-desktop\..\..\..\QtSDK\Desktop\Qt\4.7.3\mingw\incl ude\QtCore\qabstractitemmodel.h:179: virtual int QAbstractItemModel::columnCount(const QModelIndex&) const

wysota
30th August 2011, 22:43
Are you sure you know what you are doing? If you subclass QAbstractItemModel, you need to implement more methods than just setData(). Besides, your implementation doesn't make any sense.

afro_cv
1st September 2011, 21:35
#include "mudacelula.h"
#include<QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
mudaCelula::mudaCelula(QObject *parent):QAbstractTableModel(parent)
{
}

int mudaCelula::rowCount(const QModelIndex &parent) const
{
int conta=contador("SELECT COUNT(*) FROM GRUPO;");
return conta;
}

int mudaCelula::columnCount(const QModelIndex &parent) const
{
return 3;
}

QVariant mudaCelula::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role == Qt::TextAlignmentRole) {
return int(Qt::AlignRight | Qt::AlignVCenter);
}
//else if (role == Qt::DisplayRole) {

return QVariant();
}
bool mudaCelula::setData ( const QModelIndex & index, const QVariant & value, int role )
{QMessageBox msgErro2;

if (index.isValid() && role == Qt::EditRole) {

QMessageBox msgErro;
int conta=contador("SELECT COUNT(*) FROM GRUPO WHERE UPPER(DESIG_GRUPO)=UPPER(\""+value.toString()+"\");");
msgErro2.setText(QString::number(conta)+"\n"+"SELECT COUNT(*) FROM GRUPO WHERE UPPER(DESIG_GRUPO)=UPPER(\""+value.toString()+"\");");
msgErro2.exec();
switch(conta)
{
case -1:
msgErro.setText("Erro na conexão com a Base de Dados.\nNão foi possÃ*vel introduzir a Medida SI.");
msgErro.exec();
break;

case 0:emit

emit dataChanged(index,index);
return true;
break;

default:
msgErro.setText("A designação caseira introduzida já existe.");
msgErro.exec();
break;
}

return (conta==0);
}
return false;
}




int mudaCelula::contador(QString pesq)
{

if (QSqlDatabase::database().isOpen())
{
QSqlQuery resPesq;
if( resPesq.exec(pesq))
{
if(resPesq.next())
return (resPesq.record().value(0).toInt());
}

}

return -1;

}



Qt::ItemFlags mudaCelula::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags ;
if (index.column()>0)
flags =QAbstractTableModel::flags(index)| Qt::ItemIsEditable | Qt::ItemIsEnabled;
else
flags = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
return flags;
}



QVariant mudaCelula::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();

if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return tr("");

case 1:
return tr("Grupo");

case 2:
return tr("Informação");
default:
return QVariant();
}
}
return QVariant();
}





After more google search this and read qt documentation this is my new code. Why my implementation doesnt make sense?
I have 3 question

1. My problem now is with rowcont, if i put a number everything is work..but i want dinaymic something like that:



int mudaCelula::rowCount(const QModelIndex &parent) const
{
int conta=contador("SELECT COUNT(*) FROM GRUPO;");
return conta;
}


2. How after emit datachanged i can update qtableview? i search but i dont find. I have this:




connect(oi,SIGNAL(dataChanged(QModelIndex,QModelIn dex)),this, SLOT(dataChanged(QModelIndex,QModelIndex)));

void Ingrediente::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
//ui->tableView->dataChanged(topLeft, bottomRight);
ui->tableView->viewport()->update();
}






3.

in qtablewidget i put this to show checkbox in the first collum:


QTableWidgetItem *qItem = new QTableWidgetItem();
qItem->setFlags(Qt::ItemIsEnabled|Qt::ItemIsUserCheckable );


now in my subclass mudaCelula i put:



Qt::ItemFlags mudaCelula::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags ;
if (index.column()>0)
flags =QAbstractTableModel::flags(index)| Qt::ItemIsEditable | Qt::ItemIsEnabled;
else
flags = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
return flags;
}



What i doing wrong? Because checbox doesnt show.


If tell how to resolve or a link to learn more..i thk you.

PS:Sorry for my english

wysota
2nd September 2011, 00:05
Your implementation doesn't make any sense because your model has no data. I don't even understand how you belive this might work. I suggest you take a look at examples of existing models in the docs if you want to make your own. The other thing that doesn't make any sense is that you are using QTableWidget which doesn't even use a model. There are a couple of other nonsense things I could point out here but they are not relevant until you understand what you are doing.

afro_cv
2nd September 2011, 03:11
Wysota, I think because of my English, you did not understand very well what I wrote or I did not express myself properly.

1. I know the QTablewidget does not accept Model. What I was saying is that before moving to the QTableView, had been playing with QTableWidget until I find the restriction of not being able to control when the data are edited in the cell. But until then, i had managed to implement a checkbox in QTableWidget, but when I moved to QTableView could not do the same. The checkbox does not appear

2. Regarding the models, I had seen the examples and I know that everyone takes a vector, hash, or list or other data . Just what I was wondering if you could do without it, using only the search sql to give the number of lines.´

wysota
2nd September 2011, 09:36
Wysota, I think because of my English, you did not understand very well what I wrote or I did not express myself properly.
I'm reading your code, I can see what it does and what it does not do.


2. Regarding the models, I had seen the examples and I know that everyone takes a vector, hash, or list or other data . Just what I was wondering if you could do without it, using only the search sql to give the number of lines.´
You can do without it but your implementation doesn't try to. Your data() implementation doesn't return any data and your setData() implementation doesn't modify any data. And if you intend to make an SQL query every time the model is queried for anything, it will be very slow. When a view is initialized, the model is queried several times per row. Multiply that by the number of rows and think whether this is acceptable.

afro_cv
4th September 2011, 04:42
Header File


#ifndef GRUPOMODEL_H
#define GRUPOMODEL_H
#include <QAbstractTableModel>
#include <QList>
#include <grupoclass.h>
#include <QMessageBox>
#include <QWidget>
class GrupoModel : public QAbstractTableModel
{

public:
GrupoModel(QObject *parent = 0);
void setGrupoList(const QList<GrupoClass> &list);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
bool setData(const QModelIndex &index, const QVariant &value,int role);
void setParenti(QWidget *parenti);

private:
QString grupoAt(int row, int col) const;
bool checkAt(int row) const;
QList<GrupoClass> grupoList;
QString temp;
QWidget *parentias;
};

#endif // GRUPOMODEL_H




CPP FILE


#include "grupomodel.h"
#include <QMessageBox>
#include <QAbstractTableModel>
GrupoModel::GrupoModel(QObject *parent) : QAbstractTableModel(parent)
{
}

int GrupoModel::rowCount(const QModelIndex &parent) const
{
return grupoList.count();
}

int GrupoModel::columnCount(const QModelIndex &parent) const
{
return 3;
}

QString GrupoModel::grupoAt(int row, int col)const
{
QString retorno;
switch(col)
{
case 0: retorno="";break;
case 1: retorno=grupoList[row].Designacao();break;
case 2: retorno=grupoList[row].Informacao();break;
}

return retorno;
}

void GrupoModel::setGrupoList(const QList<GrupoClass> &list)
{
grupoList=list;
reset();
}

QVariant GrupoModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();

if (role == Qt::TextAlignmentRole) {
return int(Qt::AlignLeft | Qt::AlignVCenter);
}
else if (role == Qt::DisplayRole) {

return grupoAt(index.row(),index.column());

}
else if (role == Qt::EditRole)
{
return grupoAt(index.row(),index.column());
}
else if ((!index.column()) &&(role==Qt::CheckStateRole))
{
if (grupoList[index.row()].Check())
return Qt::Checked;
else
return Qt::Unchecked;
}
return QVariant();

}

Qt::ItemFlags GrupoModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags ;
if (index.column()>0)
flags =QAbstractTableModel::flags(index)| Qt::ItemIsEditable | Qt::ItemIsEnabled;
else
flags = Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
return flags;
}



QVariant GrupoModel::headerData(int section, Qt::Orientation orientation, int role) const
{


if (role != Qt::DisplayRole)
return QVariant();

if (orientation == Qt::Horizontal) {
switch (section) {
case 0:
return tr("");

case 1:
return tr("Grupo");

case 2:
return tr("Informação");
default:
return QVariant();
}
}

return QVariant();
}


bool GrupoModel::setData ( const QModelIndex & index, const QVariant & value, int role )
{
QMessageBox msgErro;

if (index.isValid() && role == Qt::EditRole)
{QMessageBox a;
a.setText(value.toString());
a.exec();
QMessageBox::warning(parentias,"","teste");
if (index.column()==1)
{
GrupoClass a(value.toString(),"",false);

if(grupoList.contains(a))
{
msgErro.setText("O grupo introduzido já existe.");
msgErro.exec();
return false;
}
else
{grupoList[index.row()].setDesignacao(value.toString());
}
}

emit dataChanged(index,index);
return true;
}

if (index.isValid() && role == Qt::CheckStateRole)
{
grupoList[index.row()].setCheck(!grupoList[index.row()].Check());
emit dataChanged(index,index);
return true;
}
return false;
}



void GrupoModel::setParenti(QWidget *parenti)
{
parentias=parenti;
}


bool GrupoModel::checkAt(int row)const
{
return grupoList[row].Check();
}







I Have Problems here because emit CloseEditor
Comipler error QObject::installEventFilter(): Cannot filter events for objects in a different thread..

I base in the Qt demo code Spreadsheet, and some other codes like spinboxdelegate..
You can give-me a ideia what i make wrong for i can search.




#include <QtGui>
#include "tabledelegate.h"
#include <QMessageBox>
#include <QLineEdit>

TableDelegate::TableDelegate(QObject *parent)
: QItemDelegate(parent) {}

QWidget *TableDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &,
const QModelIndex &index) const
{
QLineEdit *editor = new QLineEdit(parent);
connect(editor, SIGNAL(editingFinished()),this, SLOT(commitAndCloseEditor()));
return editor;
}

void TableDelegate::commitAndCloseEditor()
{
QLineEdit *editor = qobject_cast<QLineEdit *>(sender());
emit commitData(editor);
emit closeEditor(editor);
}

void TableDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
edit->setText(index.model()->data(index, Qt::EditRole).toString());


}

void TableDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{

QLineEdit *edit = qobject_cast<QLineEdit *>(editor);

if (edit)
model->setData(index, edit->text());

}






PS: The code can be a little confused because I the measure that I understand I added, not bothering to logically is very confusing

Added after 22 minutes:

I do not very well explained in the previous post. Finally I was QTableModel implement successfully. Now I'm trying to implement the delegate to carry out further validation before sending to the model.setData. So what I did was take the examples, and create a delegate without basic validations to see if it works well. Only it is giving me error.

wysota
4th September 2011, 15:27
What are you using threads for?

afro_cv
4th September 2011, 21:11
Where in my code you see

wysota
5th September 2011, 08:19
Where in my code you see

I can see it here:

I Have Problems here because emit CloseEditor
Comipler error QObject::installEventFilter(): Cannot filter events for objects in a different thread..