How to get keypressed event for table view - qt

This is my code of DropMimeData for the Tree Model.
The code works as expected , the user can drag and drop a treeitem from one location in the table view to another location in the view..
I need to add a condition in mimeData function based on Cntrl KeyPressed.
1) How can i get to know if the cntrl key is pressed in the function.
bool TreeModel::dropMimeData(const QMimeData *mimeData, Qt::DropAction
action, int row, int column, const QModelIndex &parent)
{
if (!mimeData->hasFormat(s_treeNodeMimeType)) {
return false;
}
QByteArray data = mimeData->data(s_treeNodeMimeType);
QDataStream stream(&data, QIODevice::ReadOnly);
qint64 senderPid;
stream >> senderPid;
if (senderPid != QCoreApplication::applicationPid()) {
return false;
}
TreeItem *parentNode = getItem(parent);
int count;
stream >> count;
if (row == -1) {
if (parent.isValid())
row = 0;
else
row = rowCount(parent);
}
for (int i = 0; i < count; ++i) {
qlonglong nodePtr;
stream >> nodePtr;
TreeItem *node = reinterpret_cast<TreeItem *>(nodePtr);
if (node->row() < row && parentNode == node->parent())
--row;
TreeItem *nodeNew = new TreeItem(node->GetContainer(), parentNode);
nodeNew->setContainer(node->GetContainer());
parentNode->insertChild(row, nodeNew);
endInsertRows();
++row;
// if( ctrl key is pressed ) while dragging and dropping item the Cntrl key is pressed
// removeItem(node);
}
return true;
}

Try this.
if (QGuiApplication::keyboardModifiers() != Qt::ControlModifier)
removeItem(node);

Related

Recursive function does not exit prematurely

I have a recursive function to find a treeitem in the treeview from its name.
bool SumCommandInterface::getTreeItem(const std::string &stdstrName, const QModelIndex & index, TreeModel *model, TreeItem** item)
{
if (index.isValid())
{
TreeItem* currentTreeItem = model->getItem(index);
if (currentTreeItem->getName() == stdstrName)
{
*item = currentTreeItem;
return true;
}
}
if(!model->hasChildren(index) || (index.flags() & Qt::ItemNeverHasChildren))
{
return false;
}
auto rows = model->rowCount(index);
for (int i = 0; i < rows; ++i)
getTreeItem(stdstrName , model->index(i, 0, index), model , item );
return false;
}
The function still runs even after it satisfies the condition.
The problem in you code is that you don't return from the function even if a recursive function call returns true, i.e. when the condition is met. The right way to implement the recursive call would be:
[..]
for (int i = 0; i < rows; ++i)
// Return if the condition is met.
if (getTreeItem(stdstrName , model->index(i, 0, index), model, item)) {
return true;
}
[..]

why are different treeItems linked to the same data

I have been trying to copy a treeitem to another location in the tree view along with its sub tree.
Finally i have been able to to move all of them successfully.
Header file for treeItem
class TreeItem
{
public:
explicit TreeItem( Container *data , TreeItem *parent = 0 );
~TreeItem();
TreeItem *parent();
void appendChild(TreeItem *child);
TreeItem& operator = (const TreeItem &item);
TreeItem *child(int iNumber);
int childCount() const;
int childNumber() const;
Container data() const ;
Container* GetContainer();
bool setData(Container* data , QVariant value);
void setContainer( Container* data);
bool insertChildren(int position, int count );
bool removeChildren( int position , int count );
void removeChild(int row);
void removeChild(TreeItem* itm);
QList<TreeItem*> children();
std::string getChildName(int row);
std::string getName();
int row() const;
void insertChild(int pos, TreeItem *child);
private:
QList<TreeItem*> childItems;
Container* itemData;
TreeItem* parentItem;
};
Cpp file for treeItem
TreeItem::TreeItem( Container *data, TreeItem *parent )
{
parentItem = parent;
itemData = new Container;
*itemData = *data;
}
TreeItem::~TreeItem()
{
if (itemData != nullptr)
{
delete itemData;
}
qDeleteAll(childItems);
}
TreeItem& TreeItem::operator = (const TreeItem &item)
{
qDebug() << "TreeItem operator called";
// if( this->itemData == nullptr)
// this->itemData = new Container;
*this->itemData = *item.itemData;
this->childItems = item.childItems;
this->parentItem = item.parentItem;
return *this;
}
TreeItem *TreeItem::parent()
{
return parentItem;
}
TreeItem *TreeItem::child(int iNumber)
{
return childItems.value(iNumber);
}
int TreeItem::childCount() const
{
return childItems.count();
}
int TreeItem::childNumber() const
{
if (parentItem)
return parentItem->childItems.indexOf(const_cast<TreeItem*> (this));
return 0;
}
Container TreeItem::data() const
{
return *itemData;
}
bool TreeItem::setData( Container* data , QVariant value )
{
//*itemData = *data; // Do Not !!!! uncomment this ///////////////////////////as it will set the value of default container constructor.
itemData->SetName(value.toString().toStdString() );
return true;
}
bool TreeItem::insertChildren(int position, int count)
{
if (position < 0 || position > childItems.count())
return false;
Container cont;
TreeItem *item = new TreeItem(&cont, this);
childItems.insert(position, item);
return true;
}
bool TreeItem::removeChildren(int position, int count)
{
if (position < 0 || position > childItems.count())
return false;
for (int row = 0; row < count; ++row)
{
delete childItems.takeAt(position);
}
return true;
}
void TreeItem::setContainer( Container* cont)
{
*itemData = *cont;
}
void TreeItem::appendChild(TreeItem *node)
{
childItems.append( node );
}
int TreeItem::row() const
{
// qDebug() << "The child count = " << parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
if (parentItem)
return parentItem->childItems.indexOf( const_cast<TreeItem*>(this) );
return 0;
}
void TreeItem::removeChild(int row)
{
// qDebug() << "The Row Number" << row;
// childItems.removeAt(row);
delete childItems.takeAt(row);
}
void TreeItem::insertChild(int pos, TreeItem *child)
{
childItems.insert(pos, child);
child->parentItem = this;
}
void TreeItem::removeChild(TreeItem* itm)
{
childItems.removeOne(itm);
}
std::string TreeItem::getChildName(int row)
{
return childItems.value(row)->getName();
}
std::string TreeItem::getName()
{
return itemData->GetName();
}
Container* TreeItem::GetContainer()
{
return itemData;
}
QList<TreeItem*> TreeItem::children()
{
return childItems;
}
This is my function to build the tree for subcontainers of the tree item in the tree structure.
void TreeModel::buildTree(TreeItem * pItem, QDataStream & ds) const
{
if (pItem == NULL)
return;
ds << reinterpret_cast<qlonglong>(pItem);
ds << pItem->childCount();
foreach(TreeItem* childItem, pItem->children())
{
buildTree(childItem, ds);
}
}
This is in the Drop mime data function where i restore the sub tree of the container.
// count is the number of child containers of the tree item
TreeItem *node;
//qDebug() << "The row" << row << parentNode->data().GetName().c_str() ;
for (int i = 0; i < count; ++i) {
// Decode data from the QMimeData
qlonglong nodePtr;
int childCount;
stream >> nodePtr;
stream >> childCount;
node = reinterpret_cast<TreeItem *>(nodePtr);
// Adjust destination row for the case of moving an item
// within the same parent, to a position further down.
// Its own removal will reduce the final row number by one.
if (node->row() < row && parentNode == node->parent())
--row;
TreeItem *nodeNew = new TreeItem(node->GetContainer(), node->parent());
nodeNew->setContainer(node->GetContainer());
// Insert at new position
//qDebug() << "Inserting into" << parent << row;
beginInsertRows(parent, row, row);
parentNode->insertChild(row, nodeNew);
endInsertRows();
for (int k = 0; k < childCount; k++)
{
restoreTree(stream, nodeNew);
}
++row;
}
This is the function to restore the sub tree.
TreeItem * TreeModel::restoreTree(QDataStream & ds , TreeItem* parent) const
{
Container cont;
// Restore the info from the stream
int childCount;
qlonglong nodePtr;
ds >> nodePtr;
ds >> childCount;
TreeItem *currentItem = reinterpret_cast<TreeItem *>(nodePtr);
if (currentItem == nullptr)
return nullptr;
TreeItem *thisItem = new TreeItem(currentItem->GetContainer(), currentItem->parent() );
thisItem->setContainer(currentItem->GetContainer());
//*thisItem = *currentItem;
parent->appendChild(thisItem);
for (auto nChild = 0; nChild < childCount; ++nChild)
{
TreeItem* oldChild = restoreTree(ds, thisItem);
if (oldChild != nullptr)
{
TreeItem *pChild = new TreeItem( oldChild->GetContainer() , oldChild->parent() );
pChild->setContainer(oldChild->GetContainer());
thisItem->appendChild(pChild);
qDebug() << "Appending child";
}
}
return thisItem;
}
The tree gets restored in the correct manner.
But now i have a issue, the treeitem in the old position and the new position are linked together , if i make any changes to the tree item in the old position than it also affects the TreeItem in the new position.
Changing parent->appendChild(thisItem); to parent->insertChild(row, thisItem); solved the problem now the BuildTree function that works.
TreeItem * TreeModel::restoreTree(QDataStream & ds , TreeItem* parent , int row) const
{
Container cont;
// Restore the info from the stream
int childCount;
qlonglong nodePtr;
QModelIndex parentIndex;
ds >> nodePtr;
ds >> childCount;
TreeItem *currentItem = reinterpret_cast<TreeItem *>(nodePtr);
if (currentItem == nullptr)
return nullptr;
TreeItem *thisItem = new TreeItem(currentItem->GetContainer(), currentItem->parent() );
thisItem->setContainer(currentItem->GetContainer());
//*thisItem = *currentItem;
// parent->appendChild(thisItem);
parent->insertChild(row, thisItem);
for (auto nChild = 0; nChild < childCount; ++nChild)
{
restoreTree(ds, thisItem , nChild);
}
return thisItem;
}
It was more of hit and try to find the solution that worked , if someone can give a explanation on the difference between parent->appendChild(thisItem); to parent->insertChild(row, thisItem) that would be great.
Or Any alternative solution.

Qt signal emit in addressbook

I am learning the Model-View in Qt by the AddressBook example. https://doc.qt.io/qt-5/qtwidgets-itemviews-addressbook-example.html
And I find something interesting. The code construct a TableModel class besed on QAbstractTableModel. In the override setData function, it emit the dataChanged signal. But, there is no signal emit in removeRows/insertRows. Then, how can these function update the View.
bool TableModel::removeRows(int position, int rows, const QModelIndex &index)
{
Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row) {
listOfPairs.removeAt(position);
}
endRemoveRows();
return true;
}
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {
int row = index.row();
QPair<QString, QString> p = listOfPairs.value(row);
if (index.column() == 0)
p.first = value.toString();
else if (index.column() == 1)
p.second = value.toString();
else
return false;
listOfPairs.replace(row, p);
emit(dataChanged(index, index));
return true;
}
return false;
}
Make note of function calls beginRemoveRows() and endRemoveRows() in the function removeRows() of your posted code.
The beginRemoveRows() function, emits a signal rowsAboutToBeRemoved(). This is how connected views can know about the deletion and the underlying connected views must handle before data is removed.
Look the note in below documentation:
https://doc.qt.io/qt-5/qabstractitemmodel.html#beginRemoveRows

How to show icons use QSqlRelationalTableModel and QTableView in every row

Now,I am try to use QSqlRelationalTableModel and QTableView to show my data in database,according to the properity "fileType" such as "doc,txt,exe,sln" to show a icon in the first column.
dirModel=new QSqlRelationalTableModel(this);
dirModel->setTable("ecm_doc");
dirModel->setFilter(QString("creatoruserid='%1' and parentid='%2'").arg(userid).arg(parentid));
dirModel->select();
dirView=new QTableView(this);
dirView->setItemDelegate(new DirDelegate(this));
dirView->setModel(dirModel);
dirView->setSelectionMode(QAbstractItemView::SingleSelection);
showIcon();
void DirTree::showIcon()
{
int rowCount = dirModel->rowCount();
for(int row = 0; row < rowCount; row++)
{
//here is a test.
QModelIndex index = dirModel->index(row, 1);
QIcon folderIcon(style()->standardPixmap(QStyle::SP_DirClosedIcon));
dirModel->setData(index, folderIcon, Qt::DecorationRole);
}
}
Help me,online wait:)
You should subclass from QSqlRelationalTableModel and reimplement the data() function in order to specify the icon:
QVariant MyModel::data(const QModelIndex &index, int role) const
{
// I assume that 1 is the db table column with the filetype property
if (index.column() == 1 && role == Qt::DecorationRole)
{
QSqlRecord r = modelRecord(index.row());
QString fileType = r.field(1).value().toString();
QIcon icon;
if (fileType == "exe")
icon = QIcon(":/PathToIcon/exe.png");
else if (fileType == "sln")
icon = QIcon(":/PathToIcon/sln.png");
...
return QVariant(icon);
}
return QSqlRelationalTableModel::data(index, role);
}

Updating QTableView with more rows dynamically

I have a QTableView, which uses a model derived from QAbstractTableModel.
The model starts out with a number of rows and displays the data properly.
The model also has a timer attached to it, which upon expiring, gets the number of rows and columns, constructs an index for it, and emits dataChanged signal, to update the dynamic contents of the table.
The problem is when the number of rows it is supposed to display, changes.
In that case, even though I obtain a new index with the changed no. of rows, and update the table, it still doesn't display any new rows.
I've identified why, perhaps. Let's say I have 2 rows in the beginning, and next, 5 rows are supposed to be displayed. In the timer expiration logic, I've asked it to construct a new index, with new row count… but dataChanged() signal, will only change the data for the rows which had already been inserted in the first. The new rows are not displayed.
This is my code for the model.
TableLayout::TableLayout()
: QAbstractTableModel()
{
rowCount();
columnCount();
timer = new QTimer(this);
timer->setInterval(3000);
timer->start();
connect(timer, SIGNAL(timeout()), this, SLOT(timerHit()));
//ItemList[0].SetFields("Blah" ,"Blah" , "Blah" , "Blah" , "Blah", "Blah", true );
//ItemList[1].SetFields("Blah1" ,"Blah1" ,"Blah1" ,"Blah1" ,"Blah1", "Blah1", true );
}
void TableLayout::timerHit()
{
int row = this->rowCount();
qDebug() << "RowCOunt::" << row;
qDebug() << " Now IT IS : " << row;
int col = this->columnCount();
qDebug() << "ColumnCOunt::" << col;
QModelIndex Ind = createIndex( 0, 0);
QModelIndex Ind1 = createIndex( row, col);
data(Ind1);
emit dataChanged(Ind, Ind1);
}
int TableLayout::rowCount(const QModelIndex& /*parent*/) const
{
RtdbReader* rtdbReader = RtdbReader::instance();
if (isConnected)
return rtdbReader->Get_Number_of_Items();
else return 2;
}
int TableLayout::columnCount(const QModelIndex& /*parent*/) const
{
return 6;
}
QVariant TableLayout::data(const QModelIndex& index, int role) const
{
int row = index.row();
int col = index.column();
//return row;
int row_count, col_count = 0;
if ( role == Qt::DisplayRole) {
if ( col == 1)
return ItemList[row]->GetExplanation();
if ( col == 2) {
qDebug() << " Now printing Sig name for row" << index.row();
return ItemList[row]->GetCond_Sig_Name();
}
if ( col == 3)
return ItemList[row]->GetDescription();
if ( col == 5)
return ItemList[row]->GetLogic();
if ( col == 4)
return ItemList[row]->Get_State_Text();
} else if ( role == Qt::DecorationRole && col == 0 ) {
bool col_to_display = ItemList[row]->GetValueColour();
qDebug() << "colour in view:" << col_to_display;
if ( col_to_display ) {
QString path = "Green.png";
//QPixmap p( s_type1Icon );
// return s_type1Icon;
QIcon icon ( path );
return icon;
} else {
QString path = "Yellow.png";
//QPixmap p( s_type1Icon );
// return s_type1Icon;
QIcon icon ( path );
return icon;
}
}
if (role == Qt::TextAlignmentRole )
return Qt::AlignCenter | Qt::AlignVCenter;
/* else if ( role == Qt::BackgroundRole)
{
QBrush yellowBackground(Qt::yellow);
return yellowBackground;
}*/
return QVariant();
}
Please suggest how I can change the view so new rows are added.
Thanks.
Just because you create a QModelIndex to the element at row, col, doesn't mean you created data for that element (and also not for the elements between the current end and that element).
You have to use setData(...) to add new data to the table, and then emit dataChanged(...) for the view to display it.

Resources