PDA

View Full Version : tableview and pushbutton connection



unix7777
18th August 2012, 18:57
I'm trying to make the button enabled when some of the tableview row is selected

1. I'm trying to figure out how to get the right signal from the tableview
2. I can't understand why qtcreator underline with red second line??


connect(ui->tableView_clients, SIGNAL(what_should_be_here?),
ui->pushButton_select, SLOT(setEnabled(true)));

Zlatomir
19th August 2012, 03:12
1) I think you can use selectedIndexes (http://doc.qt.nokia.com/4.7-snapshot/qtableview.html#selectedIndexes) and emit your own signal (create a signal that emits a bool and connect it with your slot).
2) The connect only take parameter type not value, so the true is error and bool is correct.

unix7777
19th August 2012, 07:43
OK, but when to emit the signal? I want the slot to be triggered when row is selected!So i thing i should use an existed signal.

spirit
19th August 2012, 09:18
Use QAbstractItemView::selectionModel and its signal QItemSelectionModel::selectionChanged.

Coises
23rd August 2012, 01:29
I'm trying to make the button enabled when some of the tableview row is selected

This one is a bit more complicated than you would expect. The signal you need doesn’t come directly from QTableView, but from the QItemSelectionModel associated with it.



connect(ui->tableView_clients->selectionModel(),SIGNAL(currentRowChanged(QModelIn dex, QModelIndex)),SLOT(enableCheck(QModelIndex, QModelIndex)));

...

void enableCheck(const QModelIndex& current, const QModelIndex& previous) {
ui->pushButton_select->setEnabled(current.isValid());
}

Since setEnabled requires a bool argument, and the signal you need doesn’t have one, you can’t connect them directly.

Zlatomir’s idea will also work, though he named the wrong method. QAbstractItemView::selectionChanged is a virtual protected slot that is called when the selection changes. If it isn’t already, you would have to make tableView_clients an instance of a subclass of QTableView — remembering the Q_OBJECT macro! — and define a signal which you would connect to QPushButton::setEnabled(bool); then override the selectionChanged method and have it call the base method, then emit that signal.

unix7777
31st August 2012, 20:56
Sorry but i can't figure out how to emit the signal.Do i have to make two connect() one with slot that will emit the signal and another that receive bool from the custom slot.
I'm confused!

I did the following but nothing happens with this signal!With another the slot works:


connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) ,
this, SLOT(setBool()));

and the custom slot is:


void Clients::setBool()
{
ui->pushButton_select->setEnabled(true);
}

Please help to find the right signal

Coises
31st August 2012, 21:22
Edit: I missed your edit, unix7777. You’re going about it spirit’s way, so what I wrote originally doesn’t apply.


I did the following but nothing happens with this signal!With another the slot works:


connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) ,
this, SLOT(setBool()));

and the custom slot is:


void Clients::setBool()
{
ui->pushButton_select->setEnabled(true);
}

Please help to find the right signal
I’m pretty sure you have the right signal. I used this (direct copy from my code) in a recent project:


connect(ui->remTable->selectionModel(),SIGNAL(currentRowChanged(QModelIn dex,QModelIndex)),
SLOT(setClean()));

void MainWindow::setClean() {
bool vi = rtProxy.rowCount() > 0;
if (vi && !ui->remTable->currentIndex().isValid())
ui->remTable->setCurrentIndex(rtProxy.index(0,0));
if (vi)
remToUI(remind()->reminders[rtProxy.mapToSource(ui->remTable->currentIndex()).row()]);
ui->remTable ->setEnabled(vi );
ui->actionImport ->setEnabled(true );
ui->actionExport ->setEnabled(vi );
ui->actionClearExpired->setEnabled(vi );
ui->actionNew ->setEnabled(true );
ui->actionCancel ->setEnabled(false);
ui->actionDelete ->setEnabled(vi );
ui->actionReplace ->setEnabled(false);
ui->actionSave ->setEnabled(false);
ui->reminderType ->setEnabled(vi );
ui->textGroupBox ->setEnabled(vi );
ui->settingsGroupBox ->setEnabled(vi );
if (vi) ui->remTable->setFocus();
else ui->buttonNew->setFocus();
checkIntro();
} and if it weren’t working... I’d definitely know it. So I think something else must be the problem.

This is probably not the problem: but just to be sure, if you haven’t already, do a complete rebuild. I’m not sure if it’s something peculiar to my setup, but in my last Qt project I frequently found that the build process would apparently miss something that needed recompilation, and the result would be some strange behavior that made no sense looking at the code. I eventually got to where whenever I couldn’t see within a few minutes what I had done wrong, I’d try a full rebuild. It was only the explanation maybe one out of ten times, but it still saved a lot of frustration!

If that’s not it... are you running a debug build, and are you checking the output to be sure there are no run-time error messages related to the connect?

If you aren’t already, try doing the connect as late as possible. I’m not sure about this, but I’m thinking perhaps there are things that can change the selectionModel of the QTableView. If it changed after the connect, nothing would notify you about that, but the connection would no longer be effective.

(original below)


Sorry but i can't figure out how to emit the signal.Do i have to make two connect() one with slot that will emit the signal and another that receive bool from the custom slot.
I'm confused!

You’ll only need one connect.

If you want to emit your own signal (Zlatomir’s method as opposed to spirit’s), the place to do it is in QAbstractItemView::selectionChanged.

That is a virtual method, and QAbstractItemView is a public base of QTableView, from which you would derive the class for your control.

If you don’t follow the previous sentence and its implications (for example, if you’re relatively new to C++ and don’t quite understand the concept of virtual methods), tell us that. You could hardly help being confused in that case.

Otherwise, remember to use the Q_OBJECT macro in the declaration for the class you derive from QTableView, and define the signal you will emit in a signals section.

unix7777
1st September 2012, 08:21
I still see the slot working.I have try with another signal and it works:

connect(ui->lineEdit_search_clients, SIGNAL(textChanged(QString)),
this, SLOT(setBool()));

I also try to completely rebuild the project.Of course i observe the debugger output.There is nothing.
Also i don't need to check whether selection has changed, but whether some row is selected.If is selected the button should be enabled if not disabled

Coises
1st September 2012, 18:03
Also i don't need to check whether selection has changed, but whether some row is selected.If is selected the button should be enabled if not disabled
Hmmm... I wonder if the clue is in there, somewhere.

I (and the others, I think) presumed you wanted to know when the QTableView’s state changes in such a way that a row is selected (when none was before; perhaps also when a different row was selected before); and perhaps also when it changes such that nothing is selected, when something was selected before. A signal is only going to be triggered when something happens or changes. If it’s not the selection changing that should trigger your check, what should trigger your check?

For the check itself, ui->tableView_clients->currentIndex() (http://doc.qt.nokia.com/latest/qabstractitemview.html#currentIndex).isValid() (http://doc.qt.nokia.com/latest/qmodelindex.html#isValid) will tell you whether anything is selected.

unix7777
1st September 2012, 21:24
OK, but which in this case is the signal?


connect(ui->tableView_clients->currentIndex(), SIGNAL(isValid()),
this, SLOT(setBool()));

Doesn't work

Coises
1st September 2012, 22:25
OK, but which in this case is the signal?

I know this might seem like a stupid question — and perhaps it is — but:

When do expect the enabled/disabled status of pushButton_select to change?
What would happen that should cause it to become disabled, and what would happen that should cause it to become enabled?

I’m trying to get a picture of the context of this within the logic of your application, so that perhaps I can guess why something that seems like it should be working is not.

(The code you tried can’t work for two reasons: QModelIndex::isValid() isn’t a signal, and the value of currentIndex() (http://doc.qt.nokia.com/latest/qabstractitemview.html#currentIndex) will change, so having connected to the QModelIndex that was current when you did the connect won’t help once it does change. I meant that if, as you indicated, you need to enable when something is selected and disable when nothing is selected, ui->tableView_clients->currentIndex().isValid() is what will tell you whether to enable or disable. When to check that seems to be something we haven’t figured out yet.)

unix7777
2nd September 2012, 08:31
Does it mean you that i have to make my own signal for that?
Custom slot, custom signal, i tough there should be an easier way.This is something common.To understand the logic is this: i have a table and have 4 buttons.One for add new row, one for delete a row and one that edit the row.The 4th button is for selecting the row.When row is selected the data from the selected row is displayed on another widget.The problem is that is the user click on the select button before select a row the program crashes.This is why i want to make this check, i want the select button to be enabled only when some row is selected and when is not to be disabled.

Coises
2nd September 2012, 09:22
i have a table and have 4 buttons.One for add new row, one for delete a row and one that edit the row.The 4th button is for selecting the row.When row is selected the data from the selected row is displayed on another widget.The problem is that is the user click on the select button before select a row the program crashes.This is why i want to make this check, i want the select button to be enabled only when some row is selected and when is not to be disabled.

Then your connect from before:

connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) ,
this, SLOT(setBool()));should be right, but the slot should look like this:

void Clients::setBool()
{
ui->pushButton_select->setEnabled(ui->tableView_clients->currentIndex().isValid());
}
so the button gets enabled when there is a selection and disabled when there is none.

I’m assuming you’ve called (or set in Designer) ui->tableView_clients->setSelectionBehavior (http://doc.qt.nokia.com/latest/qabstractitemview.html#selectionBehavior-prop)(QAbstractItemView::SelectRows) so that only rows can be selected. (If the user is supposed to be able to select either individual items or full rows and the problem is distinguishing specifically when a full row is selected, that would be a bit different.)

Be sure you’re doing the connect after you’ve attached the model and set all the other characteristics of tableView_clients, to be certain you don’t inadvertently do something that replaces the selectionModel after the connect. Also don’t forget that the signal will only reach the slot for changes that occur after the connect; so you might need to call the slot explicitly just before or after the connect to be sure everything starts off right:

setBool();
connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) , this, SLOT(setBool()));

unix7777
2nd September 2012, 16:52
connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) ,
this, SLOT(setBool()));

and SLOT:


void Clients::setBool()
{
ui->pushButton_select->setEnabled(ui->tableView_clients->currentIndex().isValid());
}

Doesn't work.Really is very reasonable but i don't know why doesn't work.
Yes, i set that only row can be selected not separated cell.

Coises
2nd September 2012, 18:03
Doesn't work.Really is very reasonable but i don't know why doesn't work.
Yes, i set that only row can be selected not separated cell.

Just to be certain: try putting a qDebug() in setBool(). I presume it is not being called when you select a row, but let’s be sure.

Can you post the class definitions (header files) for Clients and for the class of which tableView_clients is an instance? Maybe there’s a clue there... I’m not sure where to look next.

unix7777
2nd September 2012, 18:20
I don't know how to debug this!
But as i say the slot works with another signal, so the problem is in the signal, not in the slot.
The Tableview file is generated by the .ui file.

Coises
2nd September 2012, 18:56
I don't know how to debug this!
But as i say the slot works with another signal, so the problem is in the signal, not in the slot.
The Tableview file is generated by the .ui file.
In my experience, most debugging comes down to finding what it was I was sure was true, that wasn’t.

If you don’t have an #include <QDebug> in the Clients implementation (.cpp) file, add one. Then change the slot to:

void Clients::setBool() {
qDebug() << "At setBool";
ui->pushButton_select->setEnabled(ui->tableView_clients->currentIndex().isValid());
}
and let’s make sure our guess that it’s never being called is true. Do whatever you do to select a row, and to clear the selection; “At setBool” should appear every time the selection changes (including when it’s cleared entirely). If it doesn’t (which is what we’re expecting), we’ll have to sub-class the QTableView so we can add some debugging code and try to figure out if the signal is being emitted at all... then, if no, why?; if yes, why isn’t it reaching the slot?

I’d still like to see the class declaration (header file) for Clients, in case there’s a clue there.

unix7777
2nd September 2012, 19:17
QObject::connect: Cannot connect (null)::currentRowChanged(QModelIndex,QModelIndex) to Clients::setBool()
Object::connect: No such signal QSortFilterProxyModel::hasSelection() in ../Faktura/clients.cpp:58
Object::connect: (receiver name: 'lineEdit_search_clients')

The problem is that my sqlite file is in the debug directory and i don't run the programm via QT Designer but clicking on app file in debug directory otherwise it can't find sqlite file.On this way i can't see the debugg output.

Running the app from QT Designer i got the message above.

Coises
2nd September 2012, 20:39
QObject::connect: Cannot connect (null)::currentRowChanged(QModelIndex,QModelIndex) to Clients::setBool()

Then, among other things, it sounds like ui->tableView_clients->selectionModel() is not returning a useful value.
Is there any way to move the connect “later” in your code? I have a hunch tableView_clients isn’t fully set up at the point where you have the connect now. (In particular, the connect must come after you call ui->tableView_clients->setModel (http://doc.qt.nokia.com/latest/qabstractitemview.html#setModel)(...).) Try doing the connect as late in the setup sequence as you possibly can put it.

unix7777
2nd September 2012, 21:06
This is the order i call it:

Clients::Clients(QWidget *parent) :
QDialog(parent),
ui(new Ui::Clients)
{
ui->setupUi(this);


connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) ,
this, SLOT(setBool()));

updateClientTable();

}

And thank you for spending your time helping me!!!!

Coises
2nd September 2012, 21:30
I don’t know what all is in updateClientTable, but I’m going to suggest trying:

Clients::Clients(QWidget *parent) :
QDialog(parent),
ui(new Ui::Clients)
{
ui->setupUi(this);

updateClientTable();

setBool();

connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) ,
this, SLOT(setBool()));

}and seeing if it makes any difference.

unix7777
2nd September 2012, 21:50
Doing so the button is enabled even i don't select a row.
I use updateClientTable() to update the content of TableView after every manipulation (search, add, delete etc.)
What i understand is that on this way the SLOT is always called!

Coises
2nd September 2012, 23:32
Doing so the button is enabled even i don't select a row.
I use updateClientTable() to update the content of TableView after every manipulation (search, add, delete etc.)
What i understand is that on this way the SLOT is always called!

OK... now bear with me... just trying to find a way to debug this...

Change the declaration of setBool to:
void setBool(const QModelIndex& current, const QModelIndex& previous);change the definition to:
void Clients::setBool(const QModelIndex& current, const QModelIndex& previous) {
qDebug() << "At setBool" << current << previous << ui->tableView_clients->currentIndex();
ui->pushButton_select->setEnabled(ui->tableView_clients->currentIndex().isValid());
}and change the Clients constructor to:
Clients::Clients(QWidget *parent) :
QDialog(parent),
ui(new Ui::Clients)
{
ui->setupUi(this);
updateClientTable();
setBool(ui->tableView_clients->currentIndex(), QModelIndex());
connect(ui->tableView_clients->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)) , this, SLOT(setBool(QModelIndex,QModelIndex)));
}and let’s see if we can spot anything unexpected going on in the debug output. Watch to see when setBool is called and that the previous and current indices are what you would expect.

I know you said you have a problem with seeing the debug output because of difficulty connecting to your SQLite file under QtCreator. I can’t help you there, but it’s probably worth finding a way to make it work.

unix7777
3rd September 2012, 18:34
Qt_SDK__Debug/../Faktura/clients.h:41: error: expected ',' or '...' before '&' token


Qt_SDK__Debug/../Faktura/clients.h:41: error: ISO C++ forbids declaration of 'QModelIndex' with no type

unix7777
6th September 2012, 10:25
I debugged the problem but i still have no solution.
The problem is that the slot is triggered immediately after creating the dialog/tableview.After that when the selection changes the slot is called.
This means that at first i don't use the right signal (the signal i use is for change selection, but not when the there is selection) and secondly why the signal calls immediately after creating the tableview.
PLEASE HELP, i really fed up with this

Coises
6th September 2012, 19:38
I debugged the problem but i still have no solution.
The problem is that the slot is triggered immediately after creating the dialog/tableview.After that when the selection changes the slot is called.
This means that at first i don't use the right signal (the signal i use is for change selection, but not when the there is selection) and secondly why the signal calls immediately after creating the tableview.
PLEASE HELP, i really fed up with this

I’m a bit confused as to what is the problem.

You say that the slot is being called when the selection changes, but then that it’s not the right signal to tell whether there is a selection.

Is the slot not being called when the selection changes from “something is selected” to “nothing is selected”?

Or are you having trouble distinguishing, within the slot, whether something is selected or not?

The slot might be called in cases where you don’t need to do anything; but that shouldn’t be a problem, so long as it is being called whenever you do need to do something, and you can tell in the slot whether the button needs to be enabled or disabled at that time.

As far as being triggered “immediately after creating the dialog/tableview”... you did take out the explicit call to setBool() before the connect, if you don’t want it called there?

unix7777
6th September 2012, 20:25
I have changed the code to:

Clients::Clients(QWidget *parent) :
QDialog(parent),
ui(new Ui::Clients)
{
ui->setupUi(this);

updateClientTable();

connect(ui->tableView_clients->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelect ion)),
this, SLOT(setBool()));
}

and


void Clients::setBool()
{
ui->pushButton_select->setEnabled(ui->tableView_clients->currentIndex().isValid());
//QMessageBox::information(this, "", "SLOT IS TRIGGERED");
}

With this code we have some partial success.When the dialog is created the button is disabled.When i select some row it becomes enabled.But!But it doesn't do it on reverse, when again nothing is selected it doesn't become disabled again!

Coises
6th September 2012, 21:29
With this code we have some partial success.When the dialog is created the button is disabled.When i select some row it becomes enabled.But!But it doesn't do it on reverse, when again nothing is selected it doesn't become disabled again!

What causes nothing to be selected? I mean, what method do you call under what circumstances... how does the selection get set to nothing?

Did your testing (when you had the QMessageBox uncommented) show that the slot was being called at all when that happened? (If it’s not being called, that’s one problem; if it’s being called but currentIndex().isValid() is returning true when we expect it to be false, that’s something else.)

It is possible that I’ve let you astray... I see that there is a subtle difference between “current” and “selected” in a tableview and apparently they need not always be the same, even when the selection mode is SingleSelection. I didn’t run into this distinction in my program, but it might be relevant to yours. I’m not certain under just what conditions it becomes important to distinguish between the two. If your logic is causing the selection to be set to nothing but leaving the current item valid, then my suggestion to use currentIndex().isValid() was wrong. I’m not sure of this, because I haven’t used it, but it could be that ui->tableView_clients->selectionModel()->hasSelection() (http://doc.qt.nokia.com/latest/qitemselectionmodel.html#hasSelection) is what you need instead of ui->tableView_clients->currentIndex().isValid().

unix7777
7th September 2012, 07:09
It was exactly what i need.And of course it works perfect.THANK YOU!
You ask why i need to check whether some row is selected instead to get whether the selected row has changed.The answer is simple.If there are no too much records in the table there is some blank space.When you click on this space no row is selected.The same occurs when you click on lineEdit above.

Added after 41 minutes:

Something strange happens, after updating the model, meaning delete, add or edit, the signal doesn't work.