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. Blocking the event loop

Blocking the event loop

Scheduled Pinned Locked Moved General and Desktop
12 Posts 5 Posters 5.2k 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.
  • S Offline
    S Offline
    seanr8
    wrote on last edited by
    #1

    I'm new to GUI programming. I've written a client side for a messaging application, but the text never updates in the chat window. I've been reading around different posts and I keep coming up with that I'm blocking the event loop, but I really don't understand how I am, which probably means I don't fully understand what the event loop is.

    Here's the code I have for my MainWindow (where the loop is blocked).
    The ui->textBrowser is what never updates.

    @MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
    {
    bool flag;
    serverAddr = new QString;
    serverPort = new int;
    userName = new QString;
    startDialog start(serverAddr, serverPort, userName,this);
    start.setModal(true);
    start.exec();

    flag = MainWindow::Connect();
    ui->setupUi(this);
    if(!flag)
    {
        ui->textBrowser->setText("Unable to connect to server. Please restart client to try again.");
    }
    else
    {
        ui->textBrowser->setText("Successfully connected");
    }
    

    connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()));
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(on_pushButton_clicked()));
    }

    MainWindow::~MainWindow()
    {
    delete ui;
    delete serverAddr;
    delete serverPort;
    delete userName;
    delete socket;
    }

    bool MainWindow::Connect()
    {
    socket = new QTcpSocket(this);
    bool flag=false;
    QString tempString;
    socket->connectToHost(*serverAddr,*serverPort);
    if(!socket->waitForConnected())
    flag = false;
    else flag=true;
    if(flag)
    {//attempt to register user with name
    socket->write("REG\n");
    socket->flush();
    socket->waitForBytesWritten(3000);
    socket->waitForReadyRead();
    tempString = socket->readAll();
    if(tempString == "ACK")
    {
    socket->write(userName->toUtf8());
    socket->flush();
    tempString.clear();
    socket->waitForReadyRead();
    tempString = socket->readAll();
    if(tempString=="ACK")
    {
    return true;
    }
    else return false;
    }
    else return false;
    }
    else return false;
    }

    void MainWindow::readyRead()
    {
    //client has now been told by the socket that there is data to be ready that is not a part of the sending or registering. cool
    QString temp,browsTemp;
    temp=socket->readAll();
    ui->textBrowser->append(temp);
    ui->textBrowser->repaint();
    temp.clear();
    }

    void MainWindow::on_pushButton_clicked()
    {
    //user clicked the send button and would like their message to be sent. woooo.
    QString temp, stuff;
    temp=ui->lineEdit->text();
    socket->write("MSG\n");
    socket->flush();
    //socket->waitForBytesWritten(3000);
    // socket->waitForReadyRead();
    //socket->flush();
    //stuff=socket->readAll();
    //stuff=socket->readAll();

    //ready to send
    socket->write(temp.toUtf8());
    socket->flush();
    ui->lineEdit->clear();
    // socket->waitForReadyRead();
    // stuff=socket->readAll();
    // if(stuff!="ACK")
    // {
    // ui->textBrowser->clear();
    // ui->textBrowser->setText("Send failed. Please close client to reconnect");
    // }

    }@

    Thanks

    1 Reply Last reply
    0
    • B Offline
      B Offline
      b1gsnak3
      wrote on last edited by
      #2

      firstly, I think in line 13 you should use this->Connect(); not MainWindow::Connect();

      Also, you could use qDebug() << messages to see where your program doesn't go.

      1 Reply Last reply
      0
      • raven-worxR Offline
        raven-worxR Offline
        raven-worx
        Moderators
        wrote on last edited by
        #3

        yes most of the QTcpSocket functions you're using are blocking. But all of them have a time limit...

        For clarification:
        You can see the event loop as a infinite loop in which every iteration sends the available events to it's receiver objects. Events may be Mouse events, keyboard events, paint events, timer events, etc.
        Mostly you start the main event loop with QApplication.exec() und thus starting the engine of your application ;)

        --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
        If you have a question please use the forum so others can benefit from the solution in the future

        1 Reply Last reply
        0
        • C Offline
          C Offline
          ChrisW67
          wrote on last edited by
          #4

          Your code calls Connect() in the constructor. Connect() tries to implement a Qt networking conversation. Qt networking is inherently asynchronous and relies on event delivery via the event loop. UI redraw relies on the UI being visible and the event loop.

          Your main() function presumably looks like this:
          @
          QApplication app(argc, argv);
          MainWindow m;
          m.show();
          return app.exec();
          @
          All of your code is trying to happen at line 2, before the UI is shown and before the event loop is started at line 4. You have attempted to compensate using the blocking calls but really you need to move this processing until after the event loop is started and use the non-blocking methods. You can use a zero length timer set up in the constructor to call a slot immediately after the event loop starts processing.

          1 Reply Last reply
          0
          • S Offline
            S Offline
            seanr8
            wrote on last edited by
            #5

            Would the issue be fixed if I created a new class that inherited QTcpSocket and used that for all the connection stuff in the MainWindow?

            And what constructor would I be calling? The MainWindow constructor or the QTcpSocket constructor if I used the 0 length timer?

            1 Reply Last reply
            0
            • K Offline
              K Offline
              KA51O
              wrote on last edited by
              #6

              I think you don't need a new class, just split all the stuff you do in your connect funtion into more dedicated slots and don't use the syncronous methods from QTcpSocket.

              For example in your connect function just do the connect call and instead of calling waitForConnected connect a new slot (you will have to implement this) to the connected() signal of the socket you use. Then in this new slot proceed with the next step you want to take. Repeat this pattern until everything you want your client to do is covered.

              1 Reply Last reply
              0
              • S Offline
                S Offline
                seanr8
                wrote on last edited by
                #7

                If I put all the synchronous methods in a new thread, would that be useful? Most of my server side is dependent on synchronization, so I'd really like to keep using those methods.

                1 Reply Last reply
                0
                • K Offline
                  K Offline
                  KA51O
                  wrote on last edited by
                  #8

                  You don't need a new thread if you use all the asyncronous methods. You would just add a new layer of complexity to your application by using threads. It really isn't that much work to change the existing code you already have to the asyncronous approach. Its easier to debug this way and you will learn more about the event-driven nature of Qt, which you will have to do sooner or later.

                  To make the decision easier for you here's the first step:
                  @
                  void MainWindow::Connect()
                  {
                  socket = new QTcpSocket(this);
                  connect(socket, SIGNAL(connected()), this, SLOT(clientConnected()));
                  connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
                  connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(handleSocketError(QAbstractSocket::SocketError)));
                  socket->connectToHost(*serverAddr,*serverPort);
                  }

                  void MainWindow::clientConnected()
                  {
                  //you are now connected, continue with your execution
                  connect(socket, SIGNAL(bytesWritten(qint64), this, SLOT(handleBytesWritten(qint64))));
                  connect(socket, SIGNAL(readyRead(), this, SLOT(handleReadyRead())));
                  socket->write("REG\n");
                  socket->flush();
                  }

                  void MainWindow::handleBytesWritten(qint64 a_bytesSize)
                  {
                  // handle the bytesWritten signal if you need to
                  }

                  void MainWindow::handleReadyRead()
                  {
                  // handle the readyRead signal
                  // for example
                  QString tempString = socket->readAll();
                  if(tempString == "ACK" && !m_bUserNameSend )
                  {
                  socket->write(userName->toUtf8());
                  socket->flush();
                  // use a member variable to remember that you send the username if you need to
                  m_bUserNameSend = true;
                  }
                  else
                  {
                  if(tempString == "ACK" && m_bUserNameSend)
                  {
                  // DO THE NEXT STEP.
                  }
                  }
                  }

                  void MainWindow::clientDisconnected()
                  {
                  // your client disconnected, handle this if you want to
                  }

                  void MainWindow::handleSocketError(QAbstractSocket::SocketError a_error)
                  {
                  // something went wrong, check the SocketError and handle the error accordingly
                  }
                  @

                  1 Reply Last reply
                  0
                  • K Offline
                    K Offline
                    KA51O
                    wrote on last edited by
                    #9

                    BTW you don't need to send your own "ACK" acknowledgments, because if you listen to the socket signals error() and disconnected() you will immediately see if something went wrong and if you don't receive these signals you can assume that everything was received correctly. The TCP/IP protocol already handles the acknowledgments and all that stuff for you. But I guess you do this just for testing and as a learning exercise.

                    For more info about the signals you can already use see the docs for "QIODevice":http://qt-project.org/doc/qt-4.8/qiodevice.html and "QAbstractSocket":http://qt-project.org/doc/qt-4.8/qabstractsocket.html, which are inherited by QTcpSocket.

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      seanr8
                      wrote on last edited by
                      #10

                      This project is for a networking class I'm in, so yes, the ACKs are just so I can see myself what's going on. I do know that TCP/IP takes care of all that for me.

                      And I really appreciate the help, KA510. I get what you mean about not using synchronous and to just use socket signal handling. It does make a lot more sense to me now. I'm working on it now.

                      1 Reply Last reply
                      0
                      • K Offline
                        K Offline
                        KA51O
                        wrote on last edited by
                        #11

                        Glad I could persuade you to join the asynchronous side ^^
                        And don't forget what ChrisW67 said! For example you could move the connect call out of your constructor and start it by clicking a button (connect the buttons clicked() signal to your slot connect() ) or use a timer ( "singleshot":http://qt-project.org/doc/qt-4.8/qtimer.html#singleShot ) to start the connect() as soon as the eventloop is running.

                        TBH I'm not sure if you have to do this if all your stuff is using the asynchronous approach?

                        1 Reply Last reply
                        0
                        • S Offline
                          S Offline
                          seanr8
                          wrote on last edited by
                          #12

                          Just finished it and except for minor changes to my server (a few issues with thread exiting), the program works flawlessly now. Thank you so much to everyone who helped.

                          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