Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [SOLVED]Saving and reading information with QTextStream

[SOLVED]Saving and reading information with QTextStream

Scheduled Pinned Locked Moved General and Desktop
8 Posts 2 Posters 2.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Bolt2strikeB Offline
    Bolt2strikeB Offline
    Bolt2strike
    wrote on last edited by
    #1

    EDIT: I have solved my problem thanks very much.

    Hello fellow Qt users I have created a game of tic-tac-toe using Qt almost everything in it is functional but recently I attempted to add save/load game feature. I used QFile and QTextStream but, it won't work the game is saved correctly but is never loaded correctly my current setup for loading and saving is as follows:
    @void MainWindow::on_actionSaveGame_1_triggered()
    {
    QFile game1file("game1.txt");
    game1file.open(QIODevice::WriteOnly|QIODevice::Text);
    QTextStream game1(&game1file);
    game1 << ui->z11->text() << "\n";
    game1 << ui->z21->text() << "\n";
    game1 << ui->z31->text() << "\n";
    game1 << ui->z12->text() << "\n";
    game1 << ui->z22->text() << "\n";
    game1 << ui->z32->text() << "\n";
    game1 << ui->z13->text() << "\n";
    game1 << ui->z23->text() << "\n";
    game1 << ui->z33->text() << "\n";
    game1file.close();
    }

    void MainWindow::on_actionLoadGame_1_triggered()
    {
    QFile game1file("game1.txt");
    game1file.open(QIODevice::ReadOnly|QIODevice::Text);
    QTextStream game1(&game1file);
    game1.seek(1);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z11->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z11->setText("o");
    }
    else
    {
    ui->z11->setText("");
    }
    game1.seek(2);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z21->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z21->setText("o");
    }
    game1.seek(3);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z31->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z31->setText("o");
    }
    else
    {
    ui->z31->setText("");
    }
    game1.seek(4);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z12->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z12->setText("o");
    }
    else
    {
    ui->z12->setText("");
    }
    game1.seek(5);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z22->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z22->setText("o");
    }
    else
    {
    ui->z22->setText("");
    }
    game1.seek(6);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z32->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z32->setText("o");
    }
    else
    {
    ui->z32->setText("");
    }
    game1.seek(7);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z13->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z13->setText("o");
    }
    else
    {
    ui->z13->setText("");
    }
    game1.seek(8);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z23->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z23->setText("o");
    }
    else
    {
    ui->z23->setText("");
    }
    game1.seek(9);
    game1 >> tilestate;
    if (tilestate == "x")
    {
    ui->z33->setText("x");
    }
    else if (tilestate == "o")
    {
    ui->z33->setText("o");
    }
    else
    {
    ui->z33->setText("");
    }
    game1file.close();
    }
    @
    Could someone please explain what the issue is? I can provide more code if needed or even a working sample.
    Each Ui element prefixed with a 'z' is a tile and the numbers are co-ordinates for example z11 is x=1 and y=1 and z23 would be the top of the middle column.

    1 Reply Last reply
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi, welcome to devnet

      First of all... OMG... there are loops in programming languages you know. What if tic-tac-toe was 20x20 and not 3x3? Spend the weekend copy/pasting? ;)

      Second - when using QTextStream don't open the file in QFile::Text mode. The text stream will take care of the newlines.

      But to the point. You haven't said that but I'm guessing the possible state of the text is either "x", "o" or empty. Saving nothing (i.e. an empty string) is not not a good way to store something ;) Your usage of seek() doesn't make things better either.

      Consider this example (I'll shorten it to 5 for brevity):
      Save: nothing, nothing, x, o, nothing
      The content of the file is now:
      @
      \n
      \n
      x\n
      o\n
      \n
      @
      Now read like you did:
      @
      //why 1??? you skip the first newline that way
      //and QTextStream skips whitespace so:
      seek(1); game1 >> tilestate; //tilestate == "x";
      //why 2??? now you skip two newlines
      seek(2); game1 >> tilestate; //tilestate == "x" again
      //why 3??? now you skip two newlines and the x
      //QTextStream skips whitespace so:
      seek(3); game1 >> tilestate; //tilestate == "o";
      //why 4??? now you skip two newlines, x and another newline
      seek(4); game1 >> tilestate; //tilestate == "o" again
      //why 5??? now you skip two newlines, x, another newline and o
      seek(5); game1 >> tilestate; //tilestate == ""
      @
      So you entered: nothing, nothing, x, o, nothing
      You got back: x, x, o, o, nothing

      So a couple of things:

      • use loops, this is a classic example of a usage for them
      • don't open file in text mode when using QTextStream
      • don't save "nothing". Use some character to signify an empty space
      • c++ indices and offsets start at 0, not 1
      • operator >> of QTextStream skips whitespace (e.g. newlines)
      • seek() works with characters, not lines. The count also includes invisible characters like newlines
      • don't seek at all, just loop and use readLine()
      1 Reply Last reply
      0
      • Bolt2strikeB Offline
        Bolt2strikeB Offline
        Bolt2strike
        wrote on last edited by
        #3

        Thank you so much, that was very helpful and hilarious I couldn't even begin to imagine what your reaction would be if you saw all of the code *currently its nearly 1000 lines so yeah.... You'd probably go into a coma. Anyways thanks for the reply I've used some of your other answers to others posts as well. But, I still have one question would there be a way for me to systematically access the different tiles such as co-ordinates x=1 y=2 ui->"z" + x + y->setText(blah)? I've looked and tried but could not find anything plus, it's so unfortunate you cant't use variables in style-sheets WHY! Whatever, thank you.

        1 Reply Last reply
        0
        • Chris KawaC Offline
          Chris KawaC Offline
          Chris Kawa
          Lifetime Qt Champion
          wrote on last edited by
          #4

          The way I would do that would be something like this:
          @
          //define the grid size
          const int GridSize = 3;

          //create the tiles and place them in a grid layout:
          QList<Tile*> tiles; //I'll assume your tile class is called Tile
          QGridLayout* grid = new QGridLayout();
          for(int i = 0; i < GridSize; ++i)
          for(int j = 0; j < GridSize; ++j)
          tiles.append(new Tile());
          grid->addWidget(tiles.last(), i, j);
          }
          }
          someWidget->setLayout(grid); //someWidget might be your window

          //function to access specific tile by index:
          Tile* tile(int index) { return tiles[index]; }

          //or by x,y coordinate:
          Tile* tile(int x, int y) { return tiles[y * GridSize + x]; }

          //then you can access tile 1,2 text like this:
          tile(1,2)->text();
          @
          I'm skipping range checking etc. for brevity.
          Just remember that upper left is (0,0), and bottom right is (2,2), not (1,1) and (3,3).

          As for stylesheets - there are no variables, but if you name your widgets (using setObjectName) eg. "w12" then you can write a stylesheet specifically for that widget. For example:
          @
          QWidget#w12 { color: red }
          @

          Also, if your tile has a name like above you can access it through a parent by name e.g.
          @
          someParent->findChild<QWidget*>("w12")->setText("foo");
          @

          [EDIT]: Fixed some code. I was writing in a hurry.

          1 Reply Last reply
          0
          • Bolt2strikeB Offline
            Bolt2strikeB Offline
            Bolt2strike
            wrote on last edited by
            #5

            So, if I called @game1.pos()@ it would not give the line position?

            1 Reply Last reply
            0
            • Chris KawaC Offline
              Chris KawaC Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on last edited by
              #6

              No, it would give character position, which might be on any line, depending how much newline characters are between. There is no correlation between neither seek() nor pos() to a line number. The only method that understands concept of a line is (badam badam!) readLine() ;)

              1 Reply Last reply
              0
              • Bolt2strikeB Offline
                Bolt2strikeB Offline
                Bolt2strike
                wrote on last edited by
                #7

                I'm sorry to keep bothering you but now QTextStream won't even insert the newline character which I guess I could alter my reading function to account for that except... It just doesn't quite add up
                Code:
                @void MainWindow::on_actionSaveGame_1_triggered()
                {
                QString line;
                int linenum = 0;
                QFile game1file("game1.txt");
                game1file.open(QIODevice::WriteOnly);
                QTextStream game1(&game1file);
                QString z11,z21,z31,z12,z22,z32,z13,z23,z33;
                if (ui->z11->text() == "") z11 = ".";
                else z11 = ui->z11->text();
                if (ui->z21->text() == "") z21 = ".";
                else z21 = ui->z21->text();
                if (ui->z31->text() == "") z31 = ".";
                else z31 = ui->z31->text();
                if (ui->z12->text() == "") z12 = ".";
                else z12 = ui->z12->text();
                if (ui->z22->text() == "") z22 = ".";
                else z22 = ui->z22->text();
                if (ui->z32->text() == "") z32 = ".";
                else z32 = ui->z32->text();
                if (ui->z13->text() == "") z13 = ".";
                else z13 = ui->z13->text();
                if (ui->z23->text() == "") z23 = ".";
                else z23 = ui->z23->text();
                if (ui->z33->text() == "") z33 = ".";
                else z33 = ui->z33->text();

                game1 << z11 << "\n";
                game1 << z21 << "\n";
                game1 << z31 << "\n";
                game1 << z12 << "\n";
                game1 << z22 << "\n";
                game1 << z32 << "\n";
                game1 << z13 << "\n";
                game1 << z23 << "\n";
                game1 << z33 << "\n";
                /*while (linenum <= 9)
                {
                    ++linenum;
                    line = game1.readLine();
                    if (line == "")
                    {
                        game1 << ".\n";
                    }
                }*/
                game1file.close();
                

                }

                void MainWindow::on_actionLoadGame_1_triggered()
                {
                QString line;
                int linenum = -1;
                char tilemark;
                QFile game1file("game1.txt");
                game1file.open(QIODevice::ReadOnly);
                QTextStream game1(&game1file);
                while (linenum <= 9)
                {
                line = game1.readLine();
                //game1 << "\n";
                linenum++;
                if (line == ".") {}
                else if (linenum == 1) ui->z11->setText(line);
                else if (linenum == 2) ui->z21->setText(line);
                else if (linenum == 3) ui->z31->setText(line);
                else if (linenum == 4) ui->z12->setText(line);
                else if (linenum == 5) ui->z22->setText(line);
                else if (linenum == 6) ui->z32->setText(line);
                else if (linenum == 7) ui->z13->setText(line);
                else if (linenum == 8) ui->z23->setText(line);
                else if (linenum == 9) ui->z33->setText(line);
                }
                game1file.close();
                }
                @

                EDIT: I have just looked up said issue on the internet and found it is apparently because I didn't include QIoDevice:text like you'd said so I should try "<< endl;" But I found that to be no different and presented the same issue.

                EDIT 2: I realized I totally forgot to actually read the lines in my loop

                EDIT 3: I've looked at even more posts and concluded I need QIODevice::Text when I open the QFile so now the newline characters are inserted but still... The x's,o'x, and ".'s" are not being put in the right places

                EDIT 4: Tried entering some information manually, it doesn't load data correctly either

                I don't understand why QTextStream is making this so much more difficult for me x.x I remember when I only wrote console programs @#include <fstream>@ for life

                You know, what would be really cool is if you could store data with the Qt api and then have it handle everything for you so you can store a variable and rather than worrying about lines and everything you can just tell it to retrieve this variable or this section of data. Yeah, thay would be great.

                1 Reply Last reply
                0
                • Chris KawaC Offline
                  Chris KawaC Offline
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  Seriously... loops ;)

                  bq. I don’t understand why QTextStream is making this so much more difficult for me

                  It really doesn't. You're overthinking it ;)
                  @
                  QString makeName(int i, int j) {
                  return QString("z")+QString::number(i)+QString::number(j);
                  }

                  void MainWindow::save() {
                  QFile file("file.txt");
                  if(file.open(QIODevice::WriteOnly)) {
                  QTextStream stream(&file);

                      for(int i=1; i<4; ++i)
                      for(int j=1; j<4; ++j)
                          stream << (findChild<QLineEdit*>(makeName(i,j))->
                          text().isEmpty() ? ".\n" : "x\n");
                  }
                  

                  }

                  void MainWindow::load() {
                  QFile file("file.txt");
                  if(file.open(QIODevice::ReadOnly)) {
                  QTextStream stream(&file);

                      for(int i=1; i<4; ++i)
                      for(int j=1; j<4; ++j)
                          findChild<QLineEdit*>(makeName(i,j))->
                          setText(stream.readLine() == "." ? "" : "x");
                  }
                  

                  }
                  @

                  bq. You know, what would be really cool (...) Yeah, thay would be great.

                  You mean "QSettings":http://doc.qt.io/qt-5/qsettings.html ? ;)
                  @
                  QSettings s("file.txt", QSettings::IniFormat);
                  s.setValue("value1", 42);
                  int foo = s.value("value1").toInt();
                  @

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved