-3

I have a txt file to configure settings of a serial device, which looks like this:

`R ref, version, "config_ID",                   menu language, Power timeout (hours), Number of users
R  R1   1        "Template for setting parameters"  ENGLISH        1                      1

`U ref, "user name", language, volume, number of activities
U U1    "Any user"   ENGLISH   100%      1

`A ref, "activity name",    max duration, max cycles, startingPW%, available/hidden
 A A1   "Setup stim levels" 0min          0           0%           AVAILABLE FALSE FALSE TRUE TRUE

  B SA1 1 "Engine tests"
` These limits apply to all phases
`  M ref stim, channel, max current, minPW, maxPW, freq, waveform, output name
   M CH1 1 1 120mA 10us 450us 40Hz ASYM "Channel 1"
   M CH2 1 2 120mA 10us 450us 40Hz ASYM "Channel 2"

   P P0 "Test phase" 0ms NONE 2000ms STOP STOP STOP
`                Delay  RR    rate    PW    
    O CH1 0mA  0ms    0ms   600000ns 180us RATE   
    O CH2 0mA  0ms    0ms   600000ns 180us RATE

in my program , I need to read this file and change some values and save.

for example, in the last lines of the text:

  P P0 "Test phase" 0ms NONE 2000ms STOP STOP STOP
`                Delay  RR    rate    PW    
    O CH1 0mA  0ms    0ms   600000ns 180us RATE   
    O CH2 0mA  0ms    0ms   600000ns 180us RATE

I need to change those PW values (180us) into a value adjusted through a QSlider

ui->verticalSlider_ch1->value()
ui->verticalSlider_ch2->value()

Can you show me how to access those values from the txt file and change it?

p.s.

In the above-mentioned config file, comments are enclosed in backticks `` and replaced with space characters. A single backtick ` starts a comment that continues to the end of the line.

EDIT

From the comments, I tried to breakdown the problem into three parts:

1) Reading the file and extracting the contents of the O lines, 2) using that to present a screen with sliders

   QString filename = "config_keygrip";
   QString path = QCoreApplication::applicationDirPath()+"/"+filename+".txt";
   QFile file(path);

    if(!file.open(QIODevice::ReadOnly  | QIODevice::Text))
    {
        QMessageBox::information(this, "Unable to open file for read", file.errorString());
        return;
    }

    else
    {
        QTextStream in(&file);

        while(!in.atEnd())
        {
            QString line = in.readLine();
            QString trackName("O CH1");
            int pos = line.indexOf(trackName);
            if (pos >= 0)

            {

                QStringList list = line.split(' ', QString::SkipEmptyParts); // split line and get value
                QString currVal = QString::number(ui->verticalSlider->value());
                list[3] = currVal; // replace value at position 3 with slider value

            }
        }

        file.close();
    }

here I did the change in the memory.

  1. Writing back the new values to the file (with contents intact).

This is something I've difficulty implement with. How do I write those modified lines back to the original file?

  • Show what you have tried even if it does not work by clearly indicating where you are stuck since SO is not a SW writing service – eyllanesc Jan 22 '20 at 14:25
  • 1
    you have some single quotes in your text file that probably do not belong there. Code formatting is easier if you select the code then press the "Code sample" button on the top bar of the edit window – 463035818_is_not_an_ai Jan 22 '20 at 14:28
  • @formerlyknownas_463035818 Hi, In my config file , comments are enclosed in backticks ` ` and replaced with space characters. A single backtick ` starts a comment that continues to the end of the line. –  Jan 22 '20 at 14:35
  • ok, then please add this information to the question, because it isnt obvious. Poorly formatting looks similar ;) – 463035818_is_not_an_ai Jan 22 '20 at 14:37
  • 1
    This problem consists of three parts: 1) reading the file and extracting the contents of the O lines; 2) using that to present a screen with sliders; 3) writing back the new values to the file (presumably with contents intact). What have you tried for each? – Botje Jan 22 '20 at 15:20
  • @Botje , See the edit. I can now read lines and change contents by splitting it. How do I write back into the original file? –  Jan 23 '20 at 16:20

1 Answers1

1

It would be best if you keep the three steps separate, so in (untested) code:

struct Model { QVector<int> values; };
// I'm assuming you call this function when you start the program.
void MyWindow::load() {
    this->model = getModelFromFile("...");
    // set up UI according to model, this is just an example
    ui->verticalSlider->value = this->model.values[0];
    QObject::connect(ui->verticalSlider, &QSlider::valueChanged,
        [=](int value) { this->model.values[0] = value; });
    QObject::connect(ui->saveButton, &QPushButton::clicked, this, &MyWindow::saveModelToFile);
}

This allows you to manipulate the values of the Model struct with (currently 1, but possibly many) slider(s). It assumes there is a save button, which calls the following method when clicked. The gist of this method is that you open the original file for reading together with a fresh file for writing, and either copy lines (if not an O CH line) or replace the value in the line otherwise. At the end you replace the original file with the newly written file.

void MyWindow::saveModelToFile() {
    QString filename = "config_keygrip";
    QString path = QCoreApplication::applicationDirPath()+"/"+filename+".txt";

    QFile originalFile(path);
    originalFile.open(QIODevice::ReadOnly | QIODevice::Text); // TODO: error handling

    QFile newFile(path+".new");
    newFile.open(QIODevice::WriteOnly | QIODevice::Text); // TODO: error handling

    while (!originalFile.atEnd()) {
        QByteArray line = originalFile.readLine();
        if (line.contains("O CH")) {
            QStringList list = QString::fromUtf8(line).split(' ', QString::SkipEmptyParts);
            int channel = list[1].mid(2).toInt(); // list[1] is "CHx"
            list[6] = QString("%1us").arg(this->model.values[channel - 1]); // actually replace the value
            line = list.join(" ").toUtf8();
        }
        // copy the line to newFile
        newFile.write(line);
    }

    // If we got this far, we can replace originalFile with newFile.
    newFile.close();
    originalFile.close();

    QFile(path+".old").remove();
    originalFile.rename(path+".old");
    newFile.rename(path);
}

A basic implementation of getModelFromFile, without error handling and untested:

Model getModelFromFile(QString path) {
    Model ret;
    QFile file(path);
    file.open(QIODevice::ReadOnly | QIODevice::Text);
    while (!file.atEnd()) {
        QByteArray line = file.readLine();
        if (line.contains("O CH")) {
            QStringList list = QString::fromUtf8(line).split(' ', QString::SkipEmptyParts);
            int value = list[6].remove("us").toInt();
            ret.values.push_back(value);
        }
    }
    return ret;
}
Botje
  • 26,269
  • 3
  • 31
  • 41
  • 1
    Thanks a lot for the answer. Could you please give a bit more info on how to set a `model` here? Where does that model come from?. You mentioned `getModelFromFile`, how do we implement that? –  Jan 24 '20 at 11:31
  • 1
    You implement it like you already mostly had: read the file line by line. When you see a line with `O CH`, split it by spaces, push the value in the appropriate colum into a vector. – Botje Jan 24 '20 at 11:39
  • 1
    `this->model = getModelFromFile("...");` this is something I still coudnt understand, here the `model` is a List model?, could you show me a simple example how to implement this? –  Jan 24 '20 at 12:14
  • 1
    Added a very basic implementation of it to my answer. Note that it requires that all channel values are in order and that there are no gaps. – Botje Jan 24 '20 at 12:25
  • 1
    Thanks a lot for further clarification. Here, `this->model` what's `model`?, How do I initialize `model`? –  Jan 24 '20 at 14:22
  • 1
    It should be an instance variable of type `Model`. I put the definition of the `Model` type right above `MyWindow::load`. You do not need to initialize it, the default initialization will produce a model with an empty QVector. – Botje Jan 24 '20 at 14:33
  • 1
    So the `model` is pointer?, `Model *model`. in that case `this-> model = getModelFromFile(path);` gives me error `mainwindow.cpp:27:19: error: assigning to 'MainWindow::Model *' from incompatible type 'MainWindow::Model'`. Where `Model getModelFromFile(QString path);` is a public member fucntion of the class –  Jan 24 '20 at 14:59
  • 1
    Just put `Model model;` in your `MainWindow` declaration. It is a plain instance variable. Not a pointer, not a reference. – Botje Jan 24 '20 at 15:08