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. reading multi-line input from QSocketNotifier
QtWS25 Last Chance

reading multi-line input from QSocketNotifier

Scheduled Pinned Locked Moved Solved General and Desktop
qsocketnotifierqtextstream
4 Posts 2 Posters 301 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.
  • J Offline
    J Offline
    Joachim W
    wrote on 6 Aug 2024, 16:13 last edited by
    #1

    I want to write a GUI application that can also be steered from the command line. The following self-contained program reveals a first problem.

    #include <QAction>
    #include <QApplication>
    #include <QLayout>
    #include <QMainWindow>
    #include <QSocketNotifier>
    #include <QTextStream>
    #include <QToolButton>
    
    class MainWin : public QMainWindow {
     public:
        MainWin();
    
        void onCommand(const QString& cmd);
    };
    
    MainWin::MainWin()
    {
        setMinimumWidth(360);
    
        auto* a2 = new QAction{"quit"};
        connect(a2, &QAction::triggered, [this]() -> void {
    	close();
        });
    
        auto* b2 = new QToolButton;
        b2->setDefaultAction(a2);
        b2->setToolButtonStyle(Qt::ToolButtonTextOnly);
    
        auto* center = new QWidget;
        setCentralWidget(center);
    
        auto* vbox = new QVBoxLayout(center);
        vbox->addWidget(b2);
    
        show();
    }
    
    void MainWin::onCommand(const QString& cmd)
    {
        qDebug() << "READ " << cmd;
        // this shall be extended so that the GUI can also be steered from the command line
    }
    
    int main(int argc, char **argv)
    {
        QApplication app(argc, argv);
        app.setApplicationName("modal dialog test");
    
        MainWin mw;
    
        auto* notifier = new QSocketNotifier{fileno(stdin), QSocketNotifier::Read};
        QObject::connect(
            notifier, &QSocketNotifier::activated,
            [&mw](QSocketDescriptor, QSocketNotifier::Type type) {
                if (type == QSocketNotifier::Read) {
    		QTextStream qtin{stdin};
    // .... Variant A ....
      	        mw.onCommand(qtin.readLine());
    // .... Variant B ....    
    		do {
    		    mw.onCommand(qtin.readLine());
    		} while (!qtin.atEnd());
    // .... End of variants
    	    }
            });
    
        return app.exec();
    }
    

    Variant A works fine - as long as I enter the input manually, line by line. However, it fails if I paste a multi-line text block to stdin, or pipe a file to stdin.

    Variant B correctly reads copied & pasted multi-line input - but then it blocks the application forever; the "quit" button in the GUI no longer reacts to clicks.

    How to reconcile these two variants to meet all requirements?

    1 Reply Last reply
    0
    • J Offline
      J Offline
      Joachim W
      wrote on 7 Aug 2024, 08:19 last edited by Joachim W 8 Jul 2024, 08:19
      #3

      Too complex question after all, mixing at least two different problems:

      • switch from file to stdin (use freopen ?)
      • read from stdin with timeout

      I will work on these separately, therefore closing here.

      J 1 Reply Last reply 7 Aug 2024, 09:25
      0
      • J Offline
        J Offline
        Joachim W
        wrote on 6 Aug 2024, 18:06 last edited by
        #2
        // Variant C
            auto* notifier = new QSocketNotifier{fileno(stdin), QSocketNotifier::Read};
            QObject::connect(
                notifier, &QSocketNotifier::activated,
                [&mw](QSocketDescriptor, QSocketNotifier::Type type) {
        	    qDebug() << "notified";
                    if (type == QSocketNotifier::Read) {
        		QTextStream qtin{stdin};
        		QElapsedTimer timer;
        		timer.start();
        		do {
        		    qDebug() << "reading";
        		    QString cmd = qtin.readLine();
        		    qDebug() << "read " << cmd;
        		    if (cmd.isEmpty())
        			break;
        		    mw.onCommand(cmd);
        		} while (timer.nsecsElapsed() < 250e6);
        	    }
                });
        

        works for copied & pasted multiline-input, but not for piped input a.out < textfile, which results in an endless loop.

        1 Reply Last reply
        0
        • J Offline
          J Offline
          Joachim W
          wrote on 7 Aug 2024, 08:19 last edited by Joachim W 8 Jul 2024, 08:19
          #3

          Too complex question after all, mixing at least two different problems:

          • switch from file to stdin (use freopen ?)
          • read from stdin with timeout

          I will work on these separately, therefore closing here.

          J 1 Reply Last reply 7 Aug 2024, 09:25
          0
          • J Joachim W has marked this topic as solved on 7 Aug 2024, 08:19
          • J Joachim W
            7 Aug 2024, 08:19

            Too complex question after all, mixing at least two different problems:

            • switch from file to stdin (use freopen ?)
            • read from stdin with timeout

            I will work on these separately, therefore closing here.

            J Offline
            J Offline
            JonB
            wrote on 7 Aug 2024, 09:25 last edited by
            #4

            @Joachim-W
            I looked at your progress here but have not had an opportunity to examine it further. But here are a couple of points which strike me:

            • readLine() should read one line from input. It should not matter whether that comes from terminal (with or without pasting) or redirection. The fact that you seem to say sometimes it reads/returns one line and sometimes multiple lines should not happen. A line is a line. The QTextStream may (or may not) buffer further lines which are available (e.g. from redirection) but readLine() should only return a single line.

            • When reading from redirection you can/should be able to read till "end of file", indicating the end of input. But when reading from terminal there is no "end", user could type more at any time, so no "end of file".

            • You should not need a timer. One QSocketNotifier notification should be received when there is one or more lines/input available. Process all lines which are available (however you test for that) then exit. That should be it for the redirection case. For the terminal case at some future point a new QSocketNotifier notification should arrive at which point you re-enter and process whatever is available anew. You will need a readLine() call which returns with "empty" when no more input is currently available, or a test which says whether there is any further input available at this point before calling a blocking readLine(). It may be better to call readAll(): that should return all data which is available at that point, I believe, but will not block like readLine() when no further data is there. This will work for redirection too.

            1 Reply Last reply
            0

            3/4

            7 Aug 2024, 08:19

            • Login

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