I am a student programmer and have been building a GUI in Qt for my company. I am writing a member function SetData to basically act as an intermediary between my Ui elements and member variables. In this particular Ui I am using a QTableWidge. I can't seem to find out exactly how to set each column to a variable.
For instance if I have the column Name in my QTableWidget, and Name is the first column I can't access it using the traditional array parameters. The documentation from Qt is really hazey as to how to address this.. It could also be that I am still too amateur to understand how to use the class's member functions to achieve the results I want here.
To clarify I am trying to define a data type for an entire column. For instance my first column; Name, would be a variable that I have created which is a QString data type. and SetData would pass it to eventually a QVector or QList. Here is the code I have typed up so far to kinda give an Idea of what I thought I could do.
void InjectionDialog::setData(InjectionData &setDataStruct)
{
/*The following setData functions assists in creating a new instance of
the Injection dialog with whatever values are passed to setDataStruct*/
QString str;//created str to make datatype conversion
ui->lineEditFluidVelocity->setText(str.setNum(setDataStruct.lineEditFluidVelocity));
ui->lineEditFluidMassFlow->setText(str.setNum(setDataStruct.lineEditFluidMassFlow));
ui->lineEditFluidArea->setText(str.setNum(setDataStruct.lineEditFluidArea));
ui->lineEditFluidTemperature->setText(str.setNum(setDataStruct.lineEditFluidTemperture));
ui->lineEditFluidPressure->setText(str.setNum(setDataStruct.lineEditPressure));
ui->lineEditParticleManual->setText(str.setNum(setDataStruct.lineEditManualParticlesPerCell));
ui->lineEditParticleVelocity->setText(str.setNum(setDataStruct.lineEditParitcleVelocity));
ui->lineEditParticleMassFlow->setText(str.setNum(setDataStruct.lineEditParticleMassFlow));
ui->lineEditParticleArea->setText(str.setNum(setDataStruct.lineEditParticleArea));
ui->lineEditParticleTemperature->setText(str.setNum(setDataStruct.lineEditParticleTemperture));
ui->tableWidgetInjectionLocations //this is where I got stuck
}
I know that QTreeView has the option to set items by delegating columns but I need these fields to be able to be edited. I could be going about this all wrong in handling my QTableWidget; if so I appreciate any advice in how to appropriately handle this Widget.
After some research and trial and error through QTableWidgetItem; I found what I was looking for. As I said earlier I needed to write a setData function to provide a way to set each cell to some specified data using QTableWidget. QTableWidget uses setItem to set each item to a QTableWidgetItem. Knowing this I just filled in the purpose. Here's what I did; This is right after my main code.
for(int i=0; i<setDataStruct.qTableWidegetlocations.size(); i++)
{
QTableWidgetItem *qTableWidgetItemInjectionName = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsInjectionName);
ui->tableWidgetInjectionLocations->setItem(i,0, qTableWidgetItemInjectionName);
QTableWidgetItem *qTableWidgetItemInjectionOnOff= new QTableWidgetItem((setDataStruct.qTableWidegetlocations[i].locationsInjectionOnOff));
ui->tableWidgetInjectionLocations->setItem(i,1, qTableWidgetItemInjectionOnOff);
QTableWidgetItem *qTableWidgetItemInjectionX = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsX);
ui->tableWidgetInjectionLocations->setItem(i,2, qTableWidgetItemInjectionX);
QTableWidgetItem *qTableWidgetItemInjectionY = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsY);
ui->tableWidgetInjectionLocations->setItem(i,3, qTableWidgetItemInjectionY);
QTableWidgetItem *qTableWidgetItemInjectionZ = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsZ);
ui->tableWidgetInjectionLocations->setItem(i,4,qTableWidgetItemInjectionZ);
QTableWidgetItem *qTableWidgetItemInjectionnx = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsnx);
ui->tableWidgetInjectionLocations->setItem(i,5,qTableWidgetItemInjectionnx);
QTableWidgetItem *qTableWidgetItemInjectionny = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsny);
ui->tableWidgetInjectionLocations->setItem(i,6,qTableWidgetItemInjectionny);
QTableWidgetItem *qTableWidgetItemInjectionnz = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsnz);
ui->tableWidgetInjectionLocations->setItem(i,7,qTableWidgetItemInjectionnz);
QTableWidgetItem *qTableWidgetItemInjectionTemperature = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsTemperature);
ui->tableWidgetInjectionLocations->setItem(i,8,qTableWidgetItemInjectionTemperature);
QTableWidgetItem *qTableWidgetItemInjectionWeight = new QTableWidgetItem(setDataStruct.qTableWidegetlocations[i].locationsWeight);
}
Thanks For Reading
Related
I am working on a Project using Qt 5.7 with C++. I am stuck in a weird problem.
I have a QTableWidget which contains a QComboBox on its one and only cell. Simplified code is as follows.
QTableWidget *tab = new QTableWidget();
tab->insertColumn(0);
tab->insertRow(0);
QComboBox *cb = new QComboBox(tab);
cb->addItem("A");
cb->addItem("B");
tab->setCellWidget(0, 0, cb);
Now on currentIndexChanged(int) signal of the QComboBox, I am connecting to a SLOT where I am trying to retrieve the pointer of the QTableWidget as follows,
QComboBox* cb = qobject_cast<QComboBox*>(sender());
QWidget* par = cb->parentWidget();
But, I am not getting the same pointer as the actual QTableWidget.
I have also tried as follows, but still failed.
QComboBox* cb = qobject_cast<QComboBox*>(sender());
QObject *par = cb->parent();
QTableWidget *tab = qobject_cast<QTableWidget *>(par);
Can anyone suggest some other way to do it or point out the error in those code segment ?
Possible Solution Found
Parent Widget can be retrieved using cb->parent()->parent(). Although, this process is not documented, so, not reliable.
The reason is that the QTableWidget is not a direct parent of QComboBox, but a grand parent. But even this is an implementation detail and cannot be relied upon, because it is not documented.
A way out could be storing the QTableWidget pointer somewhere else.
I have a QTableWidget in my Main Window class.
I am unable to find a functionality which will undo the text change for the specified cell.
What I want to do is:
void myCellUndoFunc(int row, int col)
{
table->item(row, col)->undo(); //table is my QTableWidget
}
The problem is that there is no such undo().
So my question is, can there be a workaround for this problem using maybe some foo-doo combination of SIGNAL's & SLOT's?
Thanks!
PS: Please do not suggest to use Model/View framework because I have used QTableWidget extensively in my application. Sorry for the same.
Maybe you should use the
void QTableWidgetItem::setData ( int role, const QVariant & value ) [virtual]
using the Qt::UserRole you are able to specify the last value. In your method u can access the previously set value with the data()-Method. The only thing you have to do is always keep the old value up-to-date.
Before you set the new value of the QTableWidgetItem
tw->setData(Qt::UserRole, tw->text())
and on undo u could than retrieve the data with
tw->setText(tw->data(Qt::UserRole).toString())
where "tw" is the current QTableWidgetItem using the contextmenu-event, the clicked-event or whatever u want. You could also subclass the QTableWidgetItem and handle this whole thing internally in your class, creating an undo()-method, storing the old value, etc.
This questions to me reeks of maybe a lack of understanding of C++, as the possibilities I've considered for my problem all seem to make no sense on why this could be occuring. Feedback appreciated.
I'm using the form designer to create a form class with a table in it. I'm trying to replace the table with another table generated in a helper class. I'm only doing this so I can (hopefully) maintain the nice grid layout I've designed, and through pointer manipulation, get the replacement I desire. Here's some code snippets from the table form constructor and relevant calls :
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
....
setup();
void setup(){
tableData = Utilities::createTable(this->file, tableDelim);
//createTable returns QTableWidget*
... other assignments, and label text updates, which seem to all work
}
My understanding is that tableData is a pointer, and if printed, will give the address of the QTableWidget from the layout. So then if I create a QTableWidget* and then assign tableData to that, tableData should now point to the new widget. Instead, I see only a blank screen.
I tried checking what the tableData pointer is before I assign it to the new QTableWidget*, and after. The second pointer shown is what is generated by createTable() :
QTableWidget(0x101272d40, name = "tableData") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
It seems the pointer is being reassigned, but the table drawn isn't the right one.
What gives?
My understanding is that you want to design the table layout in designer but fill in the data from an external source.
I would suggest, to just use the QTableWidget that is created in setupUi() and modify Utilities::createTable() such that it becomes Utilities::populateTable(QTableWidget & table, <all the other parameters you need>). (Or use QTableWidget * if you prefer - however I like putting the non-zero assertion responsibility on the caller...)
Apart from that, I agree with Sebastian Lange.
You are right with your assumption. You do set a variable to be a pointer to a object and next you set the variable to be a pointer to another object. You never change any objects, just your variable which is not used to display anything.
You would need to do something like:
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
parentLayout = tableData->parent()->layout(); //Get the parent widget to add another table.
parentLayout->removeWidget(tableData);
delete tableData;
parentLayout->addWidget(createTable());
You need to use pTheContainerOfTheOriginalTableWidget->addWidget(tableData); See here: http://qt-project.org/forums/viewthread/16547
Be sure you remove the original tableWidget so you don't have two (I assume you don't want two).
If I understand you correctly we have such situation.
call of setupUi (which generated by qt tootls),
there there is something like this(pseudo code):
oldTablePtr = new QTableWidget(parent);
someLayout->addWidget(oldTablePtr);
So parent and layout hold value of oldTablePtr.
And if you set variable oldTablePtr nothing changed.
parent send QPaintEvent to oldTablePtr.
So you need call delete oldTablePtr, that remove this widget from list of childs of parent, and move newTablePtr to the same layout.
There's no need to replace it in code, you can do it in Qt Designer. Just place QTableWidget on form, then rightclick it and choose Promote widget in menu, then you will need just enter your classname.
Currently I don't have Qt Designer near me, so edits will be appreciated.
I'm trying to improve this example for a diagram editor.
The example uses a nodes class with a few attributes unrelated to my needs. Right now I want to add a "list of arrays" to this node class in order to then populate a QTableView in the "properties" dialog. I already designed the properties dialog with the QTableView. I'm not even sure this is feasible/makes sense.
Basically the table must have 4 columns: name, type, value and unit.
Each row of the table is a certain "property" I need the node to have.
My question is: how can/should I model the table at class level? I ask this because I have been looking to QList, QVariant, QMap, QMultiMap and I can't figure out out to use them correctly, and none of the examples I found so far are any help either, at least for what I need to do. I saw something about the QStandardItemModel class, and I think it relates to the solution, but I can't understand how/why.
To top it off, I'm a Qt/C++ beginner, so much of the dynamics and jargon in Qt/C++ are still elluding me.
If anyone could give me some pointers, that would be great.
EDIT:
This isn't getting much attention, and I don't know if its because I wasn't clear enough, but anyway, try to picture this:
a Node has a PropertyList
that PropertyList lists Properties
Properties are sort of dictionaries, as they have always 4 attributes and respective values: name:(string), type:(string), value:(double) and unit:(string).
one Node can only have one PropertyList; a PropertyList can have several Properties. Some Nodes will have 3 properties, others will have 4, etc...
Now, the Nodes are represented in a diagram via a QGraphicsScene with QGraphicsItem. You can access a PropertiesDialog widget that has a QTableWidget in it. This table will show the PropertyList.
I want to know what kind of "structure" I can create/define that enables me to easily insert/read data in the table widget - ie, I load the data into the PropertiesList of the Node and it shows up in the table widget; if I change the data in the table widget, it passes on to the PropertiesList of the Node.
Hope this helps clearing out any doubts that may arise.
Well, after a lot of hair pulling, I got what I needed.
My first step was to create a Property class. This class has functions to set or get a name string, a type string, a value double and a unit string.
Next, I updated the Node class to include functions to add and remove Property object pointers to a QList<Property *>. Also included was a listProperties function that returns all the Property objects from a certain Node.
After this, the function to populate the QTableWidget with a certain Node's properties was coded like this:
propertiesList = node->listMyProperties();
for (int row = 0; row < propertiesList.size(); ++row) {
Property *property = propertiesList.at(row);
addRow();
tableWidget->item(row, 0)->setData(Qt::DisplayRole, property->propertyName());
tableWidget->item(row, 1)->setData(Qt::DisplayRole, property->propertyType());
tableWidget->item(row, 2)->setData(Qt::DisplayRole, property->propertyValue());
tableWidget->item(row, 3)->setData(Qt::DisplayRole, property->propertyUnit());
}
And the addRow() function:
void PropertiesDialog::addRow()
{
int row = tableWidget->rowCount();
tableWidget->insertRow(row);
QTableWidgetItem *item0 = new QTableWidgetItem;
item0->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
tableWidget->setItem(row, 0, item0);
QTableWidgetItem *item1 = new QTableWidgetItem;
item1->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
tableWidget->setItem(row, 1, item1);
QTableWidgetItem *item2 = new QTableWidgetItem;
item2->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
tableWidget->setItem(row, 2, item2);
QTableWidgetItem *item3 = new QTableWidgetItem;
item3->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
tableWidget->setItem(row, 3, item3);
tableWidget->setCurrentItem(item0);
}
This produces what I needed: to have a class to hold the property values related to each node, and present them on a QTableWidget. Next step is to make the reverse path, meaning, when edits occur in the QTableWidget, those changes should propagate to the class. Now I think I can find my way, hope this helps anyone trying to find something related. I'll also update the tags and maybe edit the title to make it more relevant/meaningful.
I am a student programmer using Qt to build a GUI for work. I have ran into an issue; more or less and inconvience of sorts wiith multiple selections in the QTreeWidget. My GUI has a main interface with a QTreeWidget as the central item in this window. Below the QTreeWidget I have several buttons; copy, edit, and delete. As you might've already guessed each one of these buttons correlates to a function that executes the command. My tree widget has the ability to select multiple items; however, when multiple items are selected the only item that is passed through is the last item that was selected. I was hoping that somebody with some more insight in this IDE might be able to point me in the right direction for accomplishing this. Here is the process that is followed when one of these functions is executed.
void InjectionGUI::copyInjection_Clicked(QTreeWidgetItem *itemToCopy)
{
InjectionData copyInjectionData; //first use data from the tree widget row
QString converter = itemToCopy->text(0); //to find the vector item that will be copied
int id = converter.toInt();
int nameNumber;
copyInjectionData = qTreeInjectionData.at(id);
qTreeInjectionData.append(copyInjectionData);
buildTreeWidget();
}
void InjectionGUI::slotInjectionCopy()
{
if(ui->treeWidgetInjections->currentItem() == 0)
{
QMessageBox invalidSelection;
invalidSelection.setText("No row selected to copy");
invalidSelection.setWindowTitle("Error");
invalidSelection.exec();
}
else
{
copyInjection_Clicked(ui->treeWidgetInjections->currentItem());
}
}
I'm not too sure what code will be relevant towards making this change; so if there is additional structure that anyone would like to see please just requested. I'm pretty sure that my problem or my solution is going to lie in the way that I'm using current item. After reviewing the documentation from Qt's website I'm still unsure how I would change this to allow multiple selections to be passed through the function. Please only provide constructive feedback; I'm only interested in learning and accomplishing a solution. Thanks in advance.
UPDATE! SOLVED!!!
Just thought it might be nice to show what this looked like implemented:
QList<QTreeWidgetItem *> items = ui->treeWidgetInjections->selectedItems();
for(int i = 0; i < items.size(); i++)
{
QTreeWidgetItem *qTreeWidgetitem = new QTreeWidgetItem;
qTreeWidgetitem = items.at(i);
copyInjection_Clicked(qTreeWidgetitem);
}
If you need to know which items are selected, you can use
QList<QTreeWidgetItem *> QTreeWidget::selectedItems() const
to have a list of all the currently selected items in the tree.
Then you may call your function once for every item in the list, or you can overload your function to take as argument a QList<QTreeWidgetItem *> and then run through the list inside the called function.