QTableWidget to multiple files - c++

I’ve got QTableWidget with data like this:
table.png
The table can contains only names from the QList:
QList<QString> shapes { "Triangle", "Circle", "Trapeze", "Square", "Rectangle", "Diamond" };
with random int values in the neighboring cell.
Table can contain all "shapes" or only a part of it (like in the example).
I try to create separate file for each shape form the table and write down corresponding int values to them.
To achieve this I wrote something like that:
QList<QTableWidgetItem *> ItemList
/.../
for(int i = 0; i < rows; ++i)
{
for(int i = 0; i<columns; ++i)
{
foreach(QString itm, shapes )
{
ItemList = ui->tableWidget->findItems(itm, Qt::MatchExactly);
QFile mFile(itm + ".txt");
if(mFile.open(QFile::ReadWrite))
{
for(int i = 0; i < ItemList.count(); ++i)
{
int rowNR = ItemList.at(i)->row();
int columnNR = ItemList.at(i)->column();
out << "Values = " << ui->tableWidget->item(rowNR, columnNR+1)->text() << endl;
}
}
}
mFile.flush();
mFile.close();
}
}
Files are created for every item from the QList – if the shape from the QList is not in the table, an empty file is created.
How to create files only on the basis of available names in the table?

You can write like this.
QList<QTableWidgetItem *> ItemList
/.../
for(QString str : Shapes){
ItemList = ui->tableWidget->findItems(itm, Qt::MatchExactly); // Get the matching list
if(ItemList.isEmpty(){
continue; // If shape does not exist in table skip the iteration
}
QFile mFile(str + ".txt");
if(!mFile.open(QFile::ReadWrite){
return; // This should not happen ; this is error
}
for(QTableWidgetItem *item : ItemList){
int row = item->row();
int col = item->column()+1; // since it is neighboring cell
QString Value = ui->tableWidget->item(row,col)->text();
mFile.write(Value.toUtf8()); // You can change the way in which values are written
}
mFile.flush();
mFile.close();
}

Related

QT retrieve custom widget from layout

I have a scroll area with a layout that has 8 of the same custom widgets that have been added to it. This custom widget has a getter function that will return a value. My question is how to get back that original custom widget so I can call the getter function to retrieve the data it stores?
I have added the custom widget to the layout this way:
for (int var = 0; var < 9; ++var) {
calcRow *CalcWidget = new calcRow(this, &js, KeyList, SizeList);
connect(CalcWidget, &calcRow::testSignal, this, &MainWindow::getRowData);
ui->scrollArea_layout->layout()->addWidget(CalcWidget);
}
Where I am stuck:
void MainWindow::getRowData()
{
for (int i = 0;i < ui->scrollArea_layout->layout()->count() ;++i ) {
QWidget *row = ui->scrollArea_layout->layout()->itemAt(i)->widget();
if(row != NULL)
{
std::cout << row->"SOMETHING TO GET CALCROW WIDGET" <<std::endl;
}
}
}
Usually it's not the best structure for your code, any layout change might break your implementation. For example this solution will not work if you will have multiple calcRow widgets.
To make it better, you can pass required parameters which you want use inside getRowData as a parameters of testSignal signal.
Or just simplify it even more with lambda:
for (int var = 0; var < 9; ++var) {
calcRow* CalcWidget = new calcRow(this, &js, KeyList, SizeList);
connect(CalcWidget, &calcRow::testSignal, [CalcWidget]()
{
std::cout << CalcWidget->"SOMETHING TO GET CALCROW WIDGET" << std::endl;
});
ui->scrollArea_layout->layout()->addWidget(CalcWidget);
}
For anyone else that will find this in the future, the comments helped a bunch and I ended up using static_cast. My final code looks like this:
void MainWindow::getRowData()
{
for (int i = 0;i < ui->scrollArea_layout->layout()->count() ;++i ) {
QWidget *row = ui->scrollArea_layout->layout()->itemAt(i)->widget();
calcRow *rowConverted = static_cast<calcRow*>(row);
if(row != NULL)
{
std::cout << rowConverted ->getData() <<std::endl;
}
}
}

Qt - record from .cvs file causing errors when pushed into vector

I am writing a program that fills a QTableView with data from a cvs file. I am also pushing that data into a vector of objects from a class. I want to be able to catch any record from the file that may cause an out of bound error and move onto the next line without adding that record to the table or the vector.
Here is the function that populates the table:
QString filename = "currentstudents.csv";
QFile file(filename);
file.open(QIODevice::ReadOnly);
int lineindex = 0;
QTextStream input(&file);
while (!input.atEnd()) {
std::vector<QString> newRecord;
QString fileLine = input.readLine();
QStringList lineToken = fileLine.split(",", QString::SkipEmptyParts);
for (int i = 0; i < lineToken.size(); i++) {
QString value = lineToken.at(i);
newRecord.push_back(value); //this line is where out of bounds error comes from
QStandardItem *item = new QStandardItem(value);
currentStudentsModel->setItem(lineindex, i, item);
}
try
{
//creating a student object with the information parsed from the file
CurrentStudent student(newRecord.at(0), newRecord.at(1), newRecord.at(2).toInt(), newRecord.at(3).toInt(), newRecord.at(4).toInt(), newRecord.at(5).toUInt());
currentStudents.push_back(student);
}
catch (const std::out_of_range& e)
{
qDebug() << "OUT OF RANGE ERROR: " << e.what();
}
lineindex++;
}
If a record in the file is formatted in any weird way such as (,,,,,,) or without 6 commas to separate the data, it will load the record into the table improperly and then cause an out of bounds error eventually. How do I get the program to just skip over the problematic line and move onto the next?
You could add a validation test:
while (!input.atEnd())
{
// ...
for (int i = 0; i < lineToken.size(); i++) {
// load newRecord...
}
// validate..
if (newRecord.size() != 6)
{
// print warning here ?
// skip
continue;
}
if (newRecord.at(0) == "") // for example...
{
// print warning here ?
// skip
continue;
}
// more validation ?
// add record
CurrentStudent student(newRecord.at(0), newRecord.at(1), newRecord.at(2).toInt(), newRecord.at(3).toInt(), newRecord.at(4).toInt(), newRecord.at(5).toUInt());
currentStudents.push_back(student);
} // end loop

C++ Replace Value in Config File

I am trying to replace a value in a configuration file. It can be edited in a text editor.
[MODEL]
...
Latitude = 1.034
Longitude = 110.58334
...
How can I search for the keyword "Latitude" and replace "1.034" with another value? (e.g. 1.04)
Edit: Thanks for the down votes. I have attached my code below:
QFile fileReadModels(CP1);
fileReadModels.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream inModels(&fileReadModels);
while(!inModels.atEnd())
{
QString lineModels = inModels.readLine();
if(lineModels.isNull())
{
break;
}
else
{
strListInModels.append(lineModels);
}
}
fileReadModels.close();
int startFlag = 0;
int stopFlag = 0;
for(int i = 1; i <= strListInModels.count(); i++)
{
if(strListInModels[i].contains("Latitude", Qt::CaseInsensitive) == 1)
{
//! get start position
startFlag = i - 1;
//! get stop position
stopFlag = i + 2;
break;
}
}
//! get data from start till start position
for(int x = 0; x <= startFlag; x++)
{
strListOutModels << strListInModels[x];
}
//! insert in Ownship1 lat/lon
QString os1LatStr = " Latitude = " + os1Lat;
QString os1LonStr = " Longitude = " + os1Lon;
strListOutModels << os1LatStr;
strListOutModels << os1LonStr;
//! get data from stop postion till end
for(int y = stopFlag; y < strListInModels.count(); y++)
{
strListOutModels << strListInModels[y];
}
//! write to file
QFile fileWriteModels(CP1);
fileWriteModels.open(QIODevice::ReadWrite | QIODevice::Truncate);
QTextStream outModels(&fileWriteModels);
QString qStrModels = strListOutModels.join("\r");
outModels << qStrModels;
fileWriteModels.close();
You can use QSettings feature
location.ini
[MODEL]
Latitude = 1.034
Longitude = 110.58334
You can use QSetting to modify your data
//Access your datafile
QSettings settings("location.ini", QSettings::IniFormat);
//Read Data
QString sLatitude = settings.value("MODEL/Latitude").toString();
//Write Data
settings.setValue("MODEL/Latitude", "18.55");

how can I verify if multiple checkboxes are checked

std::string output;
if ((checkbox1->isChecked() && checkbox2->isChecked()) &&
(!checkbox3->isChecked() || !checkbox4->isChecked() || !checkbox5->isChecked() || !checkbox6->isChecked()))
{
output = " Using Checkbox: 1, 2 ";
}
if ((checkbox1->isChecked() && checkbox2->isChecked() && checkbox3->isChecked()) &&
(!checkbox4->isChecked() || !checkbox5->isChecked() || !checkbox6->isChecked()))
{
output = " Using Checkbox: 1, 2, 3 ";
}
....
using QT creator how can I verify how many checkboxes have been checked and change the output string accordingly?
with multiple if statements it's not working due to me getting confused with all those NOT AND OR.
and it takes a long time to code all possibilities.
All your checkBoxes should be in groupBox
Try this:
QList<QCheckBox *> allButtons = ui->groupBox->findChildren<QCheckBox *>();
qDebug() <<allButtons.size();
for(int i = 0; i < allButtons.size(); ++i)
{
if(allButtons.at(i)->isChecked())
qDebug() << "Use" << allButtons.at(i)->text()<< i;//or what you need
}
Use an array of checkboxes like this
// h-file
#include <vector>
class MyForm {
...
std::vector< QCheckBox* > m_checkBoxes;
};
// cpp-file
MyForm::MyForm() {
...
m_checkBoxes.push_back( checkbox1 );
m_checkBoxes.push_back( checkbox2 );
...
m_checkBoxes.push_back( checkbox5 );
}
...
output = " Using Checkbox:";
for ( int i = 0, size = m_checkBoxes.size(); i < size; ++i ) {
if ( m_checkBoxes[ i ]->isChecked() ) {
output += std::to_string( i + 1 ) + ", ";
}
}
TLDR: Place them in a container and build your string by iterating over them.
Code:
// line taken from #Chernobyl
QList<QCheckBox *> allButtons = ui->groupBox->findChildren<QCheckBox *>();
auto index = 1;
std::ostringstream outputBuffer;
outputBuffer << "Using Checkbox: ";
for(const auto checkBox: allButtons)
{
if(checkBox->isChecked())
outputBuffer << index << ", ";
++index;
}
auto output = outputBuffer.str();
Use QString instead of std::string and then:
QCheckBox* checkboxes[6];
checkbox[0] = checkbox1;
checkbox[1] = checkbox2;
checkbox[2] = checkbox3;
checkbox[3] = checkbox4;
checkbox[4] = checkbox5;
checkbox[5] = checkbox6;
QStringList usedCheckboxes;
for (int i = 0; i < 6; i++)
{
if (checkbox[i]->isChecked())
usedCheckboxes << QString::number(i+1);
}
QString output = " Using Checkbox: " + usedCheckboxes.join(", ") + " ";
This is just an example, but there's numerous ways to implement this. You could keep your checkboxes in the QList which is a class field, so you don't have to "build" the checkboxes array every time. You could also use QString::arg() instead of + operator for string when you build the output, etc, etc.
What I've proposed is just a quick example.

QListWidget Insert Items

I am trying to add two items into my QListWidget dynamically. However, the following codes only allow me to add only the last item into the list. strList.size() contains 4 items. Assuming name contains "ABC 1" and "ABC 2".
Is my loop incorrect? Or is my method of adding items into the listWidget wrong?
.h:
public:
QListWidgetItem *item[2];
.cpp:
...
while(!xml.atEnd())
{
xml.readNextStartElement();
if(xml.isStartElement())
{
if(xml.name() == "OS")
{
strList << xml.readElementText();
}
}
}
int num = 0;
for(int i = 0; i < strList.size(); i++)
{
if(strList[i] == "ABC")
{
QString name = strList[i] + strList[i+1];
item[num] = new QListWidgetItem();
item[num]->setText(name);
ui.listWidget->insertItem(num, item[num]);
num += 1;
}
}
Output (listWidget):
ABC02
Expected output (listWidget):
ABC01 ABC02