Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for WebAssembly
  4. System Default keyboard hides QLineEdit / Emoji Picker Issue
Forum Updated to NodeBB v4.3 + New Features

System Default keyboard hides QLineEdit / Emoji Picker Issue

Scheduled Pinned Locked Moved Unsolved Qt for WebAssembly
6 Posts 2 Posters 558 Views 2 Watching
  • 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
    SlayH
    wrote on last edited by
    #1

    Hello All.

    I have written a qt C++ desktop application which I have port on QWebAssembly. The problem is, when there is a focus on the QLineEdit and the user has to type something, the system default keyboard hides the QLineEdit.

    In my current implementation, I had to use a class (DisplayWdget) which copy the QLineEdit's field and display it at the top of the window which isn't that good.

    class DisplayWidget : public QWidget
    {
        Q_OBJECT
    private:
        QLineEdit *_lineEdit{};
    
    public:
        explicit DisplayWidget(QWidget *parent = nullptr) : QWidget(parent)
        {
            QHBoxLayout *layout = new QHBoxLayout(this);
    
            _lineEdit = new QLineEdit(this);
            layout->addWidget(_lineEdit);
    
            setLayout(layout);
        }
    
    public slots:
        void setText(const QString &text)
        {
            _lineEdit->setText(text);
            _lineEdit->setCursorPosition(_lineEdit->text().length());
        }
    };
    

    And below is the window:

    void client_chat_window::set_up_window()
    {
        QWidget *central_widget = new QWidget();
        setCentralWidget(central_widget);
    
        ask_microphone_permission();
    
    #if !defined(EMSCRIPTEN)
        _dir.mkdir(_destinator_name);
        _dir.setPath("./" + _destinator_name);
    #endif
    
        QPushButton *member_list = new QPushButton("Server's Conversation", this);
        member_list->setStyleSheet("border: none;");
        connect(member_list, &QPushButton::clicked, this, [=]()
                {
                    if (_group_name.isEmpty())
                    {
    #if !defined(EMSCRIPTEN)
                        folder();
    #endif
                    }
                    else
                    {
                        ListDialog *members = new ListDialog(_group_members, "Group Members", this);
    
                        connect(members, &QDialog::accepted, this, [=]()
                                {   
                                    QString name = members->name_selected().first();
                                    emit item_clicked(name);
    
                                    members->deleteLater(); });
    
                        members->open();
                    } });
    
        connect(this, &client_chat_window::update_button_file, this, [=]()
                { member_list->setText(QString("%1's Conversation").arg(_window_name)); });
    
        _list = new Swipeable_list_widget(this, this);
        _list->setItemDelegate(new SeparatorDelegate(_list));
        _list->setSelectionMode(QAbstractItemView::NoSelection);
    
        _insert_message = new CustomLineEdit(this);
        _insert_message->setPlaceholderText("Insert New Message");
        connect(_insert_message, &CustomLineEdit::textChanged, this, [=]()
                { (_group_name.isEmpty()) ? _client->send_is_typing(my_name(), _destinator) : _client->send_group_is_typing(_group_ID, _group_name, my_name()); });
    
        _emoji_button = new QPushButton("😀", this);
        _emoji_button->setFixedSize(30, _insert_message->height());
        _emoji_button->setFont(_emoji_font);
    
        EmojiPicker *emojiPicker = new EmojiPicker(this);
        emojiPicker->hide();
    
        connect(_emoji_button, &QPushButton::clicked, emojiPicker, [emojiPicker]()
                { emojiPicker->setVisible(!emojiPicker->isVisible()); });
    
        connect(emojiPicker, &EmojiPicker::emoji_selected, _insert_message, [=](const QString &emoji)
                { _insert_message->insert(emoji); });
    
    #ifdef __EMSCRIPTEN__
        _display_widget = new DisplayWidget(this);
        _display_widget->hide();
    
        connect(_insert_message, &CustomLineEdit::textChanged, _display_widget, &DisplayWidget::setText);
        connect(_insert_message, &CustomLineEdit::focusGained, _display_widget, &QWidget::show);
        connect(_insert_message, &CustomLineEdit::focusLost, _display_widget, &QWidget::hide);
    
        int font_ID = QFontDatabase::addApplicationFont(":/emoji/NotoColorEmoji.ttf");
        if (font_ID == -1)
            qWarning("Failed to load emoji font.");
        else
        {
            QStringList font_families = QFontDatabase::applicationFontFamilies(font_ID);
            if (!font_families.isEmpty())
                _emoji_font = QFont(font_families.at(0));
        }
    
        _insert_message->setFont(_emoji_font);
        _display_widget->setFont(_emoji_font);
        _emoji_button->setFont(_emoji_font);
    #endif
    
        QPixmap image_send(":/images/send_icon.png");
    
        _send_button = new QPushButton(this);
        _send_button->setIcon(image_send);
        _send_button->setIconSize(QSize(30, 30));
        _send_button->setFixedSize(30, 30);
        _send_button->setStyleSheet("border: none");
        connect(_send_button, &QPushButton::clicked, this, &client_chat_window::send_message);
    
        _send_file_button = new QPushButton("...", this);
        connect(_send_file_button, &QPushButton::clicked, this, &client_chat_window::send_file);
    
        _hbox = new QHBoxLayout();
        _hbox->addWidget(_emoji_button);
        _hbox->addWidget(_insert_message);
        _hbox->addWidget(_send_button);
        _hbox->addWidget(_send_file_button);
    
        _buttons = new QHBoxLayout();
        _buttons->addWidget(member_list);
    
        QVBoxLayout *VBOX = new QVBoxLayout(central_widget);
    #ifdef __EMSCRIPTEN__
        VBOX->addWidget(_display_widget);
    #endif
        VBOX->addLayout(_buttons);
        VBOX->addWidget(_list);
        VBOX->addLayout(_hbox);
        VBOX->addWidget(emojiPicker);
    }
    

    Is there any way to make the QLineEdit always visible when there is a focus on it ?
    I know in javascript the window is automatically adjusted and the input field is placed right above the keyboard.

    I also would like to know how to enable emoji picker in WebAssembly cause I had to implement a whole class to support it and list my own emojis. I had changed the font to Noto Color to support them otherwise they would appear as squares.

    1 Reply Last reply
    0
    • S Offline
      S Offline
      SlayH
      wrote on last edited by
      #2

      I’m facing the same problem when using QML. When the app is run on a Mobile and the virtual keyboard appears, it’s hides some contents.

      import QtQuick;
      import QtQuick.Controls;
      import QtQuick.Window;
      
      Rectangle 
      {
          id: root;
      
          Image 
          {
              id: welcomeImage;
      
              mipmap: true;
              fillMode: Image.PreserveAspectFit;
      
              anchors.top: parent.top;
              anchors.topMargin: 10;
              anchors.horizontalCenter: parent.horizontalCenter;
      
              width: 300;
              height: 300;
      
              source: "qrc:/QML_modules/ClientApp/icons/hi_icon.png";
          }
      
          Text 
          {
              id: textWelcome;
      
              text: "GET ON BOARD,";
              wrapMode: Text.WrapAtWordBoundaryOrAnywhere;
              font.bold: true;
              font.pixelSize: 30;
      
              leftPadding: 15;
              rightPadding: 15;
      
              anchors.top: welcomeImage.bottom;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      
          Text 
          {
              id: textAboutUs;
              text: "Create your Profile and Start the Journey with US";
      
              wrapMode: Text.WrapAtWordBoundaryOrAnywhere;
              font.bold: true;
              font.pixelSize: 10;
      
              leftPadding: 15;
              rightPadding: 15;
      
              anchors.top: textWelcome.bottom;
              anchors.topMargin: 5;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      
          InputField 
          {
              id: signUpFirstName;
              image1Source: "qrc:/QML_modules/ClientApp/icons/name_icon.png";
      
              echoMode: 0;
              placeHolder: "First Name";
              width: parent.width * 0.6;
      
              anchors.top: textAboutUs.bottom;
              anchors.topMargin: 10;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      
          InputField 
          {
              id: signUpLastName;
              image1Source: "qrc:/QML_modules/ClientApp/icons/name_icon.png";
      
              echoMode: 0;
              placeHolder: "Last Name";
              width: parent.width * 0.6;
      
              anchors.top: signUpFirstName.bottom;
              anchors.topMargin: 10;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      
          InputField 
          {
              id: signUpPhoneNumber;
              image1Source: "qrc:/QML_modules/ClientApp/icons/phone_icon.png";
      
              echoMode: 0;
              placeHolder: "Phone Number";
              width: parent.width * 0.6;
      
              anchors.top: signUpLastName.bottom;
              anchors.topMargin: 10;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      
          InputField 
          {
              id: signUpPassword;
              image1Source: "qrc:/QML_modules/ClientApp/icons/hide_icon.png";
              image2Source: "qrc:/QML_modules/ClientApp/icons/see_icon.png";
      
              echoMode: 2;
              placeHolder: "Password";
              width: parent.width * 0.6;
      
              anchors.top: signUpPhoneNumber.bottom;
              anchors.topMargin: 10;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      
          InputField 
          {
              id: signUpPasswordConfirmation;
              image1Source: "qrc:/QML_modules/ClientApp/icons/hide_icon.png";
              image2Source: "qrc:/QML_modules/ClientApp/icons/see_icon.png";
      
              echoMode: 2;
              placeHolder: "Password Confirmation";
              width: parent.width * 0.6;
      
              anchors.top: signUpPassword.bottom;
              anchors.topMargin: 10;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      
          Rectangle 
          {
              id: signUpButton;
              color: "black";
      
              radius: 5;
              width: parent.width * 0.6;
              height: 50;
      
              Text 
              {
                  text: "SIGN UP";
                  color: "white";
      
                  anchors.centerIn: parent;
              }
      
              MouseArea 
              {
                  anchors.fill: parent;
      
                  onPressed: parent.color = "#ed7bb4";
                  onReleased: parent.color = "black";
      
      
                  // FIXME: handle click button correctly
                  onClicked: console.log("Sign Up Button Click");
              }
      
              anchors.top: signUpPasswordConfirmation.bottom;
              anchors.topMargin: 20;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
       
          Row 
          {
              spacing: 10;
      
              Text 
              {
                  id: question;
                  text: "Already have an Account?";
              }
      
              Rectangle 
              {
                  id: signUp;
                  color: "transparent";
      
                  width: question.width * .5;
                  height: 20;
      
                  Text 
                  {
                      id: signUpText;
                      text: "LOGIN";
                      color: "#DE02B5";
                      font.bold: true;
                      leftPadding: 5;
      
                      anchors.centerIn: parent;
                  }
      
                  MouseArea 
                  {
                      anchors.fill: parent;
      
                      onClicked: stackView.replace(loginWindow, StackView.PopTransition);
                  }
              }
      
              anchors.top: signUpButton.bottom;
              anchors.topMargin: 20;
              anchors.horizontalCenter: parent.horizontalCenter;
          }
      }
      

      Here the InputField module implementation:

      import QtQuick;
      import QtQuick.Controls;
      import QtQuick.Window;
      import QtQuick.Controls.Basic;
      
      Rectangle
      {
          id: root;
      
          property alias inputField: textInput.text;
          required property string image1Source;
          property string image2Source;
          required property string placeHolder;
          property alias echoMode: textInput.echoMode;
      
          signal accepted(string value);
      
          height: 50;
      
          radius: 20;
          border.color: textInput.focus ? "#a10e7a" : "black";
          border.width: textInput.focus ? 4 : 2;
      
          opacity: enabled ? 1 : 0.6;
      
          TextField
          {
              id: textInput;
      
              anchors.fill: parent;
              anchors.margins: 2;
      
              font.pixelSize: 14;
      
              color: "black";
      
              placeholderText: root.placeHolder;
              placeholderTextColor: "black";
      
              leftPadding: 30;
              verticalAlignment: TextField.AlignVCenter;
      
              onAccepted: root.accepted(text);
      
              background: Rectangle 
              {
                  radius: root.radius - 2;
                  implicitWidth: 200;
                  implicitHeight: 40;
                  color: "#e6e8e8";
                  border.color: "transparent";
              }
      
              Image
              {
                  id: toggleImage;
                  anchors.left: parent.left;
                  anchors.leftMargin: 5;
                  anchors.verticalCenter: parent.verticalCenter;
      
                  width: 20;
                  height: 20;
      
                  mipmap: true;
                  source: root.image1Source;
      
                  MouseArea
                  {
                      anchors.fill: parent;
      
                      onClicked: 
                      {
                          textInput.echoMode = textInput.echoMode === TextInput.Normal ? TextInput.Password : TextInput.Normal;
                          
                          toggleImage.source = textInput.echoMode === TextInput.Normal ? root.image2Source : root.image1Source;
                      }
                  }
              }
          }
          
          Component.onCompleted: textInput.focus = false;
      }
      
      1 Reply Last reply
      0
      • Axel SpoerlA Offline
        Axel SpoerlA Offline
        Axel Spoerl
        Moderators
        wrote on last edited by
        #3

        As written on the mailing list:

        • Which Qt Version are you using?
        • Which (mobile) platform is this related to?
        • Try a focus proxy on widgets, focus scope in QML.

        Please boil the code down to a minimal compilable reproducer.

        Software Engineer
        The Qt Company, Oslo

        1 Reply Last reply
        0
        • S Offline
          S Offline
          SlayH
          wrote on last edited by SlayH
          #4

          I am using Qt 6.7.2

          The problem isn't related to any mobile platform.
          It is just that I had built the app to WebAssembly and deploy it using github pages.
          When I am using it on my a PC there is no problem but when I try it using a Phone, the phone's native virtual keyboard hides the InputField which has the focus on it.

          I would like to know how I can automatically scroll the InputField which has gained focus to the middle of the screen i.e above the virtual keyboard so it is always visible.

          IMG_7126.PNG
          This is a screenshot before clicking on the password input field and the one below is after I click on it.
          IMG_7127.PNG

          If I am using a PC there is no problem cause there is not virtual keyboard.

          1 Reply Last reply
          0
          • Axel SpoerlA Offline
            Axel SpoerlA Offline
            Axel Spoerl
            Moderators
            wrote on last edited by
            #5

            As said: Please provide a minimal reproducer.
            I don't have any issue on mobile devices, if I just use a TextField.
            So the problem seems to be caused by the custom type InputField. My suspicion is that the mouse area within the type causes the focus. You'll find that out by creating that reproducer.

            Software Engineer
            The Qt Company, Oslo

            1 Reply Last reply
            0
            • S Offline
              S Offline
              SlayH
              wrote on last edited by
              #6

              Okay I will try it out.

              Thanks

              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