Qt Components for the desktop

    This post is participating in the competition “ Smart Phones for Smart Posts ”.

    As you know, QML is based on graphic primitives and even trivial buttons have to be drawn from them (rectangle, gradient, text, mouse area, for example). To facilitate the process of creating UI, Qt Components were created. They allow you to create buttons, text fields, dropboxes and other controls for entering or displaying data. In the official release, components for
    Mobile platforms: Symbian and MeeGo. But Qt Labs also has a version for desktop platforms, which (after some time) will be included in Qt5, as the main means of creating a user interface (as we remember, QML comes first in Qt5, and QtGui comes second). At the same time, the components themselves adapt to the native look of the operating system.

    In order to show the capabilities of desktop components, and at the same time to outline the main problems and advantages of their use, I created a minimal graphical application on the classic QtGui and on components. No, not Hello World. Calculator. Without the implementation of calculations, just a graphical interface.



    Under the cat, launches under 3 operating systems and some discussions on the topic are collected.


    So, the calculator includes a display and two tabs with different buttons: a simple set (in the screenshot above) and an advanced one.


    We will deal with the code first.

    Qt Components Calculator


    The first and most interesting thing to know when working with components is that they do not use QmlApplicationViewer or QDeclarativeView explicitly. The Qml file is launched through the QDeclarativeEngine . And now the components themselves create a QDeclarativeView when it is needed (that is, when a new window is created). To facilitate the work, the QmlDesktopViewer class is located in the component repository , which is easy to connect to your project by connecting it to the general source tree and using it in main.cpp.
    #include 
    #include "qmldesktopviewer.h"
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QmlDesktopViewer *viewer = new QmlDesktopViewer();
        viewer->open("qrc:/main.qml");
        QObject::connect(&app, SIGNAL(lastWindowClosed()), viewer, SLOT(quit()));
        return app.exec();
    }
    


    Now let's turn to QML. Create the main.qml file, which will be launched when the application starts
    import QtQuick 1.1
    import QtDesktop 0.1
    Window {
        function buttonPressed(name, offset) {
            var text = display.text
            var pos = display.cursorPosition
            display.text = text.substr(0,pos) + name + text.substr(pos)
            display.cursorPosition = pos+name.length-offset
        }
        title: "Calc on Components"
        width: 400
        height: 600
        maximumHeight: 900
        minimumHeight: 250
        maximumWidth: 1000
        minimumWidth: 300
        visible: true
        id: mainWindow
        TextField {
            id: display
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.margins: 4
            height: 60; font.pixelSize: 40
        }
        TabFrame {
            id: frame
            position: "North"
            anchors.top: display.bottom
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.bottom: parent.bottom
            anchors.margins: 4
            Tab {
                id: simpleTab
                title: "Simple"
                anchors.margins: 4
                CalcButtonRow {
                    anchors.left: parent.left
                    anchors.right: parent.right
                    height: parent.height/4
                    anchors.top: parent.top
                    names: ["7","8","9","+"]
                    onButtonPressed: mainWindow.buttonPressed(name, 0)
                }
    // Еще 3 ряда
            }
    //Еще одна вкладка
        }
        Component.onCompleted: display.focus = true
    }
    

    I slightly shortened the source, but there are 125 lines in total in this file.

    So, the main element here is Window . It just creates a QDeclarativeView , which displays all its elements. For Window, you can set the title, height, width, maximum and minimum height and width, visibility. In general, the standard set for the window. The first element in the window is our display, implemented on TextField . If anyone has developed on mobile Qt Components, then this element should be familiar. It has approximately the same API as in mobile components.

    The next element is a TabFrame , which is eventually converted to a QTabWidget. We will add two Tab elements to this element (I have shortened one, it is exactly the same). The entire contents of the Tab will be displayed on this tab (that is, it is an analog of adding widgets to the tab widget or to its Layout in QtGui).

    CalcButtonRow in this case is our component that contains 4 buttons (with the names passed through the names property ) and stretches them in width and height so that the buttons occupy the entire space of the tab (the display turns out to be an analog of QGridLayout on the tab widget in QtGui). The solution is on the forehead and is subject to many problems in production, but it will do for the test.
    import QtQuick 1.0
    import QtDesktop 0.1
    Item {
        signal buttonPressed(string name)
        property variant names: ["","","",""]
        Button {
            anchors.left: parent.left
            anchors.top: parent.top
            anchors.bottom: parent.bottom
            width: parent.width/4
            text: names[0]
            onClicked: buttonPressed(text)
        }
    //Другие 3 кнопки
    }
    

    I reduced the source code again (43 lines in the original). Side buttons are positioned to the sides, central buttons - to the center of the parent element. All 4 with a quarter width of the parent element.
    Here we meet the Button element , which should also be familiar with mobile components. In the button handler, we emit a signal from our element with the text written on the button.

    Let's go back to main.qml
    // Вывод на дисплей
        function buttonPressed(name, offset) {
            var text = display.text
            var pos = display.cursorPosition
            display.text = text.substr(0,pos) + name + text.substr(pos)
            display.cursorPosition = pos+name.length-offset
        }
    // Обработчик для простых кнопок 
    onButtonPressed: mainWindow.buttonPressed(name, 0)
    // Обработчик для кнопок с функциями (sin(), cos() и т.д.)
    onButtonPressed: mainWindow.buttonPressed(name, 1)
    

    When a button is pressed , the buttonPressed function is called , which adds the button text to the line at the current cursor position and shifts it by the desired number of characters (for functions, this number is less by one, since the cursor should be inside the brackets, and not after them).

    This is the ENTIRE code. In total, we got about 160 qml lines.
    Similar code written in QtGui (without a designer, with the generation of all objects in the constructor in loops, with QSignalMapper and other ways to reduce the code for such forms) took about 130 lines of c ++ code (excluding main.cpp).

    That is, the amount of code is approximately equal. Let's look at the results in various OS

    Linux KDE4


    Everything is about the same, but. Buttons (different gradients) look a little different in the QML version, a small jamb with tabs rendering, the blue focus frame always lights up (on the QtGui version it disappears if the window is inactive), there are no animations when adding text to the text field and when switching tabs. Not bad.

    Windows 7


    In the QML version, again, a small jamb with tabs is displayed, again the focus frame is always visible and plus traces from the mouse hover on the buttons (which in the QtGui version, as they should be, disappear). Again, not bad.

    Mac OS X 10.6



    Traditionally a burning focus frame in the qml version, an ever-burning tab on an inactive window has been added to it. BUT. For Mac OS X, I had to slightly modify the application on QtGui, because when I launched it for the first time, the window looked like this.

    It was necessary for QLineEdit to explicitly specify minimumHeight. The QML version has not been redone.

    Goodies from using QML instead of QtGui


    You ask why we need these components, if there is QtGui. The answer is simple. To create a more pleasant and rich interface. I will not talk about the well-known features like kinetic scrolling, beautiful animations when changing objects, and all that.

    What can be added to the calculator UI? The first thing that comes to mind is the dependence of the font size on the display on the entered text. The more text, the smaller the font. Change for this our TextField with a display on
        TextField {
            function adaptFontSize() {
                var width = display.width
                var length = display.text.length
                var newFontSize = 40
                if (width/26 < length) {
                    newFontSize = 1.5*(display.width/display.text.length)
                    if (newFontSize < 20)
                        newFontSize = 20
                }
                display.font.pixelSize = newFontSize
            }
            id: display
            anchors.top: parent.top
            anchors.left: parent.left
            anchors.right: parent.right
            anchors.margins: 4
            height: 60; font.pixelSize: 40
            onWidthChanged: adaptFontSize()
            onTextChanged: adaptFontSize()
            Behavior on font.pixelSize { NumberAnimation{easing: Easing.OutElastic; duration: 200}}
        }
    

    As usual, the magic of QML in action. We added one function, two property change handlers and a Behavior element. And that's it, now we are changing the font dynamically, and even with the animation. How much does QtGui code take (exactly along with the animation)? A little more than 15 lines. Have to connect the Animation Framework.




    You can come up with many more examples where QML makes it easy to create UI applications for the desktop.

    The current state of Qt Components for the desktop


    Now this project is located somewhere in the alpha area and it is too early to talk about its widespread commercial application, but now it is working quite well and allows you to integrate QtGui widgets into the QML interface. Yes, of course, you can always insert them through proxying in QGraphicsObject, but it is much more complicated, it cuts down some of the possibilities for interacting with widgets and it takes more code. The screenshot shows 4 example launches from the components. They display the current status. That is, much can already be done. It is not visible in the screenshot, but the right button on the toolbar opens a new window.


    Pros and cons of using components instead of QtGui


    Pros:
    • Rich interface creation capabilities
    • Simplify the implementation of complex interfaces
    • The ability to use standard QML elements without having to create extra QDeclarativeView
    • Simplified application transfer to mobile devices (the common API for all components is very similar)
    • No platform dependency (QtGui is sometimes dependent. An example is visible on launch on Mac OS X)

    Minuses:
    • This is still deep alpha, a lot of minor and not very display bugs
    • The complication of interaction with the data layer (properties of the declarative context, plugins and other methods)
    • Unusual for those who did not deal with QML
    • Maybe not all (and I doubt that even in the release they will support all the functionality of QtGui)

    References



    Also popular now: