Transport QML Image via Bridge - qt

I have at the moment a simple PySide6 app which uses qml for image capturing. I want to transport the image to our app but cannot figure out how. I am not sure, if saving QML image is an attempt in the right direction.
My PySide App
import sys
from pathlib import Path
from PySide6.QtCore import QObject, Slot
from PySide6.QtGui import QGuiApplication, QImage
from PySide6.QtQml import QQmlApplicationEngine, QmlElement
QML_IMPORT_NAME = "io.qt.textproperties"
QML_IMPORT_MAJOR_VERSION = 1
#QmlElement
class Bridge(QObject):
#Slot(QImage)
def capture(self, preview):
# Do something with the preview
print(type(preview))
if __name__ == "__main__":
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
# Get the path of the current directory, and then add the name
# of the QML file, to load it.
qml_file = Path(__file__).parent / "simpleCam.qml"
engine.load(qml_file)
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec())
MY QML File
import QtQuick
import QtQuick.Controls
import QtMultimedia
import io.qt.textproperties
ApplicationWindow {
id: mainFrame
width: 640
height: 480
visible: true
title: qsTr("Cam Test")
Bridge {
id: bridge
}
Rectangle {
width: 640
height: 400
MediaDevices {
id: mediaDevices
}
CaptureSession {
imageCapture: ImageCapture {
id: capture
}
camera: Camera {
id: camera
}
videoOutput: output
}
VideoOutput {
id: output
anchors.fill: parent
}
Button {
id: startCamButton
text: "Start Cam"
anchors.top: output.bottom
anchors.left: output.left
onClicked: {
camera.start()
camImage.opacity = 0
}
}
Button {
id: takePicButton
text: "take pic"
anchors.top: output.bottom
anchors.left: startCamButton.right
onClicked: {
capture.capture()
camImage.opacity = 1
}
}
Image {
id: camImage
anchors.fill: parent
source: capture.preview
}
}
}
The Result
What is missing?
In the Button with id: takePicButton I want to transport the image to the PySide6 Bridge. If I add to theonClicked Signal bridge.capture(capture.preview) I got the Error:
TypeError: Passing incompatible arguments to C++ functions from JavaScript is not allowed.`
How can I solve this problem?

You should use the imageCaptured signal.
Change:
imageCapture: ImageCapture {
id: capture
}
To:
imageCapture: ImageCapture {
id: capture
onImageCaptured: function(req_id, preview){bridge.capture(req_id, preview)}
}
And change in main.py:
#Slot(QImage)
def capture(self, preview):
# Do something with the preview
print(type(preview))
To:
#Slot(int, QImage)
def capture(self,req_id, preview):
print(req_id)
print(type(preview))
Working example here.
You might want to look at this answer for other use cases.

Related

How to push different view to stack view using a function in qml main file

working on an application using qml for the interface. I have a stack view in the main qml file which will push the qml file which will be a page to the stack view. Because there are multiple pages and buttons in these pages that when clicked may push a different page onto the stack view, I created a function in the main qml file which i will call from the pages when buttons are clicke. The pages folder which contain many different pages is a subdirectory of main.qml folder. The functionis supposed to push the pages unto the stack view. However, on click of the button, the satck view does not push the new page.
This is the code below
main qml file
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import "pages"
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
property url source: ""
function changeView(source){
stackView.push(Qt.resolvedUrl(source))
}
Rectangle {
id: rectangle
color: "#391199"
anchors.fill: parent
StackView {
id: stackView
anchors.fill: parent
initialItem: Qt.resolvedUrl("pages/homepage.qml")
}
}
}
/*##^##
Designer {
D{i:0;formeditorZoom:0.75}
}
##^##*/
homePage.qml
import QtQuick 2.0
import QtQuick.Controls 2.15
import "qrc:../main.qml" as Main
Item {
Rectangle {
id: rectangle
color: "#08630f"
anchors.fill: parent
Button {
id: button
x: 478
y: 255
text: qsTr("Change ")
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 10
anchors.bottomMargin: 10
onClicked: {
source = "pages/nextPage.qml"
Main.changeView(source)
}
}
}
}
nextPage.qml
import QtQuick 2.0
import QtQuick.Controls 2.15
import "../main.qml" as Main
Item {
Rectangle {
id: rectangle
color: "#08404b"
anchors.fill: parent
Button {
id: button
x: 478
y: 255
text: qsTr("Change ")
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.rightMargin: 10
anchors.bottomMargin: 10
onClicked: {
Main.changeView("pages/homePage.qml")
}
}
}
}
I suspect the problem is coming from the calling of the function but i have a little expertise in qml. I get this error: Property 'changeView' of object [object Object] is not a function
You will want to call the changeView function on the actual main window, not on the import.
This involves a bit of "magic", you can give the main Window an id, which will be available in all the children of it (so, magic because if looking at a single page file, you can wonder what that id is doing there). So, make sure to pick a wise name which won't collide with other id (i.e. root would be quite bad)
//main.qml
Window {
id: main_window
function changeView(source) { ... }
}
//homePage.qml
Item {
...
Button {
...
onClicked: main_window.changeView("pages/nextPage.qml")
}
}

Interaction between two QML files

I want to use some qml file(main.qml) but before that I need to get some authentication info from user(login, pass). So I want to do this in the second window(login.qml). I saw Qt.createComponent for opening second qml file, but I can't get any information from this type of window.
So how can I use some information from the second window in the first window?
Or how can I dynamically load these items(main.qml, login.qml) in the parent qml file?
So how can I use some information from the second window in the first
window?
This is just one way of doing it:
main.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
ApplicationWindow {
width: 400
height: 400
visible: true
ColumnLayout {
id: logItems
height: 200
Button {
id: loginButton
onClicked: loginForm.visible = true
text: "Log in"
}
Login {
anchors.top: loginButton.bottom
id: loginForm
visible: false
onLoginInfo: {
logInfo.text = "User:" + user + " password: " + password
}
}
}
Text {
id: logInfo
anchors.top : logItems.bottom
}
}
Login.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
Item {
signal loginInfo(string user, string password)
ColumnLayout {
RowLayout {
TextField {
id: user
}
TextField {
id: password
}
}
Button {
text: "Submit"
onClicked: loginInfo(user.text, password.text)
}
}
}
How can I dynamically load QML items from separate files/resources in
another QML file?
Qt.CreateComponent allows you to use JavaScript to dynamically create and use QML code from other files.

Take snapshot of video in Qt Multimedia

Is it possible to take snapshot of a video in Qt Multimedia? how?
It depends on the platform but what you can probably do is to use a QMediaPlayer, set a subclassed video surface via setVideoOutput, and get the frame data from the QVideoFrame passed in the present method. You'll then have to deal with the frame format and to map if those are not in CPU memory.
However, depending on your need, I would use ffmpeg/libav to get a frame from a specific position.
Try this (Documentation here: http://doc.qt.io/qt-5/qml-qtquick-item.html#grabToImage-method)
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtMultimedia 5.0
Window {
id: mainWindow
visible: true
width: 480
height: 800
MediaPlayer {
id: player
source: "file:///location/of/some/video.mp4"
autoPlay: false
}
ColumnLayout {
anchors.fill: parent
VideoOutput {
id: output
source: player
Layout.fillHeight: true
Layout.fillWidth: true
}
Row {
id: buttonsRow
height: 100
spacing: 20
anchors.horizontalCenter: parent.horizontalCenter
Layout.margins: 10
Button {
id: playPauseButton
text: player.playbackState === MediaPlayer.PlayingState ? "Pause" : "Play"
onClicked: {
var playing = player.playbackState === MediaPlayer.PlayingState;
playing ? player.pause() : player.play();
}
}
Button {
text: "Snapshot"
onClicked: {
output.grabToImage(function(image) {
console.log("Called...", arguments)
image.saveToFile("screen.png"); // save happens here
});
}
}
}
}
}

QML Audio stops 400 milliseconds before the end

Can someone, please, explain this odd behavior of my application.
I am using Qt 5.1.0 and msvc2010.
This is my code:
import QtQuick 2.1
import QtQuick.Window 2.1
import QtMultimedia 5.0
Window {
visible: true
width: 360
height: 360
MouseArea {
anchors.fill: parent
onClicked: {
playAudio.play()
}
}
Audio {
id: playAudio
source: "zvuky/1.mp3"
}
}
Your code doesn't have any error. Maybe it's due to the mp3 file and Qt is not able to load it.
Did you try to convert the mp3 file to wav? Sometimes it's better to use SoundEffect instead of Audio.
You could also try the MediaPlayer type.
Here you have an example. It's in GitHub where you can download the audio clips.
import QtQuick 2.5
import QtQuick.Window 2.2
import QtMultimedia 5.4
Window {
visible: true
width: 360
height: 360
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button == Qt.RightButton)
playMP3.play()
else
playWAV.play()
}
}
SoundEffect {
id: playWAV
source: "res/kid_giggle.wav"
onPlayingChanged: {
console.log("SoundEffect - onPlayingChanged - category: " + category)
}
}
MediaPlayer {
id: playMP3
source: "res/kid_giggle.mp3"
onPlaying: {
console.log("MediaPlayer - onPlaying - duration: " + duration)
}
}
}
Finelly I found solution.
Everything works perfect with Audio element when I used Qt 5.2.1(msvc2012)

Qt Expected Character ')' Error

I am getting the following error:
Debugging starts QML debugging is enabled. Only use this in a safe
environment. QML Debugger: Waiting for connection on port 55186...
QQmlApplicationEngine failed to load component qrc:/main.qml:23
Expected token `)'
Line 23
QFile, file("C://new.txt");
The Code
#include <QIODevice>
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQml 2.2
ApplicationWindow {
title: qsTr("File Editor")
width: 640
height: 480
visible: true
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: {
var message = ("Hello World!");
QFile, file("C://new.txt");
file.open(QIODevice::ReadWrite);
QTextStream out(&file);
out << %message%;
}
}
MenuItem {
text: qsTr("E&xit")
onTriggered: Qt.quit();
}
}
}
MainForm {
anchors.fill: parent
button1.onClicked: messageDialog.show(qsTr("Button 1 pressed"))
button2.onClicked: messageDialog.show(qsTr("Button 2 pressed"))
button3.onClicked: messageDialog.show(qsTr("Button 3 pressed"))
}
MessageDialog {
id: messageDialog
title: qsTr("May I have your attention, please?")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}
As stated by Simon Warta and BaCaRoZzo in the comments, you cannot use C++ in QML. You need to use Javascript and create your own custom type for handling file input and output.
Please see this answer.

Resources