Reputation: 3
I'm trying to make a script that will open an input box on key command; you type something into it, it closes and returns the text to Python. So far, everything is working well, except in Python when my key combination is met, I cant figure out a way to show the QML GUI. I saw some working examples in C++, but haven't seem to find any for Python.
main.py:
import os
from pathlib import Path
import sys
from PySide6.QtCore import QCoreApplication, Qt, QUrl, QObject, Signal, Slot
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine
from pynput.keyboard import Key, Listener, KeyCode
#is call qml function from python to show window.
CURRENT_DIRECTORY = Path(__file__).resolve().parent
COMBINATION = {Key.shift_r, Key.enter}
current = set()
#KEYBOARD LISTENER
class KeyMonitor(QObject):
keyPressed = Signal(KeyCode)
def __init__(self, parent=None):
super().__init__(parent)
self.listener = Listener(on_press=self.on_press, on_release=self.on_release)
def on_press(self, key):
if key in COMBINATION:
current.add(key)
if all(k in current for k in COMBINATION):
print('All modifiers active!')
#I WANT TO CALL QML FUNCTION OPEN() RIGHT HERE.
def on_release(self, key):
try:
current.remove(key)
except KeyError:
pass
def stop_monitoring(self):
self.listener.stop()
def start_monitoring(self):
self.listener.start()
#SLOT STUFF
class MainBackend(QObject):
def __init__(self):
QObject.__init__(self)
signalPrintTxtEmitter = Signal(bool)
@Slot()
def printTxt(self):
self.signalPrintTxtEmitter.emit(True)
print('Hello from Python!')
input_Text = Signal(str)
@Slot(str)
def sendToPython(self, text):
currentText=text
print("Python says you typed in:" + " " + currentText)
#RUNNING QML
def main():
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
main = MainBackend()
engine.rootContext().setContextProperty("backend", main)
filename = os.fspath(CURRENT_DIRECTORY / "QML" / "main.qml")
url = QUrl.fromLocalFile(filename)
def handle_object_created(obj, obj_url):
if obj is None and url == obj_url:
QCoreApplication.exit(-1)
engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
engine.load(url)
sys.exit(app.exec())
if __name__ == "__main__":
monitor = KeyMonitor()
#monitor.keyPressed.connect(print)
monitor.start_monitoring()
main()
main.qml:
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.15
import QtQuick.Window 2.15
ApplicationWindow{
id: root
title: qsTr("Hello, I'm main.qml!")
visible: true
width: 400
height: 580
Material.theme: Material.Dark
Material.accent: Material.LightBlue
//Component.onCompleted: functions.close()
TextField {
id: input_Box
width: 160
placeholderText: qsTr("Enter Here")
anchors.centerIn: parent
focus: true
Keys.onPressed: {
if (event.key == Qt.Key_Return) {
//backend.printTxt()
backend.sendToPython(input_Box.text)
functions.close()
}
}
}
Button{
id: button
focus: true
text: qsTr("Click me!")
onClicked: functions.openQml()
}
QtObject {
id: functions
function close() {
root.hide()
}
function open() {
root.show()
}
}
Connections {
target: backend
function onSignalPrintTxtEmitter(boolValue){
return
}
function onSignalsendToPythonEmitter(str){
return
}
}
}
Upvotes: 0
Views: 1136
Reputation: 244132
Instead of trying to call a QML function from Python, you should issue a signal from Python and call the QML function to the associated slot. Here is an example of how you can do that:
class KeyMonitor(QObject):
keyPressed = Signal(KeyCode)
foo = Signal()
# ...
def on_press(self, key):
if key in COMBINATION:
current.add(key)
if all(k in current for k in COMBINATION):
print("All modifiers active!")
self.foo.emit()
main = MainBackend()
monitor = KeyMonitor()
QTimer.singleShot(1000, monitor.foo.emit)
monitor.start_monitoring()
engine.rootContext().setContextProperty("backend", main)
engine.rootContext().setContextProperty("monitor", monitor)
Connections{
target: monitor
function onFoo(){
console.log("Foo")
functions.open()
}
}
Upvotes: 1