PDA

View Full Version : QTableView switching currentIndex not performing as expected



AlphaWolfXV
30th December 2013, 21:55
Hello all,
I have composed a simple compilable example to demonstrate the following issue.
When I click in the tableView, if I am in column 0 I want it to switch selection to column 1 ->This works ok
I installed an EventFilter on the tableView and check for certain keys (Left, Right, Up, and Down) for table navigation, I catch them and emit a signal, which calls the same slot as table->SIGNAL(clicked(QModelIndex)) and this appears to get in the spot to move the selection, but it doesn't actually set the true currentIndex (at least not from what I see).

Wondering if anyone out there could give me a hand with this, as it seems it should be very straightforward...
file:main.cpp

#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}

file: mainwindow.cpp

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
table = new QTableView(this);
model = new QStandardItemModel(this);
table->setModel(model);
table->installEventFilter(this);

//populate model with data...
for(int i=0;i<5; i++)
{
for(int j=0; j<2; j++)
{
QString text = "row: "+QString::number(i) + "/col: "+QString::number(j);
QStandardItem *item = new QStandardItem(QString(text));
model->setItem(i,j,item);
}
}
table->resizeRowsToContents();
table->resizeColumnsToContents();
table->setFixedSize(300,400);
QVBoxLayout *vbl = new QVBoxLayout(this);
vbl->addWidget(table,1);
setLayout(vbl);
setFixedSize(800,600);
connect(table,SIGNAL(activated(QModelIndex)),this, SLOT(updateDesc(QModelIndex)));
connect(table,SIGNAL(clicked(QModelIndex)),this,SL OT(updateDesc(QModelIndex)));
connect(this,SIGNAL(updateFromArrow(QModelIndex)), this,SLOT(updateDesc(QModelIndex)));
}
bool MainWindow::eventFilter(QObject *o, QEvent *e)
{
if(o == table && e->type() == QEvent::KeyPress)
{
//key was pressed on param detail selection...
int row = table->currentIndex().row();
int col = table->currentIndex().column();
int rowCnt = model->rowCount()-1;
int colCnt = model->columnCount()-1;
QKeyEvent *keyEv = static_cast <QKeyEvent*> (e);
if(keyEv->key() == Qt::Key_Left)
{
qDebug()<<"Key LEFT";
if(col != 0)
emit updateFromArrow(model->index(row,col-1));
else
emit updateFromArrow(model->index(row,col));
}//end if key left
else if(keyEv->key() == Qt::Key_Right)
{
if(col != colCnt)
emit updateFromArrow(model->index(row,col+1));
else
emit updateFromArrow(model->index(row,col));
}//end keyright
else if(keyEv->key() == Qt::Key_Up)
{
if(row != 0)
emit updateFromArrow(model->index(row-1,col));
else
emit updateFromArrow(model->index(row,col));
}//end if key up
else if(keyEv->key() == Qt::Key_Down)
{
if(row != rowCnt)
emit updateFromArrow(model->index(row+1,col));
else
emit updateFromArrow(model->index(row,col));
}//end if key down
}
return false;

}
void MainWindow::updateDesc(QModelIndex mi)
{
qDebug()<<"tree Clicked: row:"<<mi.row()<<"col:"<<mi.column()<<"curindxCol:"<<table->currentIndex().column();
QModelIndex m = model->index(mi.row(),mi.column());
if(mi.column() == 0) //if we are in first column, then jump to 2nd column <-works on clicking, not on keypress from eventFilter
{
qDebug()<<"Changing index, in col 0 for param";
m = model->index(mi.row(),1);
//table->selectionModel()->select(table->model()->index(mi.row(),1), QItemSelectionModel::ClearAndSelect);
table->setCurrentIndex(m);

}

}

MainWindow::~MainWindow()
{

}

finally file: mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui/QMainWindow>
#include <QtGui>


class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = 0);
~MainWindow();
QStandardItemModel *model;
QTableView *table;
signals:
void updateFromArrow(QModelIndex);
public slots:
void updateDesc(QModelIndex);

protected:
bool eventFilter(QObject *o, QEvent *e);
};

#endif // MAINWINDOW_H


Thanks to all who can help with this!
AlphaWolfXV - and Have a happy new year!

ChrisW67
30th December 2013, 23:48
Is this suitable?


class TableView: public QTableView {
Q_OBJECT
public:
explicit TableView(QWidget *p = 0): QTableView(p) { }

protected slots:
void currentChanged(const QModelIndex &current, const QModelIndex &previous) {
QTableView::currentChanged(current, previous);
if (current.isValid() && current.column() == 0) {
QModelIndex index = current.sibling(current.row(), 1);
setCurrentIndex(index);
// Or, to move the current item without changing the selected items
// selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
}
}
};


You might want to make the column zero items not selectable in the model also.

AlphaWolfXV
31st December 2013, 03:56
Hello,
Thank you so much for the response. I think I must be confusing something, this works for mouse clicking, it forces back to column 1. However, still on the arrow key behavior I get a dotted line surrounding the column 1 but the selection is still on column 0. Either way this gives me a lot of information to go on. Thank you for that, I missed that I had to implement the superclass to get the desired behavior.
Thank you so much!
AlphaWolfXV

Added after 11 minutes:

I made a qDebug to illustrate the behavior is working like it should, just the selection is not updating - I believe the index is correct, just the cell selected is not correct with the key events...

void currentChanged(const QModelIndex &current, const QModelIndex &previous) {
qDebug()<<"cR:"<<current.row()<<"cC:"<<current.column()<<"pR:"<<previous.row()<<"pC:"<<previous.column();
QTableView::currentChanged(current, previous);
if (current.isValid() && current.column() == 0) {
qDebug()<<"wow, we need to change it..."<<current.row()<<current.column();
QModelIndex index = current.sibling(current.row(), 1);
setCurrentIndex(index);

// Or, to move the current item without changing the selected items
//selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
}
}
};
9889

ChrisW67
31st December 2013, 04:29
The current item and the selection are two different things. Depending on the selectionMode() and selectionBehavior() set on the view you might get this behaviour regarding the state of the selection after setting the current item, and you might not. That is why I suggested you might want to make the column zero items not selectable in the model to avoid any possibility of them getting into the selection.


If your requirement is that clicking on column 0 sets the currentIndex() but adds the item in column1 to the selection then you have to code that slightly differently.

AlphaWolfXV
31st December 2013, 06:34
Hello again,
Thank you for your help. I will review the docs with the different selection modes/behaviors to see what I can come up with. I appreciate all the help, and the push in the right direction.
Just to be clear, to make the column 0 non selectable, we use the item->setSelectable() correct? In other words, make all the items in col 0 not selectable?

Finally just to clarify the end goal, i wanted the view to only select values(items) in column 1. If they click in column 0, the code supplied above works wonderfully. If they arrow key over (Left) to column 0, the selection box stays in col 0 even though I can tell it updates the current index as it is supposed to. I was hoping that when the user hits "left" arrow on keyboard it would "bounce" to col 0 and immediately back to col 1... Not a huge deal, I will continue looking into it.

Again, thank you for all your kind help!
AlphaWolfXV

ChrisW67
31st December 2013, 07:40
With an underlying QStandardItemModel yes, you would use item->setSelectable(false) on every item in column zero. In your own QAbstractItemModel subclass you would arrange the equivalent in your QAbstractItemModel::flags() implementation.

AlphaWolfXV
31st December 2013, 15:22
Perfect, I will give that a try. Thank you again for your help,
AlphaWolfXV