Can access only one item using QTreeWidget::itemAt - qt

I have a QTreeWidget declared as following
QTreeWidget * datasiftIdpwTree;
datasiftIdpwTree->setColumnCount(2);
datasiftIdpwTree->headerItem()->setText(0, "Username");
datasiftIdpwTree->headerItem()->setText(1, "Api Key");
it is filled with data using the following slot
void Window::addDatasiftIdpw(QString username, QString apikey)
{
datasiftIdpwTree->addTopLevelItem(new QTreeWidgetItem(QStringList(username) << apikey));
}
I can live view the slot addind data to my tree, the probleme is when accessing the data.
I tried using
datasiftIdpwTree->itemAt(x,y)->text(0);
but however the value of x, y I use, it always point to the first item (the one produced when first calling addDatasiftIdpw)
Where did I go wrong ?

I made made a mistake between cooridnates and index. Accessing the i-th element is achived by:
datasiftIdpwThree->topLevelItem(i)->text(0);

Related

Qtableview operations on filtered sets

I have a working Qtableview with custom model subclassed QAbstractTableModel and QAbstractItemModel.
I have a Qlineedit, onclicked it will filter the view:
// model.cpp
setFilter(QString strFilter) function searches trough my intern QList (this Qlist is actually attached to model) and if match found then: m_filterSet.insert(i);
This all works great. Problem is, i have CRUD operations for the tableview (insert row, delete row..) which also work great! But when selecting a row from a filtered set, i need to somehow know where in my QList exactly is this selected row from the filtered set (QSet ).
ui.myView->selectionModel()->currentIndex().row();
obvious gives the wrong indexes counting for the current view.
How can i somehow extract the value (int) from the selected row in the QSet?
Because when i added this function to model:
foreach (const int &value, m_filterSet)
qDebug() << value;
It has printed out successfully all the i values, e.g: 3410, 3411, 3412 (those are my client id's)
If i could extract this ID for the selected row in Qset, i could write a function that iterates my intern QList, and find a matching, so to speak:
if(m_Intern[i].nClientID == nId){ // nId = value inside Qset for selected row in view
return nIdx;
}
Qt has a solution for your problem - just use QSortFilterProxyModel. You will need to:
Subclass it and write your own filtering function (filterAccpetsRow)
Proxy your original model through filtering one
Attach filtering model to a view
use QSortFilterProxyModel::mapToSource() to convert between indexes in filtered and original model.
This allows you to have more than one view with just one source data model, each view may have different filters.
I solved it after a while re thinking, i just needed to implement another function inside my model:
int myClass::screenIndex2DataIndex(int nIdxScreen)
{
if(m_bUseFilter)
{
int nIdx =-1;
for(int i=0;i<m_lstIntern.size();i++)
{
if(m_filterSet.contains(i))
{
nIdx++;
if(nIdx == nIdxScreen){
return i;
}
}
}
return -1; //not found
}
else{
return nIdxScreen;
}
}
This way i can find out for the present index on the filtered view, where it is in my intern list.
After this it's easy to get my nClientID trough a return: return m_lstIntern[idx].nClientId

Property binding not updating

I am continuously getting data for my application as it runs, but I am having a bit of trouble displaying the data once I have read it in and stored it in a map.
When I try to display the data in the QML, it simply displays zero, despite the fact that I can see it updating in the application output.
I access the value in QML using property bindings (I was under the impression that these led headingSensor to be updated whenever carData.headingSensor changed?):
property int headingSensor: carData.headingSensor
Text { text: "Heading: " + headingSensor }
In my data class I have:
Q_PROPERTY(int headingSensor READ getHeadingSensor NOTIFY headingSensorChanged)
int headingSensor;
In the c++ implementation I originally had:
int data::getHeadingSensor(){
return data.value(heading)[headingSensorReading];
}
Where it returns the value in the map which is being updated with the incoming information.
This I realized, probably doesn’t work, because the property is dependent upon the headingSensor variable, which is itself not being updated despite the correct value being returned. So, I thought if I changed it to update the headingSensor value and return that it might work.
So in my data aquisition logic I wrote a method to update the variables as well.
data.insert(key, value);
updateVariables();
}
}
}
void data::updateVariables(){
headingSensor = data.value(heading)[headingSensorReading];
}
int data::getHeadingSensor(){
return headingSensor;
}
While this led to the headingSensor variable being updated in addition to the value in the map, the correct value is still not displayed in the QML display. It simply displays 0 (its default value when it is initially displayed since it has not gotten a value from incoming data yet).
So, I am wondering, how can I get the value of sensorHeading displayed in the QML to update as the value of it and/or the value in the map changes in C++? Do I need to do something like:
Connections {
target: carData
onSensorHeadingChanged: updateValues
}
EDIT:
Trying something like this, the onSensorHeadingChanged never fires. I am not sure why, since the value of sensorHeading clearly changes as I watch it in the application output
Connections{
target: carData
onHeadingSensorChanged: console.log("It's noting the change!")
}
It is the responsibility of the C++ element writer to emit headingSensorChanged() in order to cause the binding to be updated.
This tutorial is a good place to start when implementing a C++ element.
In your case you need to do something like this:
void data::updateVariables(){
int sensorReading = data.value(heading)[headingSensorReading];
if (headingSensor != sensorReading) {
headingSensor = sensorReading;
emit headingSensorChanged();
}
}
Note that we don't emit the change notifier unless there really is a change. This prevents needless JS evaluations, and also removes the possibility of binding loops.

How to refresh contents of QCombobox in QTableView

I have QTableView which has QComboBox in one of the columns. The combobox is displaying data from a vector which get updates when I click a button.
When I start the application the combobox displays all the items in vector. Now I press the button (which adds more items to the vector) but the combobox doesn't reflect new data in vector. It still shows old data. I am also emitting dataChanged() once the vector is updated but I don't see any change. data() function does get call in the model which does return all the elements of the vector, but setEditorData doesn't get call in delegate.
Am I missing something.
Thanks,
Dev
Then you need to do something like this function:
void updateComboBox(QComboBox *comboToUpdate, const QStringList & list )
{
QString curentText = comboToUpdate->currntText();
comboToUpdate->clear();
comboToUpdate->insertItems(list);
comboToUpdate->setCurrentIndex(comboToUpdate->findText(currentText));
}
Lines
QString currentText = comboToUpdate->currentText();
...
comboToUpdate->setCurrentIndex(comboToUpdate->findText(currentText));
are optional and used to don't change currentItem after selection.

ComboBox Qt Creator - how to create an event?

I have a Qt Form that contains 2 combo box messages. The second combobox message depends on the first combo box message. I mean that the dates from the second combobox message depends on the element that I select in the first combobox.
In this moment I have different dates in the first combobox. But the second combobox is not working. I need to creare a connect method or what?
Thx! APpreciate!
Could someone give me a short example?
It's fairly simple. A combobox emits the currentIndexChanged signal that also tells you the new index. Write a method that accepts an integer and changes the second combobox according to the integer (which is the index of the selection in combobox 1).
Here are some code sniplets from a working example.
Method declaration in your window/whatever class header:
public slots:
void setI1(int index);
Filling combobox 1, connecting the signal, e.g. in the constructor:
i1Box->addItem("Neutral", 0);
i1Box->addItem("2,856 K (Illuminant A, light bulb)", 2856);
// ...
connect(i1Box, SIGNAL(currentIndexChanged(int)),
this, SLOT(setI1(int)));
Implementation of the method:
void ViewerWindow::setI1(int index) {
// either use index directly, or, as in this case we have items holding an int:
int i1 = i1Box->itemData(index).value<int>();
// use the value to change second combobox here
}
If it does not work as expected, it is always helpful to print some debug output inside the method that should be called to see where it goes wrong in the chain.
Reference: http://doc.qt.nokia.com/latest/signalsandslots.html

Connecting multiple signals to a single slot in Qt

I'm trying to keep track of the textChanged() signal on for handful of QTextEdits. I want to do the same thing regardless of the text edit emitting the signal: uncheck its associated checkbox in a QListWidget if it becomes empty and leave it checked otherwise. The function I have so for is as follows:
void MainWindow::changed()
{
QString tempStr = ui->hNMRedit->toPlainText();
if(tempStr != "")
{
ui->checkList->item(0)->setCheckState(Qt::Checked);
}
else
{
ui->checkList->item(0)->setCheckState(Qt::Unchecked);
}
}
With the current approach, I would have to make a function like this for every QTextEdit; each function containing virtually identical code. If I stored each of the text edits in an array (so I could find their associated index in the QListWidget), would it be possible for me to have a slot like this?
void MainWindow::changed(QWidget *sender) // for whichever text edit emits the
// textChanged() signal
{
QString tempStr = sender->toPlainText();
if(tempStr != "")
{
// I would potentially use some sort of indexOf(sender) function on the array I
// mentioned earlier here... a little new to Qt, sorry
ui->checkList->item(array.indexOf(sender))->setCheckState(Qt::Checked);
}
else
{
// same as above...
ui->checkList->item(array.indexOf(sender))->setCheckState(Qt::Unchecked);
}
}
Is this possible or should I just create a separate slot for every text edit?
Please let me know if any further clarification is needed!
Lastly, I feel like the only meaningful difference between QLineEdits and QTextEdits is the default size. In favor of keeping things consistent, should I just use one of these objects throughout my UI?
Thanks!!!
I think you are missing the point of slots and signals. How are you creating the connections?
Are you trying to check a box when any of the text boxes change? If so use a QSignalMapper to map the textChanged() signals to send a value of true and connect that to the QCheckBox setChecked(bool) slot.
If that is too complicated subclass QCheckBox and create a set of functions checkBox() uncheckBox() so you can toggle states without a variable. Then connect the QTextEdit textChanged() to your subclass checkBox()
If this is not what you are looking for, at least subclass QTextEditto take in a QCheckBox that it can change when the text changes instead of duplicating code for every QTextEdit
All you need is a hash of QAbstractButton*, keyed by QTextEdit*. In the slot, you look up the sender() in the hash, if found you've got the button you need. This is precisely what is done by the QSignalMapper: you can map from a sender QWidget* to your button QWidget*. Use qobject_cast to cast to QAbstractButton*.

Resources