How can I get the selected VALUE out of a QCombobox? - qt

In Qt, I can get the selected text of a QComboBox by using the
combobox->currentText() method.
How can I get the selected value?
I searched for help but I couldn't find a method currentData() which I expected to find. I could only find combobox->currentIndex()
Is there a smarter way to do it other than combobox->itemData(combobox->currentIndex())?
Update: This is no longer necessary as of Qt 5. A currentData() method has been added http://doc.qt.io/qt-5/qcombobox.html#currentData-prop

It seems you need to do combobox->itemData(combobox->currentIndex()) if you want to get the current data of the QComboBox.
If you are using your own class derived from QComboBox, you can add a currentData() function.

This one can get the text of current index:
QString cb = cbChoice ->currentText();

you can set QVariant data for all items, then you can get the value when you need it.
there is an example code for this situation:
ui.comboBoxSheetSize->addItem("128 m", QVariant(128));
ui.comboBoxSheetSize->addItem("256 m", QVariant(256));
ui.comboBoxSheetSize->addItem("512 m", QVariant(512));
ui.comboBoxSheetSize->addItem("1024 m", QVariant(1024));
...
void Page::onComboSheetSizeChanged( int index )
{
int value = ui.comboBoxSheetSize->itemData(index).toInt();
}
by the way, i think i misunderstood your question. i think the way you get data is smart enough?

The member function QComboBox::currentData has been added since this question was asked, see this commit

I had same issue
I have solved by
value = self.comboBox.currentText()
print value

This is my OK code in QT 4.7:
//add combobox list
QString val;
ui->startPage->clear();
val = "http://www.work4blue.com";
ui->startPage->addItem(tr("Navigation page"),QVariant::fromValue(val));
val = "https://www.google.com";
ui->startPage->addItem("www.google.com",QVariant::fromValue(val));
val = "www.twitter.com";
ui->startPage->addItem("www.twitter.com",QVariant::fromValue(val));
val = "https://www.youtube.com";
ui->startPage->addItem("www.youtube.com",QVariant::fromValue(val));
// get current value
qDebug() << "current value"<<
ui->startPage->itemData(ui->startPage->currentIndex()).toString();

I'm astonished that there isn't an activated signal and have the same problem. I solved it by making a subclass of QComboBox. I think it's better to avoid having to directly access the object and call its functions because that means more tight coupling and goes against Qt's philosophy. So here's the class I made that works for me.
class SmartComboBox : public QComboBox {
Q_OBJECT
private slots:
void triggerVariantActivated(int index);
public:
SmartComboBox(QWidget *parent);
signals:
void activated(const QVariant &);
};
And the implementation
void SmartComboBox::triggerVariantActivated(int index)
{
activated(itemData(index));
}
SmartComboBox::SmartComboBox(QWidget *parent)
:QComboBox(parent)
{
connect(this, SIGNAL(activated(int)), this, SLOT(triggerVariantActivated(int)));
}

The question is old, but maybe, somebody need an actual answer.
In the QGIS 3.4 you can get the value from the QComboBox with the method currentData().
Example: comboBox.currentData()
Link: https://doc.qt.io/qt-5/qcombobox.html#currentData-prop

I did this
QDir path("/home/user/");
QStringList _dirs = path.entryList(QDir::Dirs);
std::cout << "_dirs_count = " << _dirs.count() << std::endl;
ui->cmbbox->addItem(Files);
ui->cmbbox->show();
You will see with this that the QStringList named _dirs is structured like an array whose members you can access via an index up to the value returned by _dirs.count()

I had the issue and
QString str = m_UI->myComboBox->currentText();
solved this.

if you are developing QGIS plugins then simply
self.dlg.cbo_load_net.currentIndex()

I know I'm very late but for those who still have that problem, it can be solved easily.
I use Qt 5.3 and it works fine. No need to create a function or all that.
int valueComboBox;
valueComboBox = comboBox->currentIndex();
and it works !
Hope it helps !

I confirm the easiest way is to do this:
uiAnalyseAssets::AnalyseAssets(QWidget *parent)
: QWidget(parent)
{
ui.comboBox->addItem("text1");
ui.comboBox->addItem("text2");
...
}
void mainFunction::yourFunction( int index )
{
int value = ui.comboBox->currentText();
}

Related

QTextLayout / QTextLine support grouping of several-characters so it acts as one character for the cursor

Is it possible for QTextLayout to render several characters, but to process/handle it as one character. For example rendering a code point like: [U+202e], and when moving the caret/calculating positions, it is treated as one character.
Edited:
Please check this following issue, were I explain what I'm trying to do. It for the edbee Qt component. It's using QTextLayout for line rendering.
https://github.com/edbee/edbee-lib/issues/127
Possibly it isn't possible with QTextLayout, the documentation is quite limited.
According to Qt docs:
"The class has a rather low level API and unless you intend to implement your own text rendering for some specialized widget, you probably won't need to use it directly." - https://doc.qt.io/qt-5/qtextlayout.html#details
You should probably use a QLineEdit or a QTextEdit (each has a method called setReadOnly(bool)).
Before answering the question, I will point out that the CursorMode enum (https://doc.qt.io/qt-5/qtextlayout.html#CursorMode-enum) seems very promising for this problem, but to me, the documentation isn't clear on how to use it or set it.
Now to answer your question in regards to QLineEdit or QTextEdit, it's a bit complicated, but it's the same for QLineEdit and QTextEdit, so lets look at QTextEdit.
Firstly, mouse clicks: QTextEdit has a signal called cursorPositionChanged(), which will be helpful here. You'll want to connect that to a custom slot, which can make use of the function moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode = QTextCursor::MoveAnchor) (https://doc.qt.io/qt-5/qtextedit.html#moveCursor). Notice that there are very helpful enumeration values for you here in QTextCursor::MoveOperation regarding word hopping (https://doc.qt.io/qt-5/qtextcursor.html#MoveOperation-enum). How do we put all of this together? Well, probably the right way to do it is to determine the width of the chars to the left of the cursor's position and the width of the chars to the right of the cursor's position when the cursorPositionChanged() signal is emitted and go to the side of the word that has less width. However, I'm not sure how to do that. At this point I'd settle with checking the number of chars to the left and right and going to the side with less.
Secondly, keyboard presses: This goes a bit out of my knowledge, but almost everything drawable and iteractable inherits from QWidget. Take a look at https://doc.qt.io/qt-5/qwidget.html#keyPressEvent and it's possible that overriding that in your own implementation of QTextEdit is necessary to get the left arrow and right arrow keypresses to jump words (once you get that part it's pretty easy, just use the same function as last section for moving the cursor, or in the case of QLineEdit, cursorWordForward()/cursorWordBackward()).
All this being said, I've so far been assuming that you're not deleting anything or selecting anything. Selection can be a real pain depending on if you allow multiple selections, but the functions are all there in the documentation to implement those things.
Example of mouse click impl:
myclass.hpp
#include <QTextEdit>
#include <QTextCursor>
#include <QObject>
#include <QString>
int distance_to_word_beginning_or_end(const QString &str, int index, bool beginning);
class MyClass {
MyClass();
~MyClass();
private:
QTextEdit *text_edit;
public slots:
void text_edit_changed_cursor_location();
};
myclass.cpp
#include "myclass.hpp"
int distance_to_word_beginning_or_end(const QString &str, int index, bool beginning)
{
// return the distance from the beginning or end of the word from the index given
int inc_or_dec = (beginning) ? -1 : 1;
int distance = 0;
while (index >= 0 && index < str.length())
{
if (str.at(index) == ' ' || str.at(index) == '\n' || str.at(index) == '\t')
{
return distance;
}
distance++;
index += inc_or_dec;
}
return --distance;
}
MyClass::MyClass()
{
text_edit = new QTextEdit();
QObject::connect(text_edit, &QTextEdit::cursorPositionChanged, this, &MyClass::text_edit_changed_cursor_location);
}
MyClass::~MyClass()
{
delete text_edit;
}
void MyClass::text_edit_changed_cursor_location()
{
QString text_edit_string = text_edit->text();
QTextCursor text_edit_cursor = text_edit->textCursor();
auto current_position = text_edit_cursor.position();
QTextCursor new_text_cursor;
int distance_to_beginning = distance_to_word_beginning_or_end(text_edit_string, current_position, true);
int distance_to_end = distance_to_word_beginning_or_end(text_edit_string, current_position, false);
auto movement_type;
if (distance_to_beginning > distance_to_end)
{
new_text_cursor.setPosition(current_position + distance_to_end);
} else {
new_text_cursor.setPosition(current_position - distance_to_beginning);
}
text_edit->setTextCursor(new_text_cursor);
}

Processing signal of QTreeWidget that has QTreeWidgetItem derivitives as items

I didn't find a proper solution to this problem, so I hope somebody can give me an answer to my problem:
I am using a normal QTreeWidget, but as items I use an own subclass of QTreeWidgetItem (because I needed to store some other information in the item). Now I want to use the itemClicked() signal by the QTreeWidget, but I think my slot doesn't get any signal and I think it has to do with the signature of itemClicked(), since it sends a QTreeWidgetItem and of course not my own subclass.
Is it possible that QTreeWidget doesn't detect a click on my own subclass items?
Here is my connection:
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *)), this, SLOT(displayTransformData(QTreeWidgetItem*)));
And here is my slot:
void GUI::displayTransformData(QTreeWidgetItem* item) {
cout << "test" endl;
Q_actorTreeWidgetItem* actor_item = dynamic_cast<Q_actorTreeWidgetItem*>(item);
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor = actor_item->getActorReference();
double* position = new double[3];
position = actor->GetOrigin();
x_loc->setText(QString(std::to_string( position[0]).c_str() ));
}
I'm already trying to cast the item that I could get from the signal into my own subclass, but the slot function is never called, because the test from my cout line doesn't appear in the console.
I'm very grateful for every help!
The problem is your incorrect SIGNAL specification,
SIGNAL(itemClicked(QTreeWidgetItem *))
You should probably see a warning message at the console along the lines of:
QObject::connect: No such signal
tree_widget::itemClicked(QTreeWidgetItem *) in ...
From the documentation the actual signal spec is
void QTreeWidget::itemClicked(QTreeWidgetItem *item, int column)
So, using the old Qt4 syntax you need
connect(treeWidget, SIGNAL(itemClicked(QTreeWidgetItem *, int)),
this, SLOT(displayTransformData(QTreeWidgetItem*)));
If possible, however, you should make use of the newer Qt5 signal/slot syntax
connect(treeWidget, &QTreeWidget::itemClicked, this, &GUI::displayTransformData);

Qt QMap<int, MyClass> ignores insert command

I've a question that couldn't find anywhere. I have a QMap that's ignoring the QMap.insert(Key, Value) command. Here's the code:
//gets the selected problem index on the ProblemList
int selProblem = ui->tree_projects->currentItem()->data(0, Qt::UserRole).toInt();
//creates a new problem, sets its values and then replaces the old one on the ProblemsList variable
ProblemSets nProblem;
if(!problemsList.isEmpty()) //problemsList is an attribute of MainWindow
nProblem = problemsList.value(selProblem);
// some data collection that has been omitted because isn't important
// temporary maps that will carry the modifications
QMap<int, QString> nResName, nResType;
//data insertion into the maps
//these are fine
nResName.insert(fIdx, results_model->data(results_model->index(fIdx, 0)).toString());
nResType.insert(fIdx, results_model->data(results_model->index(fIdx, 1)).toString());
//replaces the old maps with the new ones
nProblem.SetProbResultsNames(nResName);
nProblem.SetProbResultsTypes(nResType);
//replaces the old problem with the new one
problemsList.insert(selProblem, nProblem); //this is the line that's doing nothing
}
That last line appears to be doing nothing! I've even tried to use
problemsList.remove(selProblem);
problemList.insert(selProblem, nProblem);
but got a similar result: the map not being inserted at the index selProblem. It got inserted, but with an outdated value - the same one of the deleted index -. I've checked on Debug and all the indexes and variables are correct, but when the .insert hits, nothing happens.
The most awkward thing is that this code is a copy/paste that I made from another method that I'm using that does similar thing, just changing the variable names, but that one works.
EDIT 1: This is the contents of nProblem, selProb and problemsList.value(selProblem)
Just before the Line:
problemsList.insert(selProblem, nProblem);
selProb: 0
nProblem:
ProbResultsNames: "NewRow0"
ProbResultsType: "Real"
problemsList.value(selProblem):
ProbResultsNames: non-existent
ProbResultsType: non-existent
After the line
problemsList.insert(selProblem, nProblem);
selProb: 0
nProblem:
ProbResultsNames: "NewRow0"
ProbResultsType: "Real"
problemsList.value(selProblem):
ProbResultsNames: non-existent
ProbResultsType: non-existent
EDIT 2:
class ProblemSets
{
public:
ProblemSets();
virtual ~ProblemSets();
ProblemSets(const ProblemSets& other);
ProblemSets& operator=(const ProblemSets& other);
//I hid getters and setters to avoid pollution on the post
private:
int index;
bool usingBenchmark;
QString functionSelected;
QString info;
QMap<int, QString> probVars_name, probVars_type, probResultsNames, probResultsTypes;
QMap<int, float> probVars_min, probVars_max;
QMap<int, int> probVars_stpSize, probVars_stp;
int varsNumber; // holds how many vars has been created, just for display purposes
int resNumber; // holds how many results has been created, just for display purposes
};
A simple test proves that QMap works as expected:
QMap<int, QString> mm;
mm.insert(1, "Test1");
qDebug() << mm[1]; // "Test1"
mm.remove(1);
qDebug() << mm[1]; // "" (default constructed value)
mm.insert(1, "Test2");
qDebug() << mm[1]; // "Test2"
Which means that the problem lies in your code.
This statement itself is highly suspicious:
That last line appears to be doing nothing!
Because then you go on to say that the map still contains the "old value". But you removed that key, so if the insert() method didn't work, you shouldn't be getting the old value, but a default constructed value.
Which means that the problem is most likely that nProblem has the same value as the one that is previously associated to that key in the map. The map works, you values are likely wrong.
Found the issue! I didn't have both the variables declared on the copy method of the ProblemSets class.
Solved simply adding them to the copy method
MainWindow::ProblemSets::ProblemSets(const ProblemSets& other)
{
// copy
index = other.index;
usingBenchmark = other.usingBenchmark;
functionSelected = other.functionSelected;
info = other.info;
probVars_name = other.probVars_name;
probVars_type = other.probVars_type;
probVars_min = other.probVars_min;
probVars_max = other.probVars_max;
probVars_stpSize = other.probVars_stpSize;
probVars_stp = other.probVars_stp;
//here
probResultsNames = other.probResultsNames;
probResultsTypes = other.probResultsTypes;
//
varsNumber = other.varsNumber;
resNumber = other.resNumber;
}
I had this issue before with the std::vector class, and that's why I suspected that could be that. Thanks to everyone that helped!

QEventLoop usage(signals and slots)

I have an application which contains such lines.
emit WindowAdded(settings->WindowType);//!!!!!!!!!!!!!!
MyWindow *widget = new MyWindow(0,settings,currentWindowIndex);
The signal changes value of currentWindowIndex, but it didn't work because of slot, it doesn't change its value in time. Some one advices me to use QEventLoop, but i don't understand how to do this. Give me an example, please.
Another part of the code:
connect(area,SIGNAL(WindowAdded(QString)),this,SLOT(addWindowOnTab(QString)));
void WorkSpace::addWindowOnTab(QString title)
{
qint32 i = TabsList->addTab(title);/////!!!!!!!!!!!!!!!!!!!!!!!!!
emit addedWindowIndex(i);
TabsList->setVisible(true);
}
connect(this,SIGNAL(addedWindowIndex(qint32)),area,SLOT(WindowIndexChanged(qint32)));
void MyMdiArea::WindowIndexChanged(qint32 index)
{
currentWindowIndex=index;
}
I think it can help.
MyMdArea is сlass inherited from QMdiArea, WorkSpace is a QWidget, TabsList is a QTabBar.
And there is another fact: I tried to understand execution sequence of slots and added some lines to code:
QLabel *n= new QLabel("1");
n->show();
after emiting WindowAdded signal
QLabel *n= new QLabel("2");
n->show();
after emiting addedWindowIndex signal
and
QLabel *n= new QLabel("3");
n->show();
after changing currentWindowIndex's value
and that is what i saw "1 2 3" and its exploded my brain. Maybe i don't understand something?

Segmentation fault when accessing the text of QLabel

I got a problem with the QLabel. I got a QtWidget with a QLabel inside. Now I want to change the text of the Label with following code:
QLabel* safetyLabel = this->findChild<QLabel *>("safety_bits");
safetyLabel->setText(QString("test"));
printf("%i", (safetyLabel->text()).length());
but I always get a "Segmentation fault". I think it's something quite simple, but I just can't see it...
Any ideas?
Your safetyLabel can be NULL if you use QtCreators' designer to build your UI and execute your code before you call ui->setupUi(this); in MainWindows constructor.
Here is the code.
QLabel *safetyLabel = NULL;
safetyLabel = (QLabel *) this->findChild("safety_bits");
if(!safetyLabel)
{
qDebug() << "Failed to find safety_bits label!";
return 1;
}
safetyLabel->setText(QString("safety_bits is here"));

Resources