I'm trying to prepare QML plugin to play video on embedded device in a way that other developers can use it without much hassle. However the way it is currently proposed requires almost always writing some C++ wrapper around your QML application. I'm refering to this example:
http://gstreamer.freedesktop.org/data/doc/gstreamer/head/qt-gstreamer/html/examples_2qmlplayer_2main_8cpp-example.html
I would like to be able to have plugin and simply write:
import AwesomeVideoPlugin 1.0
Rect
{
AwesomeVideo
{
width: 320
height: 240
url: "./myvideo.avi"
// ... some minor stuff like mouse click handling, controls, etc.
}
}
Currently QtGStreamer requires to provide videoSurface property to VideoItem. The only way to do this is to create and set context for additional property in rootContext(). And to create GraphicsVideoSurface I need QGraphicsView (QDeclarativeView fills this role).
Is it possible to:
Get QDeclarativeView from within QDeclarativeItem (to which I have only access from QML plugin) in a way that it can be later used to feed GraphicsVideoSurface? My guess is no - however I've found path QFraphicsItem::scene() ==> QGraphScene ==> QGraphScene::views() ==> QList of QGraphicsView - it looks like VERY bad programming but maybe somebody got it to work (I'm getting segfault)
Is there other way to provide video sink for QtGStreamer from within QDeclarativeItem ?
Greetz
Yatsa
I had the same question, but haven't come up with an elegant solution.
However, one thought would be to make the videosurface available via an accessor function from a sub-classed QApplication object.
This would, of course, mean that your plug-in depends on the application subclass having a getVideoSurface method, but it does remove the ugliness from the QML code.
class MyApp : public QApplication
{
....
QGst::Ui::GraphicsVideoSurface *getVideoSurface() { return m_videosurface; }
}
...
int MyApp::init()
{
m_viewer = new QDeclarativeView();
m_viewer->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
m_videosurface = new QGst::Ui::GraphicsVideoSurface(m_viewer);
}
MyVideoPlugin::MyVideoPlugin(QDeclarativeItem *parent) : QDeclarativeItem(parent)
{
QGst::Ui::GraphicsVideoSurface *surface = ((MyApp*)qApp)->getVideoSurface();
}
...
Now the MyVideoPlugin element may be used without referencing an exported videosurface context item.
Related
I am trying to design a preferences panel for my multidocument app. When a given pref changes – font size, say – all of the document windows should immediately update to reflect the new pref value. I don't want to construct the preferences panel up front, for all the document windows to connect to, because it contains a QFontComboBox that takes more than a second to set itself up (ouch); that's not a price I want to pay at startup. So then, my question is: what is an elegant design for the prefs panel to let all the document windows know about the change? In Cocoa, which I'm more used to, I'd use NSNotification to broadcast a notification from the prefs panel that all the document windows could observe; that provides the loose coupling required (since objects can add themselves as observers before the broadcaster exists).
Two approaches occur to me so far:
Loop through topLevelWidgets, do a dynamic cast to my document window class, and for all the document windows I thereby find, just call a hard-coded method on them directly.
Make a second class, PreferencesNotifier, that is separate from the UI object that takes so long to load, and construct a singleton object of this class at startup that all of the document windows can connect themselves to. When the preferences panel eventually gets created, it can send signals to slots in PreferencesNotifier, which will then call its own signals to notify the connected document windows.
Neither seems quite as elegant as NSNotification, and I'm wondering if I'm missing something. Thanks for any tips.
First thing, do not try to copy patterns, like Cocoa's NSNotification/NotificationCenter, to other frameworks (or languages, or...). There are various ways to send messages and generally each framework has picked one. Trying to use the one method that was picked by the framework you are using will lead to the most elegant solutions.
If you really want to, you could implement your own set of classes that will do exactly what NSNotification does. It will feel more elegant to you, but only because you are used to using Cocoa. It will feel odd to every other Qt developer. Also, this solution will require you to write a lot of code as you will not be able to leverage all the features of Qt.
The first solution you are suggesting is a bit ugly and looks more like a hack than anything.
What I do, when I have to handle preferences in a program, is something similar to your solution 2. I create a class that is responsible for handling all settings: read/write setting file, change setting, set default values, etc. Generally this class is a singleton. This class has very limited access to other parts of the program, and generally no access at all to the UI. Each components that needs to access the preferences will use this class. If you do it properly (e.g. use Q_PROPERTY), this class can even be accessed by QML, if you ever need to use Qt Quick.
class Settings: public QObject {
Q_OBJECT
Q_PROERTY(bool showX READ showX WRITE setShowX NOTIFY showXChanged)
public:
bool showX() const { return m_showX; }
void setShowX(bool show) {
if (show == m_showX)
return;
m_showX = show;
emit showXChanged(m_showX);
}
signals:
void showXChanged(bool);
public slots:
void save() const; // Save to disk
void load(); // Load from disk
private:
QSettings m_settings; // Handle load/save from/to disk
bool m_showX;
};
class Window {
Window() {
...
m_widgetX->setVisible(settings->showX());
connect(settings, &Settings::showXChanged,
this, [this](bool show) { m_widgetX->setVisible(show); }
);
...
}
};
class PrefWindow {
PrefWindow () {
...
ui->checkBoxShowX->setChecked(settings->showX());
...
}
private slots:
void on_saveButton_clicked() {
settings->setShowX(ui->checkBoxShowX->checked()):
settings->save();
}
};
I have got a QQuickView which has loaded a qml file like the following.
Rectangle { width: 100; height: 100 }
Then I am retrieving the root object via QObject *root = view->rootObject().
Now I want to get the class name from this object.
The following code results into "QQuickRectangle"
root->metaObject()->className()
But what I want is "Rectangle" just like the typename in the qml file.
Any idea?
Edit: I want to build a treeview with the object hirarchie of a qml file like QtCreator.
There is a pattern there, for qml types implemented in C++ the name would be QQuickSomething, for qml types implemented in qml the name would be Something_QMLTYPE_X_MAYBEMORESTUFF(objAddress).
So you can do some basic string editing depending on the result you get to isolate the actual type name:
QString name = QString(root->metaObject()->className());
if (name.contains("QQuick")) name.remove("QQuick");
else if (name.contains("QMLTYPE")) name.remove(QRegExp("_QMLTYPE_[0-9]*.*"));
// else it might be just a QObject or your on custom type you should handle
Edit: I want to build a treeview with the object hirarchie of a qml
file like QtCreator.
Unless you are willing to dig into and use private APIs, it would likely be easier and also more useful to have your own custom model to drive both a view and the actual object tree. Also, QML is quite easy to parse, I'd personally buckle down and write a parses faster than it would take me to get into the existing one, especially if all that is needed is an object tree outline, but YMMV.
There is "better" information kept on this (QQmlType & QQmlMetaType), but it is not accessible through any public API that I can think of.
Can you explain what you would like to do with it? Maybe there's an alternative.
QtQuick doesn't provide some special metadata for QML items. It looks that QtQuick uses item types internally only while parsing the source.
The known workaround is objectName:
Rectangle {
objectName: "Rectangle"
}
and so:
QString className = item->objectName();
What is an optimal and an appropriate way to save the state of a Qt GUI so I get the same state I had back when I closed the application ?
By state I mean : current indexes (for combo box ...), color palette, widgets positions... right before closing the application
You can use the QSettings class.
Simple use of QSettings class (code inspired from Qt's documentation):
In the main-window of your application code member functions that saves and restore the settings:
void MainWindow::writeSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings("reaffer Soft", "reafferApp");
settings.beginGroup("MainWindow");
resize(settings.value("size", QSize(400, 400)).toSize());
move(settings.value("pos", QPoint(200, 200)).toPoint());
settings.endGroup();
}
Call those 2 functions from the MainWindow constructor and from the closeEvent override, like this:
MainWindow::MainWindow()
{
// code from constructor
//...
readSettings();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
//optional check if the user really want to quit
// and/or if the user want to save settings
writeSettings();
event->accept();
}
The direct answer requires specific elaborated design for your code and not really a short Qt question or even the question specific to Qt. That is about C++ which is not the VM-based language that assists with serializing the state of program code to data. Having all objects serializable we can then attempt to apply certain C++/Qt classes/techniques.
This task is much easier to accomplish with languages like Java, though. And with C++/Qt you have to routinely make serialize-able / serialize / restore everything that is running in your code and still no guarantee that works as long as the context is not fully captured. This task is not easy for sure and makes sense only in specific application.
The most you can get directly from Qt is to save/restore QMainWindow and other independent widgets geometry (position/size):
saveGeometry
restoreGeometry
... and that solution is still somewhat incomplete or you may/not use QSettings for the storage.
I use QSettings for this. With routines similar to Zlatomir's.
For each window I have in the project I use a different section in QSettings and have readSettings() and writeSettings() in the source for each window.
Anything on the form that I want to persist I have to explicitly save and recall. In the case of a QComboBox it would be something like:
QSettings settings("Organisation", "MySoftware");
settings.beginGroup("WindowNumberTwo");
settings.setValue("ComboIndex", combobox->currentIndex());
// save more values here
// ...
settings.endGroup();
I don't know of a built in way to persist your window states - it has to be don't value by value.
I'm complete noob in Qt, so my question may sound too stupid, but I really need help. I know C++ a little and that's it.
So, my task is to write a C++ program which reads INI-alike (format is not very important) file
height=20
width=15
To make it clear, I have no idea what properties will be defined in this file, names or types are unknown to me at compile time.
After that program loads QML file (I can do this) and injects loaded file data (have no idea how to do this) as JavaScript object, for instance named "Settings", so that QML property bindings will use it like
Rectangle {
width: Settings.width
height: Settings.height
}
So the question is: How can I inject read data as JavaScript object into QML so that QML property binding will use it?
One way to do it would be to write a QObject wrapper around QSettings and expose an instance of it to QML, another would be to use the Settings QML Type. I am sure there are others.
I am trying to implement Custom File Explorer that fetches metadata of the specific(in house file system) file and displays all these data along with files. For this task I have implemented custom QFileSystemModel that takes care of this.
Now, I understand that loading of file is asynchronous in QFileSystemModel but display is not. Qt holds display job till all the files are loaded. As i have included metadata extraction logic in each display call, it makes display of folder with more than 100 file really slow(even after caching). During whole this time display is completely blocked. How can I display results asynchronously. To be precise display list partly and then refresh it when updates are available.
Files are displayed through QTableView UI widget.
1.You can put your extraction logic in a different thread. Look here how to do that:http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
If you use a shared data don't forget to use a mutex. Also you can send new meta from the new thread to GUI via signals with an argument containing the meta info. In this way you'll need to register a new class with qRegisterMetaType and Q_DECLARE_METATYPE to make it possible to convert it to QVariant and back:
http://qt-project.org/doc/qt-4.8/qmetatype.html
2.Also you can make the files load much faster if you disable loading of icons. For example, if you have only one type of files you can provide an icon preloaded from the resources.
This is how to disable loading of icons:
a) Create a fake icons provider:
class FakeIconProvider : public QFileIconProvider
{
public:
FakeIconProvider();
virtual QIcon icon(IconType) const override
{
return QIcon();
}
virtual QIcon icon(const QFileInfo&) const override
{
return QIcon();
}
};
b) Create an instance of the fake icons provider and install it to the model:
model->setIconProvider(m_fakeIconProvider);