Hugo Barra, VP of Product Management for Android, is out at Google and will join Chinese phone maker Xiaomi. [Hugo Barra+]
Monthly Archives: August 2013
Scientists Control One Person’s Body With Another Person’s Brain
Sit down for this one. Researchers at the University of Washington have figured out how to send commands from one person’s brain to control a different person’s muscle movement. In technical terms, it’s the world’s first noninvasive human-to-human brain interface. How’d they do it? Vulcan mind meld? Nope, just the regular ol’ internet. What in the hell?
QSettings and QML
Suffering from absence of useful QSettings in QML?
Its pretty easy to solve (if you not afraid of some c++ code in your project)
#ifndef SETTINGS_H #define SETTINGS_H #include <QObject> #include <QSettings> class Settings : public QObject { Q_OBJECT public: explicit Settings(QObject *parent = 0); Q_INVOKABLE void setValue(const QString & key, const QVariant & value); Q_INVOKABLE QVariant value(const QString &key, const QVariant &defaultValue = QVariant()) const; signals: public slots: private: QSettings settings_; }; #endif // SETTINGS_H
#include "settings.h" Settings::Settings(QObject *parent) : QObject(parent) { } void Settings::setValue(const QString &key, const QVariant &value) { settings_.setValue(key, value); } QVariant Settings::value(const QString &key, const QVariant &defaultValue) const { return settings_.value(key, defaultValue); }
register it:
QQmlContext *context = engine->rootContext(); context->setContextProperty("settings", &settings);
and use:
FileDialog { id: fileDialog folder: settings.value("lastFolder", ".") onAccepted: { settings.setValue("lastFolder", fileDialog.folder) } }
pretty easy, eh?
Multitask myst
Its turns out that some people cant do same thing at the moment. They claims that human’s brain cant do this. So, man cant walk and breathe at same time or shower and sing etc 🙂
That people invented iOS and WP to prove this mind virus.
Hopefully, there is other kind of people, who want and can do same things simultaneously
Where Exactly Did the Big Bang Actually Happen?
When you think of the big bang, that cosmic explosion that jump-started the ever-expanding universe as we know it, it’s only natural to imagine it as a single point. One corner of space that just blew up into the galactic being. But where was it?
New Camera Lets Astronomers Take Sharpest Ever Photos of the Universe
An international team of astronomers are having a blast with a new type of camera that can take photos of space that are twice as sharp as those taken by the Hubble Telescope. The technology’s been in the works for over 20 years, and when you see the pictures you can see how they were worth the wait.
Load and control QML from C++
Ok folks, today we are talking about how to load custom QML file and integrate it into your main application? It is useful, for example, to create settings UI for different plugins, when each plugin requires its own UI
So, here is a code:
#ifndef QMLSETTINGSVIEW_H #define QMLSETTINGSVIEW_H #include <QObject> #include <QQuickView> #include <QQmlApplicationEngine> #include <QQuickItem> class QmlSettingsView: public QObject { Q_OBJECT public: QmlSettingsView(QObject *parent = 0); ~QmlSettingsView(); QQmlApplicationEngine *engine() const; void setEngine(QQmlApplicationEngine *engine, const QString &qmlpath, const QString &finishedSignal); void showSettings(); void hideSettings(); bool setSettingsProperty(const char *name, const QVariant &value); QVariant settingsProperty(const char *name); public slots: virtual void settingsFinished() = 0; QQuickWindow *parentWindow() const; private: QQuickView *view_; QQmlApplicationEngine *engine_; QQuickItem *root_; QQuickWindow *parentWindow_; }; #endif // QMLSETTINGSVIEW_H
#include "qmlsettingsview.h" #include <QQmlContext> QmlSettingsView::QmlSettingsView(QObject *parent): QObject(parent) , view_(0) , engine_(0) , root_(0) , parentWindow_(0){ } QmlSettingsView::~QmlSettingsView() { if (view_) view_->deleteLater(); } QQmlApplicationEngine *QmlSettingsView::engine() const { return engine_; } void QmlSettingsView::setEngine(QQmlApplicationEngine *engine, const QString &qmlpath, const QString &finishedSignal) { engine_ = engine; if (!engine_) return; if (view_) //already created return; engine_->clearComponentCache(); if (engine_->rootObjects().count() <= 0) return; QObject *topLevel = engine_->rootObjects().value(0); parentWindow_ = qobject_cast<QQuickWindow *>(topLevel); if (!parentWindow_) return; view_ = new QQuickView(engine, parentWindow_); if (!view_) return; view_->setSource(QUrl(qmlpath)); if (view_->status() != QQuickView::Ready) { return; } root_ = view_->rootObject(); QString f_ = finishedSignal; f_ = f_.insert(0, "2"); //settingsFinished() must be implemented in child class connect(root_, f_.toLatin1().data(), this, SLOT(settingsFinished())); } void QmlSettingsView::showSettings() { if (!view_) return; view_->show(); } void QmlSettingsView::hideSettings() { if (!view_) return; view_->hide(); } bool QmlSettingsView::setSettingsProperty(const char *name, const QVariant &value) { if (!root_) return false; return root_->setProperty(name, value); } QVariant QmlSettingsView::settingsProperty(const char *name) { if (!root_) return false; return root_->property(name); } QQuickWindow *QmlSettingsView::parentWindow() const { return parentWindow_; }
The main purpose to create the code was to implement UI logic for separate plugins, that’s why its naming
Usage example:
#include "qmlsettingsview/qmlsettingsview.h" class GrayScaleFilterPluginSettings: public QmlSettingsView { Q_OBJECT public: GrayScaleFilterPluginSettings(QObject *parent = 0); virtual ~GrayScaleFilterPluginSettings(); void settingsFinished(); signals: void finished(); };
define your new class somewhere in the main code:
GrayScaleFilterPluginSettings qmlsettingsview;
implementation
GrayScaleFilterPluginSettings::GrayScaleFilterPluginSettings(QObject *parent): QmlSettingsView(parent) { } GrayScaleFilterPluginSettings::~GrayScaleFilterPluginSettings() { } void GrayScaleFilterPluginSettings::settingsFinished() { emit finished(); }
connect finished signal to your main class slot, which will deal with the settings etc
connect(&qmlsettingsview, SIGNAL(finished()), this, SLOT(settingsClosed()));
here we show and hide our settings
void GrayScaleFilterPlugin::setupItem(QQmlApplicationEngine *engine) { if (!engine) return; qmlsettingsview.setEngine(engine, "qrc:/gssettings.qml", "finished()"); qmlsettingsview.setSettingsProperty("width", qmlsettingsview.parentWindow()->width()); qmlsettingsview.setSettingsProperty("height", qmlsettingsview.parentWindow()->width()); qmlsettingsview.showSettings(); return; } void GrayScaleFilterPlugin::settingsClosed() { qmlsettingsview.hideSettings(); }
setEngine() sets QML engine, path to your settings qml file and name of signal when the settings are gets closed.
You can read new properties in settingsClosed() slot and save them to file
That’s actually it at the moment
Feel free to ask a questions
Do not hesitate to rework and clean up your code! Its always good practice to rethink what you have done before because everyone is evolving and what you thought best code solution yesterday, today becomes crappiest thing ever!
To help keep your code clean and organized let me introduce Qt plugins.
There is some documentation on how to create Qt plugins on Qt official site but lets go thru all steps again to make things clear.
So, step one: define plugin’s interface:
#ifndef PLUGININTERFACE_H #define PLUGININTERFACE_H #include <QtPlugin> QT_BEGIN_NAMESPACE class QString; QT_END_NAMESPACE class PluginInterface { public: virtual ~PluginInterface() {} virtual QString name() = 0; virtual QString description() = 0; }; QT_BEGIN_NAMESPACE #define PluginInterface_iid "org.cooldev.coolapp.PluginInterface/1.0" Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid) QT_END_NAMESPACE #endif // PLUGININTERFACE_H
as you can see, plugin interface is pure virtual class. Macro Q_DECLARE_INTERFACE tells to Qt all that it need to create Qt plugin. For sure, PluginInterface_iid must be an unique identifier
Great news for QtCreator users. Latest QtCreator IDE has a template for creating Qt plugins: just go to File->New file or Project->Libraries->C++ Library. Press ‘Choose…’. Select Type as ‘Qt plugin’, choose an name, press Next, choose your Qt version, Next, choose your plugins class name and choose base class (any of them, you’ll remove it later). QtCreator will create an plugin implementation for you.
Make sure that your plugin implementation base classes are QObject and your interface class:
class MyFirstPlugin : public QObject, public PluginInterface {
another important thing is to put Q_INTERFACES declaration before public part of your plugin’s class declaration:
class MyFirstPlugin : public QObject, public PluginInterface { Q_OBJECT Q_INTERFACES(PluginInterface)
Now lets get back to .pro file. QtCreator will create needed lines in the file:
TEMPLATE = lib CONFIG += plugin
Don’t forget about DESTDIR. Its important for packaging application for your destination platform
Ok. Plugin created and built. Now we have to load it from our application:
#include <QPluginLoader> PluginLoader::load() { QDir pluginsDir = QDir(qApp->applicationDirPath()); pluginsDir.cd("plugins"); //good practice to put plugins into 'plugins' folder near your application foreach (QString fileName, pluginsDir.entryList(QDir::Files)) { QPluginLoader loader(pluginsDir.absoluteFilePath(fileName)); QObject *plugin = loader.instance(); if (plugin) { PluginInterface *pluginInstance = qobject_cast<PluginInterface*>(plugin); if (pluginInstance) { qDebug() << "Plugin file " << fileName << " loaded ok."; // now the plugin can be initialized and used } else { qDebug() << "Plugin file " << fileName << " loading fail"; } } else { qDebug() << loader.errorString(); qDebug() << plugin; } } }
Two main points:
- Qt tries to load every file in ‘plugins’ folder as Qt plugin
- with casting loaded instance to your interface class you actually checking if the plugin is implementing exact this interface
That’s it for now
ps. Plugins can be derived from QObject, which makes possible to use signal-slot conception. As usual, there some tricks need to be done:
- Add your new plugin interface header file to HEADERS .pro file of your plugin implementation
- This works only for non-static Qt builds