aboutsummaryrefslogtreecommitdiffstats
path: root/sources/pyside2/doc/tutorials/qmlsqlintegration
diff options
context:
space:
mode:
Diffstat (limited to 'sources/pyside2/doc/tutorials/qmlsqlintegration')
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml127
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.pngbin6954 -> 0 bytes
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/main.py85
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst223
-rw-r--r--sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py146
5 files changed, 0 insertions, 581 deletions
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml b/sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml
deleted file mode 100644
index 487f5b36c..000000000
--- a/sources/pyside2/doc/tutorials/qmlsqlintegration/chat.qml
+++ /dev/null
@@ -1,127 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the examples of Qt for Python.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.12
-import QtQuick.Layouts 1.12
-import QtQuick.Controls 2.12
-
-ApplicationWindow {
- id: window
- title: qsTr("Chat")
- width: 640
- height: 960
- visible: true
- ColumnLayout {
- anchors.fill: parent
-
- ListView {
- id: listView
- Layout.fillWidth: true
- Layout.fillHeight: true
- Layout.margins: pane.leftPadding + messageField.leftPadding
- displayMarginBeginning: 40
- displayMarginEnd: 40
- verticalLayoutDirection: ListView.BottomToTop
- spacing: 12
- model: chat_model
- delegate: Column {
- readonly property bool sentByMe: model.recipient !== "Me"
- anchors.right: sentByMe ? parent.right : undefined
- spacing: 6
-
- Row {
- id: messageRow
- spacing: 6
- anchors.right: sentByMe ? parent.right : undefined
-
- Rectangle {
- width: Math.min(messageText.implicitWidth + 24, listView.width - messageRow.spacing)
- height: messageText.implicitHeight + 24
- radius: 15
- color: sentByMe ? "lightgrey" : "#ff627c"
-
- Label {
- id: messageText
- text: model.message
- color: sentByMe ? "black" : "white"
- anchors.fill: parent
- anchors.margins: 12
- wrapMode: Label.Wrap
- }
- }
- }
-
- Label {
- id: timestampText
- text: Qt.formatDateTime(model.timestamp, "d MMM hh:mm")
- color: "lightgrey"
- anchors.right: sentByMe ? parent.right : undefined
- }
- }
-
- ScrollBar.vertical: ScrollBar {}
- }
-
- Pane {
- id: pane
- Layout.fillWidth: true
-
- RowLayout {
- width: parent.width
-
- TextArea {
- id: messageField
- Layout.fillWidth: true
- placeholderText: qsTr("Compose message")
- wrapMode: TextArea.Wrap
- }
-
- Button {
- id: sendButton
- text: qsTr("Send")
- enabled: messageField.length > 0
- onClicked: {
- chat_model.send_message("machine", messageField.text, "Me");
- messageField.text = "";
- }
- }
- }
- }
- }
-}
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.png b/sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.png
deleted file mode 100644
index a0c189665..000000000
--- a/sources/pyside2/doc/tutorials/qmlsqlintegration/example_list_view.png
+++ /dev/null
Binary files differ
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/main.py b/sources/pyside2/doc/tutorials/qmlsqlintegration/main.py
deleted file mode 100644
index c710e019a..000000000
--- a/sources/pyside2/doc/tutorials/qmlsqlintegration/main.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#############################################################################
-##
-## Copyright (C) 2019 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of the Qt for Python project.
-##
-## $QT_BEGIN_LICENSE:LGPL$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU Lesser General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU Lesser
-## General Public License version 3 as published by the Free Software
-## Foundation and appearing in the file LICENSE.LGPL3 included in the
-## packaging of this file. Please review the following information to
-## ensure the GNU Lesser General Public License version 3 requirements
-## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 2.0 or (at your option) the GNU General
-## Public license version 3 or any later version approved by the KDE Free
-## Qt Foundation. The licenses are as published by the Free Software
-## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-2.0.html and
-## https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-import logging
-
-from PySide2.QtCore import QDir, QFile, QUrl
-from PySide2.QtGui import QGuiApplication
-from PySide2.QtQml import QQmlApplicationEngine
-from PySide2.QtSql import QSqlDatabase
-
-from sqlDialog import SqlConversationModel
-
-logging.basicConfig(filename="chat.log", level=logging.DEBUG)
-logger = logging.getLogger("logger")
-
-
-def connectToDatabase():
- database = QSqlDatabase.database()
- if not database.isValid():
- database = QSqlDatabase.addDatabase("QSQLITE")
- if not database.isValid():
- logger.error("Cannot add database")
-
- write_dir = QDir()
- if not write_dir.mkpath("."):
- logger.error("Failed to create writable directory")
-
- # Ensure that we have a writable location on all devices.
- filename = "{}/chat-database.sqlite3".format(write_dir.absolutePath())
-
- # When using the SQLite driver, open() will create the SQLite
- # database if it doesn't exist.
- database.setDatabaseName(filename)
- if not database.open():
- logger.error("Cannot open database")
- QFile.remove(filename)
-
-
-if __name__ == "__main__":
- app = QGuiApplication()
- connectToDatabase()
- sql_conversation_model = SqlConversationModel()
-
- engine = QQmlApplicationEngine()
- # Export pertinent objects to QML
- engine.rootContext().setContextProperty("chat_model", sql_conversation_model)
- engine.load(QUrl("chat.qml"))
-
- app.exec_()
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst b/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst
deleted file mode 100644
index c26d154ac..000000000
--- a/sources/pyside2/doc/tutorials/qmlsqlintegration/qmlsqlintegration.rst
+++ /dev/null
@@ -1,223 +0,0 @@
-QML, SQL and PySide Integration Tutorial
-########################################
-
-This tutorial is very similar to the `Qt Chat Tutorial`_ one but it focuses on explaining how to
-integrate a SQL database into a PySide2 application using QML for its UI.
-
-.. _`Qt Chat Tutorial`: https://doc.qt.io/qt-5/qtquickcontrols-chattutorial-example.html
-
-sqlDialog.py
-------------
-
-We import the pertinent libraries to our program, define a global variable that hold the
-name of our table, and define the global function ``createTable()`` that creates a new table if it
-doesn't already exist.
-The database contains a single line to mock the beginning of a conversation.
-
- .. literalinclude:: sqlDialog.py
- :linenos:
- :lines: 40-77
-
-The ``SqlConversationModel`` class offers the read-only data model required for the non-editable
-contacts list. It derives from the :ref:`QSqlQueryModel` class, which is the logical choice for
-this use case.
-Then, we proceed to create the table, set its name to the one defined previously with the
-:meth:`~.QSqlTableModel.setTable` method.
-We add the necessary attributes to the table, to have a program that reflects the idea
-of a chat application.
-
- .. literalinclude:: sqlDialog.py
- :linenos:
- :lines: 80-91
-
-In ``setRecipient()``, you set a filter over the returned results from the database, and
-emit a signal every time the recipient of the message changes.
-
- .. literalinclude:: sqlDialog.py
- :linenos:
- :lines: 93-103
-
-The ``data()`` function falls back to ``QSqlTableModel``'s implementation if the role is not a
-custom user role.
-If you get a user role, we can subtract :meth:`~.QtCore.Qt.UserRole` from it to get the index of
-that field, and then use that index to find the value to be returned.
-
- .. literalinclude:: sqlDialog.py
- :linenos:
- :lines: 105-112
-
-
-In ``roleNames()``, we return a Python dictionary with our custom role and role names as key-values
-pairs, so we can use these roles in QML.
-Alternatively, it can be useful to declare an Enum to hold all of the role values.
-Note that ``names`` has to be a hash to be used as a dictionary key,
-and that's why we're using the ``hash`` function.
-
- .. literalinclude:: sqlDialog.py
- :linenos:
- :lines: 114-128
-
-The ``send_message()`` function uses the given recipient and message to insert a new record into
-the database.
-Using :meth:`~.QSqlTableModel.OnManualSubmit` requires you to also call ``submitAll()``,
-since all the changes will be cached in the model until you do so.
-
- .. literalinclude:: sqlDialog.py
- :linenos:
- :lines: 130-146
-
-chat.qml
---------
-
-Let's look at the ``chat.qml`` file.
-
- .. literalinclude:: chat.qml
- :linenos:
- :lines: 40-42
-
-First, import the Qt Quick module.
-This gives us access to graphical primitives such as Item, Rectangle, Text, and so on.
-For a full list of types, see the `Qt Quick QML Types`_ documentation.
-We then add QtQuick.Layouts import, which we'll cover shortly.
-
-Next, import the Qt Quick Controls module.
-Among other things, this provides access to ``ApplicationWindow``, which replaces the existing
-root type, Window:
-
-Let's step through the ``chat.qml`` file.
-
- .. literalinclude:: chat.qml
- :linenos:
- :lines: 44-49
-
-``ApplicationWindow`` is a Window with some added convenience for creating a header and a footer.
-It also provides the foundation for popups and supports some basic styling, such as the background
-color.
-
-There are three properties that are almost always set when using ApplicationWindow: ``width``,
-``height``, and ``visible``.
-Once we've set these, we have a properly sized, empty window ready to be filled with content.
-
-There are two ways of laying out items in QML: `Item Positioners`_ and `Qt Quick Layouts`_.
-* Item positioners (`Row`_, `Column`_, and so on) are useful for situations where the size of items
- is known or fixed, and all that is required is to neatly position them in a certain formation.
-* The layouts in Qt Quick Layouts can both position and resize items, making them well suited for
- resizable user interfaces.
- Below, we use `ColumnLayout`_ to vertically lay out a `ListView`_ and a `Pane`_.
-
- .. literalinclude:: chat.qml
- :linenos:
- :lines: 50-53
-
-Pane is basically a rectangle whose color comes from the application's style.
-It's similar to `Frame`_, but it has no stroke around its border.
-
-Items that are direct children of a layout have various `attached properties`_ available to them.
-We use `Layout.fillWidth`_ and `Layout.fillHeight`_ on the `ListView`_ to ensure that it takes as
-much space within the `ColumnLayout`_ as it can, and the same is done for the Pane.
-As `ColumnLayout`_ is a vertical layout, there aren't any items to the left or right of each child,
-so this results in each item consuming the entire width of the layout.
-
-On the other hand, the `Layout.fillHeight`_ statement in the `ListView`_ enables it to occupy the
-remaining space that is left after accommodating the Pane.
-
-.. _Item Positioners: https://doc.qt.io/qt-5/qtquick-positioning-layouts.html
-.. _Qt Quick Layouts: https://doc.qt.io/qt-5/qtquicklayouts-index.html
-.. _Row: https://doc.qt.io/qt-5/qml-qtquick-row.html
-.. _Column: https://doc.qt.io/qt-5/qml-qtquick-column.html
-.. _ColumnLayout: https://doc.qt.io/qt-5/qml-qtquick-layouts-columnlayout.html
-.. _ListView: https://doc.qt.io/qt-5/qml-qtquick-listview.html
-.. _Pane: https://doc.qt.io/qt-5/qml-qtquick-controls2-pane.html
-.. _Frame: https://doc.qt.io/qt-5/qml-qtquick-controls2-frame.html
-.. _attached properties: https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html
-.. _Layout.fillWidth: https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html#fillWidth-attached-prop
-.. _Layout.fillHeight: https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html#fillHeight-attached-prop
-.. _ListView: https://doc.qt.io/qt-5/qml-qtquick-listview.html
-.. _Qt Quick QML Types: https://doc.qt.io/qt-5/qtquick-qmlmodule.html
-
-Let's look at the ``Listview`` in detail:
-
- .. literalinclude:: chat.qml
- :linenos:
- :lines: 53-99
-
-After filling the ``width`` and ``height`` of its parent, we also set some margins on the view.
-
-
-Next, we set `displayMarginBeginning`_ and `displayMarginEnd`_.
-These properties ensure that the delegates outside the view don't disappear when you
-scroll at the edges of the view.
-To get a better understanding, consider commenting out the properties and then rerun your code.
-Now watch what happens when you scroll the view.
-
-We then flip the vertical direction of the view, so that first items are at the bottom.
-
-Additionally, messages sent by the contact should be distinguished from those sent by a contact.
-For now, when a message is sent by you, we set a ``sentByMe`` property, to alternate between
-different contacts.
-Using this property, we distinguish between different contacts in two ways:
-
-* Messages sent by the contact are aligned to the right side of the screen by setting
- ``anchors.right`` to ``parent.right``.
-* We change the color of the rectangle depending on the contact.
- Since we don't want to display dark text on a dark background, and vice versa, we also set the
- text color depending on who the contact is.
-
-At the bottom of the screen, we place a `TextArea`_ item to allow multi-line text input, and a
-button to send the message.
-We use Pane to cover the area under these two items:
-
- .. literalinclude:: chat.qml
- :linenos:
- :lines: 101-125
-
-The `TextArea`_ should fill the available width of the screen.
-We assign some placeholder text to provide a visual cue to the contact as to where they should begin
-typing.
-The text within the input area is wrapped to ensure that it does not go outside of the screen.
-
-Lastly, we have a button that allows us to call the ``send_message`` method we defined on
-``sqlDialog.py``, since we're just having a mock up example here and there is only one possible
-recipient and one possible sender for this conversation we're just using strings here.
-
-.. _displayMarginBeginning: https://doc.qt.io/qt-5/qml-qtquick-listview.html#displayMarginBeginning-prop
-.. _displayMarginEnd: https://doc.qt.io/qt-5/qml-qtquick-listview.html#displayMarginEnd-prop
-.. _TextArea: https://doc.qt.io/qt-5/qml-qtquick-controls2-textarea.html
-
-
-main.py
--------
-
-We use ``logging`` instead of Python's ``print()``, because it provides a better way to control the
-messages levels that our application will generate (errors, warnings, and information messages).
-
- .. literalinclude:: main.py
- :linenos:
- :lines: 40-50
-
-``connectToDatabase()`` creates a connection with the SQLite database, creating the actual file
-if it doesn't already exist.
-
- .. literalinclude:: main.py
- :linenos:
- :lines: 53-72
-
-
-
-A few interesting things happen in the ``main`` function:
-* Declaring a :ref:`QGuiApplication`.
- You should use a :ref:`QGuiApplication` instead of :ref:`QApplication` because we're not
- using the **QtWidgets** module.
-* Connecting to the database,
-* Declaring a :ref:`QQmlApplicationEngine`.
- This allows you to access the QML context property to connect Python
- and QML from the conversation model we built on ``sqlDialog.py``.
-* Loading the ``.qml`` file that defines the UI.
-
-Finally, the Qt application runs, and your program starts.
-
- .. literalinclude:: main.py
- :linenos:
- :lines: 75-85
-
-.. image:: example_list_view.png
diff --git a/sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py b/sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py
deleted file mode 100644
index 6a9ff8234..000000000
--- a/sources/pyside2/doc/tutorials/qmlsqlintegration/sqlDialog.py
+++ /dev/null
@@ -1,146 +0,0 @@
-#############################################################################
-##
-## Copyright (C) 2019 The Qt Company Ltd.
-## Contact: https://www.qt.io/licensing/
-##
-## This file is part of the Qt for Python project.
-##
-## $QT_BEGIN_LICENSE:LGPL$
-## Commercial License Usage
-## Licensees holding valid commercial Qt licenses may use this file in
-## accordance with the commercial license agreement provided with the
-## Software or, alternatively, in accordance with the terms contained in
-## a written agreement between you and The Qt Company. For licensing terms
-## and conditions see https://www.qt.io/terms-conditions. For further
-## information use the contact form at https://www.qt.io/contact-us.
-##
-## GNU Lesser General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU Lesser
-## General Public License version 3 as published by the Free Software
-## Foundation and appearing in the file LICENSE.LGPL3 included in the
-## packaging of this file. Please review the following information to
-## ensure the GNU Lesser General Public License version 3 requirements
-## will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-##
-## GNU General Public License Usage
-## Alternatively, this file may be used under the terms of the GNU
-## General Public License version 2.0 or (at your option) the GNU General
-## Public license version 3 or any later version approved by the KDE Free
-## Qt Foundation. The licenses are as published by the Free Software
-## Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-## included in the packaging of this file. Please review the following
-## information to ensure the GNU General Public License requirements will
-## be met: https://www.gnu.org/licenses/gpl-2.0.html and
-## https://www.gnu.org/licenses/gpl-3.0.html.
-##
-## $QT_END_LICENSE$
-##
-#############################################################################
-
-import datetime
-import logging
-
-from PySide2.QtCore import Qt, Slot
-from PySide2.QtSql import QSqlDatabase, QSqlQuery, QSqlRecord, QSqlTableModel
-
-table_name = "Conversations"
-
-
-def createTable():
- if table_name in QSqlDatabase.database().tables():
- return
-
- query = QSqlQuery()
- if not query.exec_(
- """
- CREATE TABLE IF NOT EXISTS 'Conversations' (
- 'author' TEXT NOT NULL,
- 'recipient' TEXT NOT NULL,
- 'timestamp' TEXT NOT NULL,
- 'message' TEXT NOT NULL,
- FOREIGN KEY('author') REFERENCES Contacts ( name ),
- FOREIGN KEY('recipient') REFERENCES Contacts ( name )
- )
- """
- ):
- logging.error("Failed to query database")
-
- # This adds the first message from the Bot
- # and further development is required to make it interactive.
- query.exec_(
- """
- INSERT INTO Conversations VALUES(
- 'machine', 'Me', '2019-01-07T14:36:06', 'Hello!'
- )
- """
- )
- logging.info(query)
-
-
-class SqlConversationModel(QSqlTableModel):
- def __init__(self, parent=None):
- super(SqlConversationModel, self).__init__(parent)
-
- createTable()
- self.setTable(table_name)
- self.setSort(2, Qt.DescendingOrder)
- self.setEditStrategy(QSqlTableModel.OnManualSubmit)
- self.recipient = ""
-
- self.select()
- logging.debug("Table was loaded successfully.")
-
- def setRecipient(self, recipient):
- if recipient == self.recipient:
- pass
-
- self.recipient = recipient
-
- filter_str = (
- "(recipient = '{}' AND author = 'Me') OR " "(recipient = 'Me' AND author='{}')"
- ).format(self.recipient)
- self.setFilter(filter_str)
- self.select()
-
- def data(self, index, role):
- if role < Qt.UserRole:
- return QSqlTableModel.data(self, index, role)
-
- sql_record = QSqlRecord()
- sql_record = self.record(index.row())
-
- return sql_record.value(role - Qt.UserRole)
-
- def roleNames(self):
- """Converts dict to hash because that's the result expected
- by QSqlTableModel"""
- names = {}
- author = "author".encode()
- recipient = "recipient".encode()
- timestamp = "timestamp".encode()
- message = "message".encode()
-
- names[hash(Qt.UserRole)] = author
- names[hash(Qt.UserRole + 1)] = recipient
- names[hash(Qt.UserRole + 2)] = timestamp
- names[hash(Qt.UserRole + 3)] = message
-
- return names
-
- def send_message(self, recipient, message, author):
- timestamp = datetime.datetime.now()
-
- new_record = self.record()
- new_record.setValue("author", author)
- new_record.setValue("recipient", recipient)
- new_record.setValue("timestamp", str(timestamp))
- new_record.setValue("message", message)
-
- logging.debug('Message: "{}" \n Received by: "{}"'.format(message, recipient))
-
- if not self.insertRecord(self.rowCount(), new_record):
- logging.error("Failed to send message: {}".format(self.lastError().text()))
- return
-
- self.submitAll()
- self.select()