QT - How to retrieve QVariant Values from combobox? - c++

I'm using QVariant to store a object inside of a Qcombobox, This appears to work fine. This is the implementing code:
Add type to QVariant in header:
Q_DECLARE_METATYPE(CDiscRecorder*)
pDiscRecorder Casted as CDiscRecorder:
CDiscRecorder* pDiscRecorder = new CDiscRecorder();
Then stored in the combobox
ui->cbDrives->addItem(QString::fromWCharArray(strName), QVariant::fromValue(pDiscRecorder));
The problem arises when I try to pull it out:
CDiscRecorder* discRecorder = this->ui->cbDrives->itemData(index).value<CDiscRecorder*>;
I receive the error:
error C3867: 'QVariant::value': function call missing argument list; use '&QVariant::value' to create a pointer to member
I tried to implement the hint in the error code to no avail, I have followed the thread Add QObject in the combo box of Qt to implement this behavior, how can get my object back ?
Thanks

The compiler is giving you the hint that the argument list is missing - all you should need to do is add the brackets to tell it that you're trying to call the function. So change it to
CDiscRecorder* discRecorder = this->ui->cbDrives->itemData(index).value<CDiscRecorder*>();
And it should work. That's quite a long line, might be cleaner to break it out
QVariant variant = this->ui->cbDrives->itemData(index);
CDiscRecorder* discRecorder = variant.value<CDiscRecorder*>();

Related

Correct C++ syntax in Qt "connect"?

I am learning how to use connect in Qt.
I have an idea how it works when connecting widgets in current object.
My problem is - I do not fully understand C++ syntax when connecting two objects.
My current learning test task is to pass item selected in list to list_2 using C++ code - in current object. (I know how to implement that using QtDesigner - but I want to learn using code)
QListWidgetItem item;
connect(ui->list,
&QListWidget::itemClicked(QListWidgetItem &item),
ui->list_2,
&QListWidget::addItem(&item));
The above code gives me two errors and I need help to IDENTIFY what is wrong with my C++ syntax.
/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:127: error: expected primary-expression before '&' token
&QListWidget::itemClicked(QListWidgetItem &item),
/media/f/QT/Qt/QT/qtconnectivity/examples/bluetooth/CAT_BT_18112020/device.cpp:129: error: cannot call member function 'void QListWidget::addItem(QListWidgetItem*)' without object
&QListWidget::addItem(&item));
^
Thank you
I like to add / edit / clarify the post.
It would be helpful to start with knowing the convention / symbols in this C++ connect code.
What are the piece parts [=](){...} of "lambda" syntax in English?
connect(action, &QAction::triggered, engine,
[=]() { engine->processAction(action->text()); });
Perhaps help me by applying similar to my initial connect code.
The correct syntax for the connect statement should be
connect(list_widget_1,
&QListWidget::itemClicked,
list_widget_2,
QOverload<QListWidgetItem*>::of(&QListWidget::addItem));
Because addItem() has 2 overloads, QOverload must be used
QListWidget::addItem(const QString &label)
QListWidget::addItem(QListWidgetItem *item)
But you don't want to do this, since the documentation specifically said that:
Warning: A QListWidgetItem can only be added to a QListWidget once. Adding the same QListWidgetItem multiple times to a QListWidget will result in undefined behavior.
Instead you should do something like this
connect(list_widget_1,
&QListWidget::itemClicked,
[list_widget_2](QListWidgetItem *item)
{
list_widget_2->addItem(item->clone());
});
Explanation for the lambda part:
Inside the square brackets is the capturing part. In the following body of the lambda, I need to use list_widget_2, so I need to capture it.
Inside the parentheses is the place for the parameters. This part is like normal functions. Since itemClicked() passes a QListWidgetItem *, I will take it as parameter for the lambda.
Inside the curly braces is the lambda body. This part is like normal functions.
More information on lambda in the documentation

How to get the currently selected text in a CComboBoxEx?

My first approach to the problem was to call the GetWindowsText method on the CComboBoxEx control, but I found that there is no associated text. After analyzing the control with Spy++ and reading some documentation on CComboBoxEx, I realised that these type of controls are only the parent of a classic ComboBox:
I tried using the GetLBText() method on the child ComboBox, passing GetCurSel() as an argument, but I only get some wrong text (the correct text should be "English"):
Am I missing something? Thanks in advance!
What you want to do is map the control to a int variable using Class Wizard:
Now it is easy to access the selected text at any time. You need to use the GetItem function. For example (code not tested):
COMBOBOXEXITEM cmbItem;
CString strText;
cmbItem.mask = CBEIF_TEXT;
cmbItem.iItem = m_cbItemIndex;
cmbItem.pszText = strText.GetBuffer(_MAX_PATH);
m_cbMyCombo.GetItem(&cmbItem);
strText.ReleaseBuffer();
In short, you need to use the COMBOBOXEXITEM and initialise it with the right flags to state what information you want to get from the extended combo. That, and the item index. Job done!
I realise that you have your own inherited class, but the mechanics are the same. You don't use GetLBText. You use the structure with the index and GetItem to get the selected text.
In the end I managed to retrieve the correct name; as you can see in the image below, the ComboBox is only a child of a CombBoxEx32:
I retrieved the pointer to the parent ComboBoxEx32 from the child ComboBox, and searched for the text this way:
CString szText;
CComboBoxEx cbParentCombo ;
cbParentCombo.Attach( GetParent()->GetSafeHwnd()) ;
cbParentCombo.GetLBText( GetCurSel(), szText) ;
cbParentCombo.Detach() ;
My mistake was that I was calling GetLBText() directly from the child ComboBox, instead of the parent CComboBoxEx; because of that, all I was getting was some random gibberish. GetLBText() was indeed the correct solution.

QVariant conversion to QPainterPath

I have a problem right now with my mini-game I am making. The problem is as follows: I have created an level editor for my game and thus I had to create my own delegate and model, the problem occurs when I try to edit through a shapeeditor ( which more likely creates a painterpath ). I then return the painterpath through data but when I try to paint it with my delegate, qt tells me the following error:
/usr/include/qt4/QtCore/qmetatype.h:169: error: 'qt_metatype_id' is not a member of 'QMetaTypeId<QPainterPath>'
I am not quite sure why I am having this error. For information regarding the source code of the project, I can give if needed. But I am simply thinking the conversion from qvariant to qpainterpath isn't possible. They must be a way to do it.
Note: I tried to do the following
QVariant var = index.model()->data(index, Qt::DecorationRole);
QPainterPath path = var.value<QPainterPath>(); // The error occurs here, this is line 169
But this didn't work >.< Thanks if you can help me
Possible solution, is there anyway to create a pixmap from the painterpath? I could simply return the pixmap instead of the painterpath.
Looks like you need to use Q_DECLARE_METATYPE macro with QPainterPath
Like
Q_DECLARE_METATYPE (QPainterPath)
Here is documentation for the same.

Map QWidget to variable

The idea was to connect QWidget with a variable so that when text changes on a widget it will be also changed in a variable.
And do this with just one line like this
WidgetMapper::connect(ui->lineEdit, SIGNAL(textChanged(QString)), someClass.var);
which would connect for example QLineEdit with a variable.
1) This would display var in a lineEdit
2) when lineEdit fires an textChanged(QString) signal - WidgetMapper would convert this QString to correct mapped type with stringstream and write it to var.
But i dont really know templates that well, and dont know if it is possible at all.
I dont think it is possible to use one WidgetMapper for every type, so i also tried creating separate instances for each type (WidgetMapper<int> mapper;) which would still be betten then writing setters and onTextChangedSlots for each QLiteEdit but i could not figure out how to make it work as well (converter part still could not figure out the correct type).
WidgetMapper is using QSignalMapper to map signal to QWidget, and it worked fine, the part i have troubles with - is converting QString to template variable.
So is it possible? And if yes how could i do this? Or maybe there already a solution for this problem? (Somehow use QDataWidgetMapper with a class that contains variables maybe?)
First of, connecting the variable would do nothing else than calling some function if it were possigle.
Second try using QSignalMapper, this way you could use a single slot for all widgets, given you keep their pointers in an array with the index being the signal(int) emitted by the SignalMapper. This way your slot can just use MyWidgetArray[i]->text().

Passing QSqlQueryModel through control class

How would I go about passing QSqlQueryModel from a class that connects and queries the database through the control class or QMainWindow in my attempt and back to the widget needing the information?
I thought I could pass the reference location to the QSqlQueryModel object, but this is not working or I am doing something wrong.
I haven't found any examples showing what I am doing on the Qt Developer page.
Looks like these are just compiler errors, nothing specifically to do with Qt.
In short you are getting your pointers and references mixed up.
Error #1:
cardList = new List(sqlModel->getListModel());
You are passing a reference when the List takes a pointer. Fix your return type from getListModel or fix the above line.
Next, you are not specifying the second argument, i.e. the parent QWidget. Either specify your MainWindow as the parent, pass 0, or fix your constructor's signature to provide a default (generally 0).
Error #2:
List::List(QSqlQueryModel *model, QWidget *parent) : ListUI(parent){
setListItems(&model);
}
You receive the model as a pointer and then attempted to take the address of the pointer. I.e. You're making a double pointer. Change the line to
setListItems(model);
Hope that helps.