convert qtablewidget item to float - c++

I Have a Qtablewidget , and a signal cellchanged(), that calls a Slot Change();
setup_ui->tableWidget->setRowCount(1);
setup_ui->tableWidget->setColumnCount(2);
QTableWidgetItem *item = new QTableWidgetItem("Gain");
setup_ui->tableWidget->setHorizontalHeaderItem(0,item);
QTableWidgetItem *item1 = new QTableWidgetItem("Offset");
setup_ui->tableWidget->setHorizontalHeaderItem(1,item1);
However , i couldn't convert the cell edited value to float, something like
setup_ui->tableWidget->item(0,0)->float();
Please help,

what you need within the slot
Class::Change( int row, int column ) {
bool ok
float value = setup_ui->tableWidget->item(row, column)->text().toFloat(&ok);
if (ok) {
// do whatever with value
}
else {
// do some error handling
}
}
You can skip the flag (bool ok) if you can guarantee that the conversion never fails!
For more info, post more code ...

Related

Do an action while any checkbox state is modified with Qt

In my programm, I fill my interface with a lot of checkbox by this way :
void VGCCC::addMaterialToUI(QDomNodeList _materialNodeList, QWidget* _areaWidget, QLayout* _layout, QWidget* _layoutWidget, int _maTable)
{
for(int i=0; i< _materialNodeList.count();i++)
{
QDomElement materialElement = _materialNodeList.at(i).toElement();
QString elementFile = materialElement.attribute("file");
QString elementId = materialElement.attribute("id");
QString elementLabel = elementId;
elementLabel += " - ";
elementLabel += materialElement.attribute("label");
QCheckBox* checkbox = new QCheckBox(elementLabel);
_layout->addWidget(checkbox);
_layoutWidget->adjustSize();
_areaWidget->setMinimumHeight(_layoutWidget->height());
_areaWidget->setMinimumWidth(_layoutWidget->width());
configuration c;
c.path = (m_igmPath+elementFile).toStdString();
c.id = elementId.toInt();
c.name = elementLabel.toStdString();
if(_maTable==0)
{
m_materialSectionMap[checkbox] = c;
}
else
{
m_materialPostMap[checkbox] = c;
}
}
}
I would like to know how to retrieve these "abstract" checkbox. More exactly, if one of these checkbox is checked, I would like to call another function like this :
connect(anyCheckbox,SIGNAL(stateChanged(anyCheckbox)), this, SLOT(doSomethingFunctionIfCheckboxIsChecked()));
The difficulty is that in my UI, these checkbox didn't exist, so I can't connect them to my function. How can I solve it ?
You can e.g. collect pointers to your checkbox objects to a list so can access or "retrieve" them later.
You can connect each checkbox's stateChanged signal to a same slot which is then called when state of any of the checkboxes is changed. In the slot you can cast the sender() to a checkbox if you need to know which specific checkbox is in question. Another alternative is to use QSignalMapper.
In your class declaration:
private slots:
void checkboxStateChanged(int state)
private:
QList<QCheckBox*> m_checkboxes;
In your class definition:
void VGCCC::addMaterialToUI(QDomNodeList _materialNodeList, QWidget* _areaWidget, QLayout* _layout, QWidget* _layoutWidget, int _maTable)
{
...
QCheckBox* checkbox = new QCheckBox(elementLabel);
m_checkboxes.append(checkbox);
connect(checkbox, SIGNAL(stateChanged(int)), this, SLOT(checkboxStateChanged(int)));
...
}
void VGCCC::checkboxStateChanged(int state)
{
// Here your can e.g. call doSomethingFunctionIfCheckboxIsChecked()
QCheckBox* checkbox = qobject_cast<QCheckBox*>(sender());
if (checkbox)
{
// checkbox points to the object whose state changed
}
}

How to get current row of QTableWidget if I clicked on its child?

I have created a QTableWidget in which I've used setCellWidget(QWidget*). I've set QLineEdit in the cell widget. I've also created a delete button and clicking that button sends a signal to the function deleteRow. I've also used a function currentRow() to get the current row, but it returns -1 because of the QLineEdit. The code snippet is below.
void createTable() {
m_table = new QTableWidget(QDialog); //member variable
for (int i = 0; i < 3; i++)
{
QLineEdit *lineEdit = new QLineEdit(m_table);
m_table->setCellWidget(i, 0, lineEdit);
}
QPushButton *deleteBut = new QPushButton(QDiaolg);
connect(deleteBut, SIGNAL(clicked()), QDialog, SLOT(editRow()));
}
editRow() {
int row = m_table->currentRow(); // This gives -1
m_table->remove(row);
}
In above scenario I click in the QLineEdit and then click on the button delete. Please help me out with a solution.
Just tried it here, it seems that currentRow of the table returns -1 when clicking the button right after program start, and when first selecting a cell, then selecting the QLineEdit and then clicking the button, the correct row is returned.
I would do the following as a workaround: Save the row number in the QLineEdit, e.g. by using QObject::setProperty:
QLineEdit *lineEdit = new QLineEdit(m_table);
lineEdit->setProperty("row", i);
m_table->setCellWidget(i, 0, lineEdit);
Then, in the editRow handler, retrieve the property by asking the QTableWidget for its focused child:
int row = m_table->currentRow();
if (row == -1) {
if (QWidget* focused = m_table->focusWidget()) {
row = focused->property("row").toInt();
}
}
The accepted solution, as is, would not work if rows might get deleted while the program runs. Thus the approach would require to update all the properties. Can be done, if this is a rare operation.
I got away with an iteration approach:
for(unsigned int i = 0; i < table->rowCount(); ++i)
{
if(table->cellWidget(i, relevantColumn) == QObject::sender())
{
return i;
}
}
return -1;
Quick, dirty, but worked, and in my case more suitable, as rows got deleted often or changed their positions, only buttons in the widget were connected to the slot and the slot was never called directly. If these conditions are not met, further checks might get necessary (if(QObject::sender()) { /* */ }, ...).
Karsten's answer will work correctly only if QLineEdit's property is recalculated each time a row is deleted, which might be a lot of work. And Aconcagua's answer works only if the method is invoked via signal/slot mechanism. In my solution, I just calculate the position of the QlineEdit which has focus (assuming all table items were set with setCellWidget):
int getCurrentRow() {
for (int i=0; i<myTable->rowCount(); i++)
for (int j=0; j<myTable->columnCount(); j++) {
if (myTable->cellWidget(i,j) == myTable->focusWidget()) {
return i;
}
}
return -1;
}

Getting variable from widget in a QListWidget

I have a custom QWidget class called VideoWidget. Its source file looks something like this:
VideoWidget::VideoWidget(QWidget *parent, string test) :
QWidget(parent)
{
pathname=test;
QLabel *label= new QLabel(pathname.c_str(), this);
//...
}
string VideoWidget::getFilePath(){
return pathname;
}
In my MainWindow class I add the VideoWidget to a QListWidget through looping through a xml file and getting the string argument from that file like this:
QDomNode node = rootXML.firstChild();
while( !node.isNull() )
{
if( node.isElement() )
{
QDomElement element = node.toElement();
VideoWidget* mytest = new VideoWidget(this, element.attribute( "Pathname", "not set").toStdString());
QListWidgetItem* item = new QListWidgetItem;
item->setSizeHint(QSize(150,100));
ui->myList->addItem(item);
ui->myList->setItemWidget(item,mytest);
}
node = node.nextSibling();
}
This correctly fills my QListWidget with the VideoWidget where all the labels have a different value.
Now I'd like to get the pathname variable everytime I doubleclick on a item in the QListWidget like this:
connect(ui->myList,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(playClip(QModelIndex)));
void MainWindow::playClip(QModelIndex index){
QListWidgetItem* item = ui->myList->itemAt(0,index.row());
VideoWidget* widget = dynamic_cast<VideoWidget*>(ui->myList->itemWidget(item));
cout << widget->getFilePath() << endl;
}
My problem is that widget->getFilePath() always returns the same value for every clicked widget. It is the value of the first time I set pathname=test;. What am I missing here?
This is probably mistake:
QListWidgetItem* item = ui->myList->itemAt(0,index.row());
Method "itemAt" takes x and y coordinates, not indexes. Use "takeItem" instead.
Next thing I want to say is that this part:
ui->myList->itemWidget(item)
is useless. You can convert "item" directly.
And last - use qobject_cast since you use Qt. And never use dynamic_case (especially when you anyway do not check result against NULL).

Extract menu action data in receiving function or slot

In my menu, I am setting data to the menu actions. How can I extract that data in my slot? Or even better, instead of connecting a slot, can I also connect a member function that is able to extract the action data (like in the 1st connect)? The action data is meant to identify each action. As a sidenode, I am not sure if I can use several menu action entries on only one openNote-action.
void Traymenu::createMainContextMenu() {
QAction *actionNewNote = m_mainContextMenu.addAction("Neue Notiz");
actionNewNote->setIcon(QIcon("C:\\new.ico"));
actionNewNote->setIconVisibleInMenu(true);
QObject::connect(actionNewNote,&QAction::triggered,this,&Traymenu::newNote);
QString menuEntryName;
QAction *openNote;
QVariant noteID;
for (int i = 0; i<m_noteList.count(); i++) {
std::string noteTitle = m_noteList[i].data()->getTitle();
menuEntryName = QString::fromStdString(noteTitle);
openNote = m_mainContextMenu.addAction(menuEntryName);
connect(openNote,SIGNAL(triggered()),this,SLOT(s_showNote()));
noteID.setValue(m_noteList[i].data()->getID());
openNote->setData(noteID);
}
m_mainIcon.setContextMenu(&m_mainContextMenu);
}
And the slot:
void Traymenu::s_showNote() {
QObject* obj = sender();
//int noteID = data.toInt();
//Search all notes in noteList for that ID and show it
}
Using QObject::sender()
You can use QObject::sender() to get the signal's sender, followed by qobject_cast to cast the sender pointer to the right type.
void Traymenu::s_showNote()
{
QAction* act = qobject_cast<QAction *>(sender());
if (act != 0)
{
QVariant data = act->data();
int noteID = data.toInt();
showNote(noteID); // isolate showNote logic from "get my ID" stuff
}
}
void Traymenu::showNote(int noteID)
{
// Do the real work here, now that you have the ID ...
}
As the Qt documentation warns, "This function violates the object-oriented principle of modularity." It's still a fairly safe and standard practice, though — just one with some shortcomings. In particular, note that you're committing to having a s_showNote method that only works when it's accessed as a slot (otherwise sender is 0).
Using QSignalMapper
Alternatively, you can use the QSignalMapper class to return a pointer to teh item or to associate a unique identifier (int or QString) with each item.
Something like this:
void Traymenu::createMainContextMenu()
{
signalMapper = new QSignalMapper(this); // (or initialize elsewhere)
// ... (create your newNote here same as before) ...
QString menuEntryName;
QAction *openNote;
int noteID;
for (int i = 0; i<m_noteList.count(); i++) {
std::string noteTitle = m_noteList[i].data()->getTitle();
menuEntryName = QString::fromStdString(noteTitle);
openNote = m_mainContextMenu.addAction(menuEntryName);
noteID = m_noteList[i].data()->getID();
openNote->setData(QVariant(noteID)); // (if you still need data in the QActions)
signalMapper->setMapping(openNote, noteID);
}
connect(signalMapper, SIGNAL(mapped(int)),
this, SLOT(showNote(int)));
m_mainIcon.setContextMenu(&m_mainContextMenu);
}
void Traymenu::showNote(int noteID) {
// Now you have the ID ...
}
This pattern has the benefit of isolating all the ugly "Wait, how do I get my identifier?" stuff in one spot, instead of having both the initialization code and the slot function having code for associating actions and IDs.
I would write it like:
void Traymenu::s_showNote() {
QObject* obj = sender();
QAction *action = qobject_cast<QAction *>(obj);
int id = action->data().toInt();
for (int i = 0; i < m_noteList.count(); i++) {
if (m_noteList[i].data()->getID() == id) {
[..]
}
}
}

Drag and drop issue in Qt: Pass parameter to receiving dropEvent

A healthPackButton is dropped on a mysquare. Now I would like to add a value to this button (because I have a number of healthPackButtons and I want to be able to differentiate them). I have tried changing the makeDrag function for it to accept an extra parameter but than my SIGNAL was no longer matched.
Question: How can I pass additional information (=> int value) to my dropEvent handler inside another class.
Dialog class
for (int i=0; i<healthPks.size(); i++){
int value = healthPks.at(i);
QPushButton *healthPackButton = new QPushButton(title,this);
connect(healthPackButton,SIGNAL(pressed()),this,SLOT(makeDrag()));
}
void Dialog::makeDrag(){
QDrag *drag = new QDrag(this);
QMimeData *mime = new QMimeData;
mime->setText("This is a test");
drag->setMimeData(mime);
drag->start();
}
mysquare class
void MySquare::dropEvent(QGraphicsSceneDragDropEvent *event){
isHealthPack=true;
int xCoord = curX/width;
int yCoord = curY/height;
int value = 0; //what's the value??
const QMimeData *mimeData = event->mimeData();
emit healthMapChanged(xCoord,yCoord,value);
update();
}
To get an additional parameter into your slot, you can use a QSignalMapper – the documentation has an example of adding a QString const& parameter, but you can use an int in exactly the same way to pass the value to a makeDrag(int).
You could then use QMimeType's setData (converting your int to a QByteArray using QByteArray::number for example) to get that value to the drop target.