Creating a pop-up dialog in QtQuick 1.1 - qt

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!

Related

Qt: Track mouse position while QDrag is running

I am developing a Qt application with multiple windows and want to implement cross-window drag&drop functionality for some elements in my program.
To do so, I attach an event filter to the to-be-dragged QML elements and listen for the MousePress/MouseMove events to start the drag procedure as follows:
QDrag *drag = new QDrag(quickItem);
QMimeData* mimeData = new QMimeData();
mimeData->setText("Test");
drag->setHotSpot(QPoint(0, 0));
drag->setMimeData(mimeData);
drag->exec();
This works fine, but now I would like to show a little tooltip (being a QWidget) while dragging, following the mouse cursor and displaying a short text depending on the element the mouse is currently over (similar to the "Copy to ..." or "Move to..." labels appearing when you drag files around in Windows Explorer).
However, while dragging the element, I don't receive any MouseMove events neither on the QDrag object nor on the quickItem itself, which makes it impossible to track the mouse position. Since the mouse is grabbed during dragging, there should be some event in Qt that frequently reports the mouse position, no matter where on the screen the mouse is.
I am aware of the QDrag::setPixmap method, however this won't allow me to change my tooltip text during dragging and has some other limitations I would like to avoid.
Is there some way to listen to mouse move events while QDrag is running, without using platform-specific system APIs?
Update:
I don't think that there is way of doing this without using OS libraries nor getting the mouse position every X miliseconds. It looks like a really specific problem that Qt framework does not contemplate. You will need to write your own class to control this using win32 for windows, x11 for linux and the equivalent of Mac.
If you want to get the mouse position when your window is active and you are dragging something, check this:
Searching a bit I've found a solution for getting it when your window has the focus using QObject::eventFilter.
Create a class (for example EventListener) that inherits from QObject and overrides eventFilter and a method to set this as your qml window (which inherits from QObject) event filter with installEventFilter.
eventslistener.h:
#include <QEvent>
#include <QObject>
#include <QDebug>
#include <QDropEvent>
class EventsListener : public QObject
{
Q_OBJECT
public:
EventsListener(QObject * ptr) : QObject (ptr) {
}
Q_INVOKABLE void handleEventsOf(QObject *object) {
if (object)
object->installEventFilter(this);
}
bool eventFilter(QObject *object, QEvent *event) override {
if(event->type() == QEvent::DragMove) {
QDragMoveEvent *mouseEvent = static_cast<QDragMoveEvent*>(event);
qDebug() << "Mouse position dragging (x, y): (" << mouseEvent->pos().x() << ", " << mouseEvent->pos().y() << ")";
return false; //this is must return false or drop event will be handled by this method and drag&drop won't work correctly
}
return false;
}
};
Now we need to access to an instance (singleton in this case) of this class with qmlRegisterSingletonType. You may wish to use qmlRegisterType instead to register this eventlistener as a type (instead of a singleton) and use signals to notify directly qml the mouse position.
main.cpp:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "eventlistener.h"
static QObject *eventsListenerInstance(QQmlEngine *qmlEngine, QJSEngine *engine)
{
return new EventsListener(engine);
}
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qmlRegisterSingletonType<EventsListener>("AppEventListener", 1, 0, "EventsListener", eventsListenerInstance);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml:
import ...
import AppEventListener 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
id: item
property string display
property alias dropEnabled: acceptDropCB.checked
color: dropArea.containsDrag ? "#CFC" : "#EEE"
Component.onCompleted: EventsListener.handleEventsOf(item)
...
}

Enable / disable camera (QML Camera)

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.

QT 5.8 how does Webview do a request and how can I intercept it?

I am trying to pass QnetworkRequest to a webView located in my main.qml file instead of a "url". I pass the url by referecing the webView object and the setproperty function. However, haven't found the right function and really do not know where to start in order to either create a new function or modify the existing webView code in order to get this to work. Is there a way to edit the source code to the webView in the .qml file. Of course i am just learning the QT framework.
I have tried WebengineView but the Webview is MUCH faster in loading a page. and that is critical for the application
I guess the real question is how does Webview do a request and how can I intercept it?
main.qml
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtWebView 1.1
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.2
ApplicationWindow {
flags: Qt.FramelessWindowHint
visible: true
x: 600
y: 400
width: 500
height: 500
title: webView.title
WebView {
id: webView
anchors.fill: parent
objectName: "webView"
//setting this value through main.cpp
// url: "https://www.google.com"
onLoadingChanged: {
if (loadRequest.errorString)
console.error(loadRequest.errorString);
}
}
}
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QtWebView::initialize();
QQmlApplicationEngine engine;
//How to Pass THIS request to the webview instead of url?
QNetworkRequest request;
request.setUrl(QUrl("http://google.com"));
request.setRawHeader("Accept-Charset", "UTF-8,*;q=0.5");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QObject *rootObject = engine.rootObjects().first();
QObject *qmlObject = rootObject->findChild<QObject*>("webView");
//Able to set the URL for the webView:
qmlObject->setProperty("url", "https://www.google.com" );
return app.exec();
}
AFAIK, all QML components use QNetworkAccessManager. You can register your own factory to have you own class handle the networking. You could overload the get method and change the header if the url matches google, or whatever you want to do:
class MyNetworkManager : public QNetworkAccessManager {
public:
QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request) {
if (request.url.contains("google")) {
request.setRawHeader("Accept-Charset", "UTF-8,*;q=0.5");
}
return QNetworkAccessManager::get(request)
}
}
Of course, here request is const so you would have to construct a new request, but I hope this shows the basic idea!
Example on how to register your own NetworkAccessManagerFactory in main.cpp:
http://doc.qt.io/qt-5/qtqml-networkaccessmanagerfactory-example.html

Avoid QQuickView delayed qml loading

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.

QML StatusBar with SizeGrip

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.

Resources