Populating a table in Qt - c++

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.

Related

Making only one column of QTreeWidget editable // troubleshooting

Mind that this question isn't a duplicate of question Making only one column of a QTreeWidgetItem editable, as it's proposed solution doesn't work.
Hello, so I just want to make only ONE column of my treeWidget editable.
propertyItems.push_back(new QTreeWidgetItem); //gets filled by the while-loop
propertyItems[propertyItems.size()-1]->setText(0, prop.name); //sets the text of the item
propertyItems[propertyItems.size()-1]->setText(1, prop.value);//set the text of the other item
propertyItems[propertyItems.size()-1]->setFlags(Qt::ItemIsEditable);
ui->treeWidget_3->insertTopLevelItem(ui->treeWidget_3->topLevelItemCount(), propertyItems[propertyItems.size()-1]); //appends the items
counter ++;
and
void MainWindow::onTreeWidget3ItemDoubleClicked()
{
if (ui->treeWidget_3->currentColumn() == 2) {
ui->treeWidget_3->editItem(ui->treeWidget_3->currentItem(), ui->treeWidget_3->currentColumn());
}
}
is my approach. ontreeWidget3ItemDoubleClicked is connected with treeWidget::doubleClicked, treeWidget_3 has NO edit-triggers
BUT: when I execute the programm, the QTreeView is just grayed out.
That said, I also tried
propertyItems[propertyItems.size()-1]->setFlags(propertyItems[propertyItem.size()].flags | Qt::ItemIsEditable);
The treeWidget_3 isn't grayed off anymore, but it is still uneditable...
How can I fix this?
BTW: I am a newb to Qt so I might have forgotten something crucial. Sorry in this case.
As mentioned in the documentation:
The QTreeWidgetItem class provides an item for use with the QTreeWidget convenience class.
It means that it won't work for all use cases. The solution is to create your own model and overload the flags(const QModelIndex& index) method returning the appropriate values (basically Qt:: ItemIsEnabled for read-only columns and Qt:: ItemIsEnabled | Qt::ItemIsEditable for the editable one). You can get the column from index.column().
Qt provides an example to start with trees and models.

QListWidgetItem with Radio Button

I'm working on my first QT application and I have a problem with QListWidgetItems.
I will be having different kind of list.
for checkboxed list using:
listElement[i]->setFlags(Qt::ItemIsEnabled);
listElement[i]->setCheckState(Qt::Unchecked);
works exactly as wanted.
But now I want a Radio Button list. so my question is in two parts
can use the same logic that I used for checkBox to create Radio Buttons?
I have used:
listElement[i]->setFlags(Qt::ItemIsEnabled);
QRadioButton *radio1 = new QRadioButton(0);
dlList->setItemWidget(listElement[i],radio1);
this will display Items in the list with a radio Button, the problem is that the text is Over the Radio Button:
going to try to demonstrate without image
This is a test
o
for elements 1
instead for checkbox I have
This is a test
[]
for element 1
how can I get the radioButton to align correctly with text?
New Questions:
Thanks alot for the answers my text is next to my RadioButton now.
Only thing there is no WordWrap, My text is Longer than maximum Size of the RadioButton. How can I get it to wordwrap:
rButton = new QRadioButton();
rButton->setFixedSize(LIST_TEXT_WIDTH_WO_ICON, LIST_TEXT_HEIGHT);
rButton->setStyleSheet("border:none");
rButton->setFont(segoe18Font);
rButton->setText("This is just a test for elementsss of type euh!!!");
rButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
dropListWidget->setItemWidget(listElement, rButton);
As you may have read, there are two approaches to achieve what you want.
The most flexible one: use a QListView, implement a new delegate and a model if necessary.
Keep using the classic item-based interface (QListWidget) and change the item's widgets either by sub-classing QListWidgetItem or calling QListWidgetItem::setItemWidget.
Since the question points towards the second one, I'll try to provide the simplest item-based solution.
The following piece of code generates the list widget in the picture.
QListWidgetItem *it;
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item 1")));
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item 2")));
// .
// .
// .
it = new QListWidgetItem(ui->listWidget);
ui->listWidget->setItemWidget(it, new QRadioButton(tr("Item N")));
where ui->listWidget is a pointer to the QListWidget that holds the items.
I hope this helps. As far as I understand, that's what you need.

Replace QWidget with a new QWidget

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.

QTreeWidget Passing multiple Items (more then one selection) through a function

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.

Addressing QTableWidget Columns

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