1

How to modify the size of the virtual keyboard? And as far as possible, the drag and drop option is allowed. Also, since there is no escape key, I cannot get the virtual keyboard once it is displayed. Can you do something about it? My application runs on a kiosk-type terminal, with a touch screen, no mouse, and no physical keyboard. I am using Python 3.8.10 on ubuntu 20.04.3 LTS. Here is a part of my code...

import sys
import os
os.environ["QT_IM_MODULE"] = "qtvirtualkeyboard"
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtWidgets import *
from PySide6.QtGui import *
from PySide6.QtCore import *

class MainApp(QMainWindow):
    def __init__(self, parent=None, *args):
        super(MainApp, self).__init__(parent)
        
        self.setFixedSize(1600, 1000)      
       
        self.button = QPushButton(self)        
        self.button.setGeometry(20, 20, 140, 30)     
        self.button.setText("Show Dialog")
        self.button.clicked.connect(self.show_dialog)
        
    def show_dialog(self):
        self.dialog = Dialog()
        self.dialog.show()

class Dialog(QDialog):
    
    def __init__(self):
        QDialog.__init__(self)

        self.setFixedSize(600, 550)
        self.move(500, 200)      
        self.setWindowFlags((Qt.FramelessWindowHint))
        self.setStyleSheet("background-color: rgba(57, 239, 255, 100)")

        self.label = QLabel(self)
        self.label.setGeometry(0, 0, 600, 30)
        self.label.setText("Login")
        self.label.setAlignment(Qt.AlignCenter)

        self.lbl_dni = QLabel(self)
        self.lbl_dni.setGeometry(100, 150, 80, 30)
        self.lbl_dni.setText("DNI")
        self.lbl_dni.setObjectName("lbl_dni")
        self.lbl_dni.setAlignment(Qt.AlignCenter)

        self.lnet_dni = QLineEdit(self)
        self.lnet_dni.setGeometry(250, 150, 100, 30)
        self.lnet_dni.setObjectName("lnet_dni")
        self.lnet_dni.setMaxLength(8)
        self.lnet_dni.setAlignment(Qt.AlignCenter)

        self.lbl_pass = QLabel(self)
        self.lbl_pass.setGeometry(100, 300, 80, 30)
        self.lbl_pass.setText("Password")
        self.lbl_pass.setObjectName("lbl_pass")
        self.lbl_pass.setAlignment(Qt.AlignCenter)
      
        self.lnet_pass = QLineEdit(self)
        self.lnet_pass.setGeometry(225, 300, 160, 30)
        self.lnet_pass.setObjectName("lnet_pass")
        self.lnet_pass.setMaxLength(20)
        self.lnet_pass.setEchoMode(QtWidgets.QLineEdit.Password)
        self.lnet_pass.setAlignment(Qt.AlignCenter)

        self.btn_login = QPushButton(self)
        self.btn_login.setGeometry(150, 450, 100, 24)
        self.btn_login.setObjectName("btn_login")
        self.btn_login.setText("Login")
        self.btn_login.clicked.connect(self.login)      
      
        self.btn_cancel = QPushButton(self)
        self.btn_cancel.setGeometry(350, 450, 80, 25)
        self.btn_cancel.setObjectName("btn_cancel")
        self.btn_cancel.setText("Cancel")
        self.btn_cancel.clicked.connect(self.cancel)
            
    def login(self):
        print('do something')

    def cancel(self):             
        self.close()
        
if __name__ == "__main__":        
    app = QApplication(sys.argv)
    window = MainApp()
    window.show()
    app.exec()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
dangusting
  • 11
  • 3

1 Answers1

1

You can hide or show the virtual keyboard using the QInputMethod.

On the other hand, to move it is not trivial since the keyboard has a special construction (and that can vary since it is part of the private api), a window is created that covers the entire screen, the keyboard is drawn using QML and a mask to only show what I draw, that is, that the position of the window that contains the keyboard is always 0x0. So for example if you want to move to the top you have to subtract the vertical position of the visual keyboard.

In the next demo it will hide and show the keyboard every second, and it will also move to the top and bottom every second.

import os
import sys

from PySide6.QtCore import QRect, QTimer, QObject, QPoint
from PySide6.QtGui import QGuiApplication, QRegion
from PySide6.QtWidgets import QApplication, QLineEdit, QVBoxLayout, QWidget


class KeyboardManager:
    def __init__(self):
        self._keyboard_window = None
        self.input_method.visibleChanged.connect(self._handle_visible_changed)

    @property
    def input_method(self):
        input_method = QGuiApplication.inputMethod()
        if input_method is None:
            raise RuntimeError("QGuiApplication.inputMethod() is None")
        return input_method

    @property
    def keyboard_window(self):
        return self._keyboard_window

    def _handle_visible_changed(self):
        for w in QGuiApplication.allWindows():
            if w.metaObject().className() == "QtVirtualKeyboard::InputView":
                if self._keyboard_window != w:
                    if self._keyboard_window is not None:
                        self._keyboard_window.disconnect(self._handle_destroyed)
                    w.destroyed.connect(self._handle_destroyed)
                    self._keyboard_window = w
                return
        self._keyboard_window = None

    def _handle_destroyed(self):
        self._keyboard_window = None


def main():
    os.environ["QT_IM_MODULE"] = "qtvirtualkeyboard"
    app = QApplication(sys.argv)

    keyboard_manager = KeyboardManager()

    w = QWidget()
    le = QLineEdit()
    lay = QVBoxLayout(w)
    lay.addWidget(le)
    lay.addStretch()
    w.show()

    def handle_timeout1():
        if keyboard_manager.keyboard_window is None:
            return
        if keyboard_manager.keyboard_window.y() < 0:
            keyboard_manager.keyboard_window.setPosition(0, 0)
        else:
            keyboard = keyboard_manager.keyboard_window.findChild(QObject, "keyboard")
            y = keyboard.property("y")
            keyboard_manager.keyboard_window.setPosition(0, -y)

    def handle_timeout2():
        if keyboard_manager.input_method is None:
            return
        keyboard_manager.input_method.setVisible(
            not keyboard_manager.input_method.isVisible()
        )
        print(f"visibility: {keyboard_manager.input_method.isVisible()}")

    timer1 = QTimer(interval=1000, timeout=handle_timeout1)
    timer1.start()

    timer2 = QTimer(interval=1000, timeout=handle_timeout2)
    QTimer.singleShot(500, timer2.start)

    sys.exit(app.exec())


if __name__ == "__main__":
    main()

If you want to change the size you won't be able to, a possible option is to apply a mask, a requirement similar to the one you point out, I implemented it in this answer.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241