На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела *nix / gcc / Eclipse / Qt / wxWidgets / GTK+
  • При создании темы ОБЯЗАТЕЛЬНО указывайте версию тулкита / библиотеки / компилятора.
  • Перед тем как задать вопрос, сформулируйте его правильно, чтобы вас могли понять.
  • Нарушение Правил может повлечь наказание со стороны модераторов.


Полезные ссылки:
user posted image Boost по-русски
user posted image Qt по-русски
Модераторы: Majestio
  
> Эмуляция работы консольного окна через QPlainTextEdit в приложении GUI
    Есть некоторое GUI-шное приложение. И в нём при нажатии на одну кнопку происходит вызов диалога, который эмулирует консольное окно. На этом диалоге расположен компонент типа класса Console, который является потомком класса QPlainTextEdit:

    ExpandedWrap disabled
      class Console : public QPlainTextEdit


    В это текстовое поле должна выводиться и вводиться информация. Я нашёл такой способ эмуляции консольного окна:

    habr.com/ru/articles/122831/

    С выводом информации и с обработкой нажатия клавиш всё ясно. Но как быть с вводом информации?
    То есть, например, в текстовое поле было выведено "Введите первое число: " , а как потом сделать ожидание ввода (аналог функций scanf, getstr или _getch в консольных приложениях)?
    То есть как сделать так, чтобы программа ожидала бы ввода какой-то строки и последующего нажатия клавиши Return (Enter)?
    А после этого программа снова вывела бы другую надпись, например "Введите второе число: " и снова ожидало бы ввода строки?

    Как всё это можно сделать?
      Раз с обработкой нажатия клавиш все ясно, тогда в чем проблема то? Обрабатывайте нажатия, пока не получите значения клавиши Enter.
        Цитата erslgoeirjh @
        Как всё это можно сделать?

        Прочитай про установку фильтров событий в Qt. В той статье, что ты указал - там как раз об этом говорится. Да, получится очень жалкое подобие эмуляции терминала. Но нормальная эмуляция - вопрос очень не простой. Посмотри проект "нормального" эмулятора терминала - ConEmu, и сам зацени уровень сложности.
          Если правильно понял:
          Для ожидания ввода строки и последующего нажатия клавиши Return (Enter) в текстовом поле QPlainTextEdit можно использовать сигналы и слоты в Qt. Следующий пример показывает, как это можно сделать:

          ExpandedWrap disabled
            // Создаем слот для обработки нажатия клавиши Return (Enter)
            void Console::onReturnPressed() {
                // Получаем текст из текстового поля
                QString inputText = this->toPlainText();
                // Очищаем текстовое поле
                this->clear();
                // Обрабатываем введенную строку (например, выводим ее на экран)
                qDebug() << "Input: " << inputText;
                // Выводим следующую надпись
                this->appendPlainText("Введите второе число: ");
            }
             
            // В конструкторе класса Console подключаем сигнал editingFinished() к слоту onReturnPressed()
            Console::Console(QWidget *parent) : QPlainTextEdit(parent) {
                connect(this, &QPlainTextEdit::editingFinished, this, &Console::onReturnPressed);
                this->appendPlainText("Введите первое число: ");
                this->setFocus(); // Устанавливаем фокус на текстовое поле
            }


          В данном примере, при нажатии клавиши Return (Enter) в текстовом поле, сигнал editingFinished() будет вызван и связанный с ним слот onReturnPressed() будет выполнен. Внутри слота onReturnPressed() можно получить текст из текстового поля, очистить его и обработать введенную строку. Затем можно добавить следующую надпись в текстовое поле и ожидать ввода следующей строки.
            Я написал:

            1) класс Console:

            ExpandedWrap disabled
              class Console : public QPlainTextEdit
              {
              public:
                  explicit  Console(QWidget *parent=nullptr);
                  explicit  Console(const QString &text, QWidget *parent=nullptr);
                  virtual  ~Console();
                  void  output(QString s);
              protected:
                  void  mousePressEvent(QMouseEvent *);
                  void  keyPressEvent(QKeyEvent *event);
                  void  onEnter();
              public:
                  bool  isLocked;
              };
               
              void  Console::keyPressEvent(QKeyEvent *event)
              {
                  if (isLocked==true)
                      return;
                  if ((event->key()>=0x20)&&(event->key()<=0x7e)&&((event->modifiers()==Qt::NoModifier)||(event->modifiers()==Qt::ShiftModifier)))
                      QPlainTextEdit:;keyPressEvent(event);
                  if ((event->key==Qt::Key_Return)&&(event->modifiers()==Qt::NoModifier))
                      onEnter();
              }
               
              void  Console::onEnter()
              {
                  textCursor().insertBlock();
                  isLocked = true;
              }
               
              void  Console::output(QString s)
              {
                  textCursor().insertBlock();
                  textCursor().insertText(s);
                  isLocked = false;
              }


            2) класс ConsoleWindow--класс диалогового окна, который содержит на себе компонент plainTextEdit типа Console:

            ExpandedWrap disabled
              void  ConsoleWindow::print(char* s)
              {
                  QString  myString;
               
                  myString = QString(s);
                  ui->plainTextEdit->output(myString);
              }
               
              void  ConsoleWindow::getstr(char *s)
              {
                  string  stdstr;
                  QString  myString;
               
                  isEntered = false;
                  while (isEntered==false)
                  {
                      if (ui->plainTextEdit->isLocked==true)
                                                      isEntered = true;
                  }
                  QTextCursor  textCursor = ui->plainTextEdit->textCursor();
                  QTextBlock  textBlock = textCursor.block();
                  myString = textBlock.text();
                  stdstr = myString.toStdString();
                  strcpy(s,stdstr.c_str());
              }


            3) в классе MainWindow, соответствующему главному диалоговому окну приложения:

            ExpandedWrap disabled
              void  MainWindow::on_pushButton_clicked()
              {
                  char  s[80], s1[80], s2[80], s3[80], s4[80];
                  double  val1, val2, val3;
               
                  ConsoleWindow *consoleWindow = new ConsoleWindow(this);
                  consoleWindow->mainWindow = this;
                  consoleWindow->show();
                  strcpy(s,"Введите первое вещественное число: \n");
                  consoleWindow->print(s);
                  consoleWindow->getstr(s1);
                  // ...    
              }


            В результате чего при отладке программы действия с выводом и вводом данных в ConsoleWindow "зависают"--само окно ConsoleWindow с компонентом plainTextEdit выводится, то там не отображается строка "Введите первое вещественное число" и нет ожидания ввода последующей строки. В чём причина этого? Можно ли как-то сделать так, чтобы заработало ожидание ввода строки из plainTextEdit и сам этот ввод?
              Ура, заработало!

              Код:

              1) файл console.h :

              ExpandedWrap disabled
                #include <QObject>
                #include <QPlainTextEdit>
                 
                class Console : public QPlainTextEdit
                {
                    Q_OBJECT
                    public:
                    explicit  Console(QWidget *parent=nullptr);
                    explicit  Console(const QString &text, QWidget *parent=nullptr);
                    virtual  ~Console();
                    void  output(QString s);
                    void  sendSignal();
                    protected:
                    void  mousePressEvent(QMouseEvent *);
                    void  keyPressEvent(QKeyPressEvent *event);
                    signals:
                    void  lineEntered();
                };


              2) в файле console.cpp :

              ExpandedWrap disabled
                void  Console::keyPressEvent(QKeyEvent *event)
                {
                    if ((event->key()>=0x20)&&(event->key()<=0x7e)&&((event->modifiers()==Qt::NoModifier)||(event->modifiers()==Qt::ShiftModifier)))
                        QPlainTextEdit::keyPressEvent(event);
                    if (((event->key()==Qt::Key_Backspace)||(event->key()==Qt::Key_Left)||(event->key()==Qt::Key_Right))&&(event->modifiers()==Qt::NoModifier))
                        QPlainTextEdit::keyPressEvent(event);
                    if ((event->key()==Qt::Return)&&(event->modifiers()==Qt::NoModifier))
                    {
                        sendSignal();
                        QPlaintTextEdit::keyPressEvent(event);
                    }  
                }
                 
                void  Console::output(QString s)
                {
                    appendPlainText(s);
                }
                 
                void  Console::sendSignal()
                {
                    emit  lineEntered();
                }


              3) файл consolewindow.h :

              ExpandedWrap disabled
                #include <QDialog>
                #include "mainwindow.h"
                #include "ui_mainwindow.h"
                 
                namespace  Ui {
                    class  ConsoleWindow;
                }
                 
                class ConsoleWindow : public QDialog
                {
                    Q_OBJECT
                    public:
                    explicit  ConsoleWindow(QWidget *parent=nullptr);
                    ~ConsoleWIndow();
                    private slots:
                    void  on_pushButton_2_clicked();
                    public slots:
                    void  onEnter();
                    private:
                    Ui::ConsoleWIndow *ui;
                    public:
                    void  print(char* s);
                    void  getstr(char* s);
                    int  curlength;
                    char  mystr[80];
                    MainWindow *mainWindow;
                    QEventLoop  loop;
                };


              4) в файле consolewindow.cpp :

              ExpandedWrap disabled
                void  ConsoleWindow::print(char* s)
                {
                    QString  myString;
                 
                    myString = QString(s);
                    ui->plainTextEdit->output(myString);
                }
                 
                void  ConsoleWindow::getstr(char *s)
                {
                    int  index, length;
                    string  stdstr;
                    QString  myString;
                 
                    connect(ui->plainTextEdit,SIGNAL(lineEntered()),this,SLOT(onEnter()));
                    loop.exec();
                    myString = ui->plainTextEdit->toPlainText();
                    length = myString.length();
                    myString = myString.left(length-1);
                    index = myString.lastIndexOf('\n');
                    myString = myString.right(length-index-2);
                    stdstr = myString.toStdString();
                    strcpy(s,stdstr.c_str());
                    disconnect(ui->plainTextEdit,SIGNAL(lineEntered()),this,SLOT(onEnter()));    
                }
                 
                void  ConsoleWindow::onEnter()
                {
                    loop.exit();
                }


              5) в файле mainwindow.cpp :

              ExpandedWrap disabled
                void  MainWindow::on_pushButton_clicked()
                // если была нажата кнопка "Тестировать"
                {
                    char  s[80], s1[80], s2[80], s3[80], s4[80], sanswer[10];
                    double  val1, val2, val3;
                 
                    ConsoleWindow *consoleWindow = new ConsoleWIndow(this);
                    consoleWindow->mainWindow = this;
                    consoleWindow->show();
                    metka: ;
                    strcpy(s,"Введите первое вещественное число:\n");
                    consoleWindow->print(s);
                    consoleWindow->getstr(s1);
                    strcpy(s,"Введите второе вещественное число:\n");
                    consoleWindow->print(s);
                    consoleWindow->getstr(s2);
                    val1 = atof(s1);
                    val2 = atof(s2);
                    val3 = val1 + val2;
                    sprintf(s3,"%f",val3);
                    sprintf(s4,"Сумма введённых двух чисел равна: ");
                    strcat(s4,s3);
                    consoleWindow->print(s4);
                    strcpy(s,"Будете ещё работать (y/n)?\n");
                    consoleWindow->print(s);
                    consoleWIndow->getstr(sanswer);
                    if (((strcmp(sanswer,"y")==0)||(strcmp(sanswer,"Y")==0)))
                        goto metka;
                    consoleWindow->close();
                }
              1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
              0 пользователей:


              Рейтинг@Mail.ru
              [ Script execution time: 0,0680 ]   [ 15 queries used ]   [ Generated: 5.07.25, 20:34 GMT ]