How to subclass QML Window? - qt

I need to add some features in c++. But I struggle how to properly create my own QML window type.
I have tried to subclass QQuickWindow and register my new type and use it in My QML project. But when starting it show error, that I can not set opacity
mywindow.h
#include <QQuickItem>
#include <QQuickWindow>
#include <QWindow>
#include <QApplication>
#include <QObject>
class MyWindow : public QQuickWindow {
Q_OBJECT
public:
MyWindow(QQuickWindow *parent=nullptr);
public slots:
Q_INVOKABLE void mycppFeature();
mywindow.cpp
#include "reminderwindow.h"
MyWindow::MyWindow(QQuickWindow *parent):QQuickWindow(parent){
}
main.cpp
qmlRegisterType<MyWindow>("com.organization.my", 1, 0, "MyWindow");
SplashWindow.qml
import QtQuick 2.0
import QtQuick.Controls 2.5
import QtQuick.Window 2.15
import com.organization.my 1.0
MyWindow{
opacity: 0.8
MyWindow is find but the error is "MyWindow.opacity" is not available in com.organizatino.my 1.0. I believe I do not know how to properly subclass the QML Window type. I use it besides the main ApplicationWindow
When I use it without opacity, it works properly

Add this to your MyWindow class declaration:
QML_FOREIGN(QQuickWindow)
The opacity property is declared on QWindow (inherited by QQuickWindow) like this:
Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged REVISION(2, 1))
Meaning it was added in version 2.1 of the QtQuick.Window QML module.
The QML_FOREIGN documentation states:
Declares that any QML_ELEMENT, QML_NAMED_ELEMENT(), QML_ANONYMOUS, QML_INTERFACE, QML_UNCREATABLE(), QML_SINGLETON, QML_ADDED_IN_MINOR_VERSION(), QML_REMOVED_IN_MINOR_VERSION(), QML_ATTACHED(), or QML_EXTENDED() macros in the enclosing C++ type do not apply to the enclosing type but instead to FOREIGN_TYPE. The enclosing type still needs to be registered with the meta object system using a Q_GADGET or Q_OBJECT macro.
So that tells the QML machinery to not validate the version restrictions against your module but against the one that QQuickWindow is provided in.
More discussion in these bug reports similar to yours:
https://bugreports.qt.io/browse/QTBUG-91706
https://bugreports.qt.io/browse/QTBUG-72986

Related

Proper way to pass QColor object into Qdialog subclass

I am having a problem with a QDialog subclass that I am using to pass two QT Objects into: QColor and QFont. If I pass by reference the application unexpectedly crashes before it can run even though it compiled out without error.
I was able to get it to work using pointers but it looks ugly, and messes up the rest of the code. I want to get it working by reference and refrain from using 'New' keyword to instantiate QFont or QColor classes. So basically my working subclass constructer using pointers looks like this:
HEADER:
class MySettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit MySettingsDialog(QColor *acolor, QFont *afont, QWidget *parent=0);
CLASS FILE:
MySettingsDialog::MySettingsDialog(QColor *acolor, QFont *afont, QWidget *parent) :
QDialog(parent, Qt::WindowCloseButtonHint), m_color(*acolor), m_font(*afont),
ui(new Ui::MySettingsDialog)
{
ui->setupUi(this);
}
This way works but I have to in my MainWindow.cpp file declare for example:
QFont * systemFont;
systemFont = New QFont("myfont whatever");
And everywhere I want to apply that font I have to unmask like this:
ui->mylabel->setfont(*systemFont).
Before I wasn't using 'new' to instantiate my systemFont variable and systemFont wasn't declared as a pointer in the header file. Such that if Mydialog was declared like this the program crashes:
DOESNT WORK:
HEADER
explicit MySettingsDialog(const QColor &acolor, const QFont &afont, QWidget *parent=0);
CLASS FILE:
MySettingsDialog::MySettingsDialog(const QColor &acolor, const QFont &afont, QWidget *parent) :
QDialog(parent, Qt::WindowCloseButtonHint), m_color(acolor), m_font(afont),
ui(new Ui::MySettingsDialog)
{
ui->setupUi(this);
}
Mainwindow:
MySettingsDialog(systemColor, systemFont, this);
What am I doing wrong?
Thanks
Things got stranger and stranger but I finally figured it out. It seems as if you can't instantiate a QDialog subclass within a function subroutine. I had an init() routine and running this code not work:
void MyProgram::init() {
systemColor = QColor("red");
systemFont = QFont("Consolas", zoomFactor);
settingsDialog = new UefiSettingsDialog(systemColor, systemFont, this);
...... ... ... }
but the same code called right at the beginning of the start of code works without any failure to launch. Probably a scope issue though I have no idea why.

Another time source for QML animations?

I am thinking about building a gstreamer plugin that renders animated QML graphics for later overlaying onto playing video. So far the idea to use QML looks very promising to me, except one problem. I need to be able to seek within the video, and the animations must also rewind and jump to the required point in time. Now that I read QML docs, I see that all the animations are typically time bound.
So my question is: is it possible to bind QML animations to some "time source", other than the real world time, which may not be monotonous (in fact, it can be manipulated by the application). Or, more generically, can I bind QML animation to a numeric value X, so that when it changes, my animation progresses, and there is a strict relation between X and animation state. I hope you get the idea.
This answer is suitable only for NumberAnimation object. Probably similar approach can be used to replace other Animation objects as well.
As already stated by ddriver there is no other way than work around.
Here is my solution to the problem. It may seem complicated but I can assure it is easy to use. At the end of this answer I put a link to the source code of example project using this code. You can try it.
Add these files to your project:
easingvalueforprogress.h
#ifndef EASINGVALUEFORPROGRESS_H
#define EASINGVALUEFORPROGRESS_H
#include <QObject>
#include <QEasingCurve>
class EasingValueForProgress : public QObject
{
Q_OBJECT
public:
explicit EasingValueForProgress(QObject *parent = 0);
Q_INVOKABLE double getValue(int easingEnum, double progress){
QEasingCurve easing((QEasingCurve::Type)easingEnum);
return easing.valueForProgress(progress);
}
signals:
public slots:
};
#endif // EASINGVALUEFORPROGRESS_H
easingvalueforprogress.cpp
#include "easingvalueforprogress.h"
EasingValueForProgress::EasingValueForProgress(QObject *parent) : QObject(parent)
{
}
XValueAnimation.qml
import QtQuick 2.0
Item {
id: xValueAnimator
property Item target
property string targetProperty
property double from
property double to
property int easing: Easing.Linear
property double xValue
onXValueChanged: {
if (target.hasOwnProperty(targetProperty)) {
target[targetProperty] = calculateCurrentValue(
from, to, easing, xValue);
}
else
console.error("XValueAnimator: target:", target,
"does not have property", targetProperty)
}
function calculateCurrentValue(
defaultFrom, defaultTo, animationEasing, xValue) {
return defaultFrom + (defaultTo - defaultFrom)
* easingValueForProgress.getValue(animationEasing, xValue)
}
}
Add this to your main.cpp:
#include <QQmlContext>
#include "easingvalueforprogress.h"
EasingValueForProgress easingValueForProgress;
engine.rootContext()->setContextProperty(
"easingValueForProgress", &easingValueForProgress);
Now you can use it like this (instead of NumberAnimation object):
XValueAnimator {
target: object_you_want_to_affect // for example id of the object
targetProperty: "property_to_affect" // for example "x"
from: 100
to: 500
easing: Easing.OutQuad // omit to use Easing.Linear
xValue: myXValue // your property holding values from 0 to 1
}
Here I provided working example project. Feel free to download and test it.

How to have a QTextBrowser to display contents of a QTextEdit?

I am trying to connect QTextEdit to QTextBrowser, so the text browser widget outputs what is entered in text edit widget. As a signal I used textChanged(), and as a slot I used setText(QString). And these two don't have same parameters.
If I used QLineEdit instead of QTextEdit, in that case there is textChanged(QString) function which is compatible with the slot,but I need to make it work with QTextEdit. Here is the code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QWidget * mainWidget=new QWidget(this);
ui->setupUi(this);
QTextEdit * mainTextEdit=new QTextEdit();
QTextBrowser * textDisplay=new QTextBrowser();
connect(mainTextEdit,SIGNAL( textChanged() ),
textDisplay,SLOT( setText(QString) ) );
QHBoxLayout * Alayout=new QHBoxLayout();
Alayout->addWidget(mainTextEdit);
Alayout->addWidget(textDisplay);
mainWidget->setLayout(Alayout);
setCentralWidget(mainWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
Thankfully, the QTextEdit and QTextBrowser are views onto a QTextDocument model. So, you can simply set the editor's document on the browser. QTextBrowser::setDocument is semantically equivalent to QAbstractItemView::setModel:
textDisplay->setDocument(mainTextEdit->document());
In Qt, there are really two basic model classes: QAbstractItemModel and QTextDocument. A QTextDocument is a model in its own model-view framework. We simply set another view onto the document that the editor operates on. The editor allows modifications to the model, the browser doesn't. It's no different from using the same model on two QListViews, etc.
A QTextEditor is a view with a default model (document). You can replace that default model with one from another view, or even with one that you yourself provide. You could have multiple editors all displaying the same QTextDocument document and allowing editing of it, in parallel. You can also have multiple browsers doing the same.
Complete example:
#include <QApplication>
#include <QTextEdit>
#include <QTextBrowser>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QHBoxLayout layout(&window);
QTextEdit edit;
QTextBrowser browser;
layout.addWidget(&edit);
layout.addWidget(&browser);
browser.setDocument(edit.document());
window.show();
return a.exec();
}
I would do it in the following way:
Declare the pointers to the text edit and text browser widgets as member variables in the class,
Create a slot onTextChanged() in MainWindow class that will be called as soon as the text edit is changed and setup the connection as:
connect(mainTextEdit, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
Implement the onTextChanged() slot in the following way:
MainWindow::onTextChanged()
{
QString text = mainTextEdit->toPlainText();
textDisplay->setPlainText(text);
}

QLCDNumber Does Not Name a Type

I am trying to compile a test application for an ARM embedded device. If I use my Desktop Qt SDK version of Qt, this header file compiles just fine. If I use my Linaro GCC for the Embedded target from within Qt Creator, I get the error "'QLCDNumber' does not name a type" on the line of the private declaration for lcdNumber. I've googled around but do not see any solutions that work for this.
Is the problem that my embedded version of qt is missing support for QLCDNumber?
If so, why doesn't it complain about the #include ?
Also, if this is the case, does anyone happen to know what I need to enable in ./configure to enable support for QLCDNumber?
#ifndef BATTERYMONITOR_H
#define BATTERYMONITOR_H
#include <QtGui>
#include <QWidget>
#include <QLabel>
#include <QRadioButton>
#include <QLCDNumber>
class BatteryMonitor : public QWidget
{
Q_OBJECT
public:
BatteryMonitor(QWidget *parent = 0);
public slots:
void clickedBatteryStatus();
private:
QRadioButton *temperature;
QRadioButton *voltage;
QRadioButton *current;
QRadioButton *relativeStateOfCharge;
QRadioButton *batteryStatus;
QRadioButton *runTimeToEmpty;
QLCDNumber *lcdNumber;
};
#endif // BATTERYMONITOR_H
Did it config with QT_NO_LCDNUMBER defined in your embedded Qt SDK? You can check it in file $QTDIR/include/QtCore/qconfig.h.
QLCDNumber and qlcdnumber.h are in the right include path of Qt SDK no matter macro QT_NO_LCDNUMBER defined or not. So there is nothing wrong about #include <QLCDNumber>.

How to find global position of text cursor?

I would like to execute a QMenu object at the position of text cursor in a QPlainTextEdit. My problem is that QTextCursor is only define by its position in the Text (index of the character).
How can I find global position of the QTextCursor? Should I use an other object than QTextCursor in order to find the position of the text cursor where I want to open my QMenu?
Thank you by advance.
I've never tried myself, but doesn't QPlainTextEdit::cursorRect() work? It should give you position of the cursor in viewport coordinates. You can then get the viewport using viewport() and map the local position to global using viewport()->mapToGlobal().
I have found similar query to your in some online forum and here's someone suggested the output as
Note: Reference from http://www.unix.com/unix-linux-applications/81388-read-position-mouse-cursor.html, Author of below posting is daggilli, registered user of UNIX online forums. Credit of below posting in its complete form goes to daggilli.
This is the complete code for a Qt application I threw together in about ten minutes (called crosshair) which displays the current mouse coordinates in a window. You might be able to pull enough out of it to be useful. This is Qt 3.1, but Qt 4 is not a great deal different. You will need the Qt development libraries, not just the runtimes. The code comprises two files, crosshair.h and crosshair.cpp.
crosshair.h:
Code:
#ifndef CROSSHAIR_H
#define CROSSHAIR_H
#include <qwidget.h>
#include <qstring.h>
#include <qlabel.h>
#include <qevent.h>
class Crosshair : public QLabel
{
Q_OBJECT
public:
Crosshair(QWidget *parent=0);
protected:
void mousePressEvent(QMouseEvent *);
private:
QTimer *timer;
private slots:
void timerfire();
};
#endif
crosshair.cpp:
Code:
#include <qapplication.h>
#include <qpushbutton.h>
#include <qtimer.h>
#include <qcursor.h>
#include <iostream>
#include "crosshair.h"
using namespace std;
int main(int argc,char **argv)
{
QApplication a(argc,argv);
Crosshair mousepos;
a.setMainWidget(&mousepos);
mousepos.show();
return a.exec();
}
Crosshair::Crosshair(QWidget *parent) : QLabel(parent)
{
setIndent(20);
resize(100,30);
move(1200,200);
setText("0,0");
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timerfire()));
timer->start(50,false);
}
void Crosshair::mousePressEvent(QMouseEvent *)
{
qApp->quit();
}
void Crosshair::timerfire()
{
QPoint p=QCursor::pos();
this->setText(QString().sprintf("%d,%d",p.x(),p.y()));
}
To build this, put both files in a directory called crosshair. cd to that directory and type
Code:
qmake -project
qmake
make
This does nothing more complex than inherit from a QLabel, set a timer to run 20x a second, grab the current cursor coordinates and write them into the label's text. Clicking in the window closes it. I use it for fixing up alignment bugs in JavaScript when I'm laying out objects.
You could open a file in the Crosshair class's constructor to store your data, and use gettimeofday(2) to get a timestamp. Nothing says Qt has to run in GUI mode (you can tell it explicitly not to in the QApplication constructor).
Qt from Trolltech: http://doc.trolltech.com

Resources