I have qml camera widget in camera.qml. the qml component is loaded from a Qt widget "WidgetCamera" that is placed on a stack widget in the background. The widget starts the camera device already at creation.
How to make the camera start only when the widget is shown in the foreground. And vice versa, how release the camera when the widget goes to the background?
camera.qml
Item {
width: 640
height: 360
Camera {
id: camera
}
VideoOutput {
source: camera
anchors.fill: parent
}
}
widgetCamera.h
class WidgetCamera : public QWidget
{
Q_OBJECT
public:
WidgetCamera() {
QQuickWidget *qw= new QQuickWidget;
qw->setSource(QUrl("qrc:///camera.qml"));
// ...
}
}
mainwindow.h
class MainWindow : QMainWindow
{
Q_OBJECT
public:
MainWindow() {
QStackedWidget *sw = new QStackedWidget;
sw->addWidget(new QWidget());
sw->addWidget(new WidgetCamera());
// ...
}
}
QML camera type has start(), stop() methods accessible directly inside QML. But to be able to turn the camera on/off at will from c++ side, you should first introduce it as a member in your MainWindow class, e.g. like this:
#include "widgetCamera.h"
class MainWindow : QMainWindow
{
Q_OBJECT
private:
WidgetCamera* _cameraWidget;
public:
MainWindow() {
QStackedWidget *sw = new QStackedWidget;
sw->addWidget(new QWidget());
_cameraWidget = new WidgetCamera();
sw->addWidget(_cameraWidget);
// PS: Make sure you free your instances correctly, too
// ...
}
}
Now, in your WidgetCamera class, you should also introduce a member variable to access the actual QML widget faster, similar to the above. Let's stick with the "qw" you already gave it.
Then, make sure you give objectNames to all QML children that you want to access (in this case, we want the camera), like this:
Item {
width: 640
height: 360
Camera {
id: camera
objectName: "theCamera"
}
VideoOutput {
source: camera
anchors.fill: parent
}
}
Once you have that, you need a function to enable/disable the capturing of the camera, which could be done like this:
void WidgetCamera::disableCapture() {
QObject* qmlCamera = qw->findChild<QObject*>("theCamera");
QCamera* camera = qvariant_cast<QCamera*>(qmlCamera->property("mediaObject"));
camera->stop();
}
Now, obviously, a lot of this could be improved and optimized (like making the actual c++ QCamera a member of WidgetCamera, etc.), but this should get you started.
As to when you want to call that function to enable/disable the camera, that is completely up to you.
Related
Here's my situation. I'm trying to combine qml with a mostly widget based UI. To do this, I'm using QQuickView with QWidget::createWindowContainer. I can't use QQuickWidget, because I need to convert the window into a native window, and QQuickWidget doesn't like that. But back to the issue.
My problem is that the first time the view is displayed, it takes like half a second to load causing a very obvious flicker. After that I can hide/show the view all I want, it displays immediately. It's only the first time the qml loads. And I'm fairly certain it's the loading of the qml that causes the issue. Because I have two different QQuickViews that get the same qml as their source. But after any one of them loads once, the other has no issues displaying instantly.
I tried to call show() on view early to get it to load in time. But this causes the qml to appear for a brief moment before any of the widgets get displayed.
Has anyone encountered a similar issue? How can I get the QQuickView to behave.
Edit: I'm using Qt 5.4.2, and I can't update to a newer version due to various reasons.
I was going to say that you can use the same approach as in this answer, but it seems that even that is too early to being loading the QML. It's hacky, but the only other thing I can think of is using a very short Timer:
main.cpp:
#include <QtWidgets>
#include <QtQuick>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0) :
QMainWindow(parent)
{
QQuickView *view = new QQuickView();
QWidget *container = QWidget::createWindowContainer(view, this);
container->setFocusPolicy(Qt::TabFocus);
view->rootContext()->setContextProperty("window", view);
view->setSource(QUrl("qrc:/main.qml"));
setCentralWidget(container);
resize(400, 400);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
#include "main.moc"
main.qml:
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
Item {
anchors.fill: parent
// Connections {
// target: window
// onAfterSynchronizing: loader.active = true
// }
Timer {
running: true
repeat: true
interval: 50
onTriggered: {
loader.active = true
}
}
Loader {
id: loader
active: false
sourceComponent: Column {
anchors.fill: parent
Repeater {
model: 30000
delegate: Button {
text: index
}
}
}
}
BusyIndicator {
running: loader.status === Loader.Null
anchors.centerIn: parent
}
}
For brevity, I chucked the "heavy" QML into sourceComponent, but you can also use the source property to point to a URL.
BusyIndicator runs its animation on the render thread, so it can continue to spin while the GUI thread is blocked.
I notice that QML's StatusBar type doesn't include the SizeGrip like QStatusBar does.
In order to get a size grip, I had to instead embed the QML into a QMainWindow with a QStatusBar. Although this works, it complicates the rest of the app and it's not really the design I'm after.
Would it be possible to implement the QStatusBar directly in QML by subclassing it and how would QML be able to recognise/use the SizeGrip?
EDIT:
I've attempted to derive QQuickPaintedItem to try and render a QStatusBar in QML, but so far haven't had any luck. An error is being triggered in the render call: ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 399d3d8. Receiver '' (of type 'QStatusBar') was created in thread 8c9f00", file kernel\qcoreapplication.cpp, line 553
.h
class WindowStatusBar : public QQuickPaintedItem
{
Q_OBJECT
public:
explicit WindowStatusBar(QQuickItem *parent = 0);
virtual ~WindowStatusBar();
void paint(QPainter *painter);
protected:
QStatusBar *statusBar_;
};
.cpp
WindowStatusBar::WindowStatusBar(QQuickItem *parent)
: QQuickPaintedItem(parent)
, statusBar_(NULL)
{
setOpaquePainting(true);
setAcceptHoverEvents(true);
setAcceptedMouseButtons(Qt::AllButtons);
statusBar_ = new QStatusBar;
}
WindowStatusBar::~WindowStatusBar()
{
delete statusBar_;
}
void WindowStatusBar::paint(QPainter *painter)
{
statusBar_->render(painter, QPoint(), QRegion(),
QStatusBar::DrawWindowBackground | QStatusBar::DrawChildren);
}
Yes, you can derive your own statusbar QML type from StatusBar or you can use the standard QML StatusBar with a contentItem that you designed. To implement the size grip you would put a MouseArea at the right border- in the onPositionChanged you would emit a signal that is interpreted by the mainwindow as a resize command. Avoiding feedback loops (because resizing the main window may change the position in the MouseArea) is left as an exercise for the reader.
I am trying to implement a pop-up confirmation box in an application using QtQuick 1.1, this means I dont have access to QtQuick Dialogs. How would I go about implementing this? I couldn't find anything in the documentation
You can render your QML application unto QWidget, register this widget as context object, and expose static methods of QMessageBox to generate a dialog:
class QmlWidget : public QQuickWidget // or QWidget + QQuickView combination
{
...
public:
void warning(const QString& title, const QString& message, ...)
{
QMessageBox::warning(this, title, message, ...);
}
};
int main()
{
QmlWidget w;
auto engine = w.engine();
auto ctx = engine.rootContext();
// expose w to qml
ctx->setContextProperty("qmlwidget", &w);
w.show();
return app.exec();
}
In QML:
Item {
Component.onCompleted: qmlwidget.warning()
}
Or you can simply write a screen blocking Rectangle with Text items and buttons. Or simply upgrade your application into QtQuick 2.x!
I am currently trying to develop a quite important application (OS-like) with Qt 5.2 and Qt Quick 2 ; what I would like to do is to have all the logic implemented in C++, the UI being declared thanks to QML. At this point, it seems logical and the way to get around. However, I can’t figure how to do it the clean way.. I’ve read a lot of documentation, tutorials and examples but nothing so big…
Let’s explain a little what I would like to put as an architecture ; let’s say we have a Scene object, which could contains an undefined number of Application objects. What I would like is to define the logic in CPP (how I load the applications from XML, what the scene should have as properties, …) and then show the scene with QML. Also, we have to notice that Scene and Application elements should be re-used as component ; so, here is the basic idea : I’d like to define graphical styles that are common to each object with a file in QML (extending the CPP type).
For example, I could create a file with this content :
Application {
Rectangle { ... }
}
Saying that an application should be representated as a Rectangle ; then, when I create a Scene object that have a list of Application (or one unique Application, to begin with), I would like it to be displayed automatically (‘cause this is a property of Scene object). Is it even possible ? How can I do that ?
I thought that if I extend the C++ object and declare some graphical elements for it, it would be automatic.. But actually it doesn’t look like that !
Maybe there is another way around ?
Thanks
I don't like this question too much, as it's not really asking anything in particular. The Qt documentation is very comprehensive, so I often find it strange when people say they've read documentation, tutorials and examples, and still haven't found what they're looking for. However, I think I understand the gist of what you're asking, and think the answer could be useful to some, so I'll try to answer it.
main.cpp
#include <QtGui/QGuiApplication>
#include <QtQml>
#include <QQuickItem>
#include "qtquick2applicationviewer.h"
class ApplicationItem : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QString title MEMBER mTitle NOTIFY titleChanged)
public:
ApplicationItem(QQuickItem *parent = 0) : QQuickItem(parent) {
}
public slots:
void close() {
emit closed(this);
}
signals:
void titleChanged(QString title);
void closed(ApplicationItem *app);
private:
QString mTitle;
};
class SceneItem : public QQuickItem
{
Q_OBJECT
public:
SceneItem() {
}
public slots:
void startApp(const QString &qmlFile) {
QQmlComponent *component = new QQmlComponent(qmlEngine(this), QUrl(qmlFile));
if (component->isLoading()) {
QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
this, SLOT(componentStatusChanged()));
} else {
// The component was synchronously loaded, but it may have errors.
if (component->isError()) {
qWarning() << "Failed to start application:" << component->errorString();
} else {
addApp(component);
}
}
}
void componentStatusChanged(QQmlComponent::Status status) {
QQmlComponent *component = qobject_cast<QQmlComponent*>(sender());
if (status == QQmlComponent::Ready) {
addApp(component);
} else if (status == QQmlComponent::Error) {
qWarning() << "Failed to start application:" << component->errorString();
}
}
void appClosed(ApplicationItem *app) {
int appIndex = mApplications.indexOf(app);
if (appIndex != -1) {
mApplications.removeAt(appIndex);
app->deleteLater();
}
}
private:
void addApp(QQmlComponent *component) {
ApplicationItem *appItem = qobject_cast<ApplicationItem*>(component->create());
appItem->setParentItem(this);
connect(appItem, SIGNAL(closed(ApplicationItem*)), this, SLOT(appClosed(ApplicationItem*)));
mApplications.append(appItem);
delete component;
}
QList<ApplicationItem*> mApplications;
};
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtQuick2ApplicationViewer viewer;
qmlRegisterType<ApplicationItem>("Test", 1, 0, "ApplicationItem");
qmlRegisterType<SceneItem>("Test", 1, 0, "SceneItem");
viewer.setMainQmlFile(QStringLiteral("qml/quick/main.qml"));
viewer.showExpanded();
return app.exec();
}
#include "main.moc"
I represented both classes as QQuickItem subclasses. SceneItem is composed of many ApplicationItem instances, which are added to the scene by invoking startApp(). This slot takes a path to a QML file as its argument. This file could be loaded over a network, or from a local file, hence we account for the possibility of both synchronous and asynchronous loading.
The QML file should describe the visual appearance of an application, and the scene expects its root type to be ApplicationItem. As an example, here's MySweetApp.qml:
import QtQuick 2.0
import QtQuick.Controls 1.0
import Test 1.0
ApplicationItem {
id: someAppStyle
title: "My Sweet App"
width: 100
height: 100
MouseArea {
anchors.fill: parent
drag.target: parent
}
Rectangle {
radius: 4
color: "lightblue"
anchors.fill: parent
Text {
anchors.left: parent.left
anchors.right: closeButton.right
anchors.leftMargin: 4
anchors.top: parent.top
anchors.topMargin: 4
text: someAppStyle.title
}
Button {
id: closeButton
anchors.right: parent.right
anchors.rightMargin: 4
anchors.top: parent.top
anchors.topMargin: 2
onClicked: close()
text: "x"
width: 20
height: width
}
}
}
Applications can close themselves by invoking the close() slot declared in ApplicationItem.
Here's main.qml:
import QtQuick 2.0
import QtQuick.Controls 1.0
import Test 1.0
SceneItem {
id: scene
width: 360
height: 360
Button {
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
text: "Launch app"
onClicked: scene.startApp("qml/quick/MySweetApp.qml")
}
}
This is where the SceneItem is declared, along with a simple interface to launch several instances of My Sweet App (it's a very useful app).
I believe this is the most appropriate way to do what you're asking. It avoids the hassle of setting up lists of ApplicationItems in C++ which are exposed to QML (it's actually not that hard, but this is one area where the documentation could be more obvious), and allows the users of your OS freedom in how applications appear. If you want to be more strict in what can be styled, I'd suggest looking into how Qt Quick Controls does styling.
I would advise against using C++ for the logic unless you really need to - use casese to use C++ for the logic are if you have high-performance requirements like realtime data that needs to processed like 10x per second.
As most of the use cases do not have this requirement, it is better to use QML also for application logic because it will save up to 90% source code (and time) compared with C++. Especially in the beginning of development, you are way faster to code the logic in QML and get results faster. You can later on still move the logic to C++ if needed.
There are 2 good guides about this topic available that explain this in more detail and come with source code examples:
QML Architecture Tips and why/how to avoid C++ in your Qt app
QML Architecture Best Practices and Examples
How can I save QML Image into phone memory ??
also if saving the image was applicable , I have this case which I need to add some text to the image (we can imagine it as we have a transparent image[that hold the text] and put it over the second image , so finally we have one image that we can save it into phone memory)
Not from Image directly. QDeclarativeImage has pixmap, setPixmap and pixmapChange methods, but for some reason there is no property declared. So you cannot use it fom qml. Unfortunately it cannot be used from C++ either - it is a private calsss.
What you can do is paint graphics item to your pixmap and save it to file.
class Capturer : public QObject
{
Q_OBJECT
public:
explicit Capturer(QObject *parent = 0);
Q_INVOKABLE void save(QDeclarativeItem *obj);
};
void Capturer::save(QDeclarativeItem *item)
{
QPixmap pix(item->width(), item->height());
QPainter painter(&pix);
QStyleOptionGraphicsItem option;
item->paint(&painter, &option, NULL);
pix.save("/path/to/output.png");
}
Register "capturer" context variable:
int main()
{
// ...
Capturer capturer;
QmlApplicationViewer viewer;
viewer.rootContext()->setContextProperty("capturer", &capturer);
// ...
}
And use it in your qml:
Rectangle {
// ...
Image {
id: img
source: "/path/to/your/source"
}
MouseArea {
anchors.fill: parent
onClicked: {
capturer.save(img)
}
}
}
With Qt 5.4+ you can do it straight from your Qml with:
grabToImage