diff options
Diffstat (limited to 'sources/pyside6/doc/tutorials/modelviewprogramming')
3 files changed, 416 insertions, 0 deletions
diff --git a/sources/pyside6/doc/tutorials/modelviewprogramming/qlistview-dnd.py b/sources/pyside6/doc/tutorials/modelviewprogramming/qlistview-dnd.py new file mode 100644 index 000000000..cebc99447 --- /dev/null +++ b/sources/pyside6/doc/tutorials/modelviewprogramming/qlistview-dnd.py @@ -0,0 +1,174 @@ +############################################################################# +## +## Copyright (C) 2022 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import sys + +from PySide6.QtWidgets import (QAbstractItemView, QApplication, QMainWindow, + QListView) +from PySide6.QtCore import (QByteArray, QDataStream, QIODevice, QMimeData, + QModelIndex, QStringListModel, Qt) + + +class DragDropListModel(QStringListModel): + """A simple model that uses a QStringList as its data source.""" + + def __init__(self, strings, parent=None): + super().__init__(strings, parent) + +#! [0] + + def canDropMimeData(self, data, action, row, column, parent): + if not data.hasFormat("application/vnd.text.list"): + return False + + if column > 0: + return False + + return True +#! [0] +#! [1] + def dropMimeData(self, data, action, row, column, parent): + if not self.canDropMimeData(data, action, row, column, parent): + return False + + if action == Qt.IgnoreAction: + return True +#! [1] + +#! [2] + begin_row = 0 + + if row != -1: + begin_row = row +#! [2] #! [3] + elif parent.isValid(): + begin_row = parent.row() +#! [3] #! [4] + else: + begin_row = self.rowCount(QModelIndex()) +#! [4] + +#! [5] + encoded_data = data.data("application/vnd.text.list") + stream = QDataStream(encoded_data, QIODevice.ReadOnly) + new_items = [] + while not stream.atEnd(): + new_items.append(stream.readQString()) +#! [5] + +#! [6] + self.insertRows(begin_row, len(new_items), QModelIndex()) + for text in new_items: + idx = self.index(begin_row, 0, QModelIndex()) + self.setData(idx, text) + begin_row += 1 + + return True +#! [6] + +#! [7] + def flags(self, index): + default_flags = super().flags(index) + if index.isValid(): + return Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled | default_flags + return Qt.ItemIsDropEnabled | default_flags +#! [7] + +#! [8] + def mimeData(self, indexes): + mime_data = QMimeData() + encoded_data = QByteArray() + stream = QDataStream(encoded_data, QIODevice.WriteOnly) + for index in indexes: + if index.isValid(): + text = self.data(index, Qt.DisplayRole) + stream.writeQString(text) + + mime_data.setData("application/vnd.text.list", encoded_data) + return mime_data +#! [8] + +#! [9] + def mimeTypes(self): + return ["application/vnd.text.list"] +#! [9] + +#! [10] + def supportedDropActions(self): + return Qt.CopyAction | Qt.MoveAction +#! [10] + + +class MainWindow(QMainWindow): + + def __init__(self, parent=None): + super().__init__(parent) + + file_menu = self.menuBar().addMenu("&File") + quit_action = file_menu.addAction("E&xit") + quit_action.setShortcut("Ctrl+Q") + +#! [mainwindow0] + self._list_view = QListView(self) + self._list_view.setSelectionMode(QAbstractItemView.ExtendedSelection) + self._list_view.setDragEnabled(True) + self._list_view.setAcceptDrops(True) + self._list_view.setDropIndicatorShown(True) +#! [mainwindow0] + + quit_action.triggered.connect(self.close) + + self.setup_list_items() + + self.setCentralWidget(self._list_view) + self.setWindowTitle("List View") + + def setup_list_items(self): + items = ["Oak", "Fir", "Pine", "Birch", "Hazel", "Redwood", "Sycamore", + "Chestnut", "Mahogany"] + model = DragDropListModel(items, self) + self._list_view.setModel(model) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec()) diff --git a/sources/pyside6/doc/tutorials/modelviewprogramming/simplemodel-use.py b/sources/pyside6/doc/tutorials/modelviewprogramming/simplemodel-use.py new file mode 100644 index 000000000..503834aaf --- /dev/null +++ b/sources/pyside6/doc/tutorials/modelviewprogramming/simplemodel-use.py @@ -0,0 +1,81 @@ +############################################################################# +## +## Copyright (C) 2022 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import sys + +from PySide6.QtWidgets import (QApplication, QFileSystemModel, QLabel, + QVBoxLayout, QWidget) +from PySide6.QtGui import QPalette +from PySide6.QtCore import QDir, Qt + + +if __name__ == '__main__': + app = QApplication(sys.argv) + + window = QWidget() + layout = QVBoxLayout(window) + title = QLabel("Some items from the directory model", window) + title.setBackgroundRole(QPalette.Base) + title.setMargin(8) + layout.addWidget(title) + +#! [0] + model = QFileSystemModel() + model.setRootPath(QDir.currentPath()) + + def on_directory_loaded(directory): + parent_index = model.index(directory) + num_rows = model.rowCount(parent_index) +#! [1] + for row in range(num_rows): + index = model.index(row, 0, parent_index) +#! [1] +#! [2] + text = model.data(index, Qt.DisplayRole) +#! [2] + label = QLabel(text, window) + layout.addWidget(label) + + model.directoryLoaded.connect(on_directory_loaded) +#! [0] + + window.setWindowTitle("A simple model example") + window.show() + sys.exit(app.exec()) diff --git a/sources/pyside6/doc/tutorials/modelviewprogramming/stringlistmodel.py b/sources/pyside6/doc/tutorials/modelviewprogramming/stringlistmodel.py new file mode 100644 index 000000000..9d3631f62 --- /dev/null +++ b/sources/pyside6/doc/tutorials/modelviewprogramming/stringlistmodel.py @@ -0,0 +1,161 @@ +############################################################################# +## +## Copyright (C) 2022 The Qt Company Ltd. +## Contact: https://www.qt.io/licensing/ +## +## This file is part of the Qt for Python examples of the Qt Toolkit. +## +## $QT_BEGIN_LICENSE:BSD$ +## You may use this file under the terms of the BSD license as follows: +## +## "Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are +## met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in +## the documentation and/or other materials provided with the +## distribution. +## * Neither the name of The Qt Company Ltd nor the names of its +## contributors may be used to endorse or promote products derived +## from this software without specific prior written permission. +## +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +## +## $QT_END_LICENSE$ +## +############################################################################# + +import sys + +from PySide6.QtWidgets import (QApplication, QListView) +from PySide6.QtCore import QAbstractListModel, QStringListModel, QModelIndex, Qt + + +#! [0] +class StringListModel(QAbstractListModel): + def __init__(self, strings, parent=None): + super().__init__(parent) + self._strings = strings + +#! [0] + def rowCount(self, parent=QModelIndex()): + """Returns the number of items in the string list as the number of rows + in the model.""" + return len(self._strings) +#! [0] + +#! [1] + def data(self, index, role): + """Returns an appropriate value for the requested data. + If the view requests an invalid index, an invalid variant is returned. + Any valid index that corresponds to a string in the list causes that + string to be returned.""" + row = index.row() + if not index.isValid() or row >= len(self._strings): + return None + if role != Qt.DisplayRole and role != Qt.EditRole: + return None + return self._strings[row] +#! [1] + +#! [2] + def headerData(self, section, orientation, role=Qt.DisplayRole): + """Returns the appropriate header string depending on the orientation of + the header and the section. If anything other than the display role is + requested, we return an invalid variant.""" + if role != Qt.DisplayRole: + return None + if orientation == Qt.Horizontal: + return f"Column {section}" + return f"Row {section}" +#! [2] + +#! [3] + def flags(self, index): + """Returns an appropriate value for the item's flags. Valid items are + enabled, selectable, and editable.""" + + if not index.isValid(): + return Qt.ItemIsEnabled + return super().flags(index) | Qt.ItemIsEditable +#! [3] + + #! [4] + def setData(self, index, value, role=Qt.EditRole): + """Changes an item in the string list, but only if the following conditions + are met: + + # The index supplied is valid. + # The index corresponds to an item to be shown in a view. + # The role associated with editing text is specified. + + The dataChanged() signal is emitted if the item is changed.""" + + if index.isValid() and role == Qt.EditRole: + self._strings[index.row()] = value + self.dataChanged.emit(index, index, {role}) + return True +#! [4] #! [5] + return False +#! [5] + +#! [6] + def insertRows(self, position, rows, parent): + """Inserts a number of rows into the model at the specified position.""" + self.beginInsertRows(QModelIndex(), position, position + rows - 1) + for row in range(rows): + self._strings.insert(position, "") + self.endInsertRows() + return True +#! [6] #! [7] +#! [7] + +#! [8] + def removeRows(self, position, rows, parent): + """Removes a number of rows from the model at the specified position.""" + self.beginRemoveRows(QModelIndex(), position, position + rows - 1) + for row in range(rows): + del self._strings[position] + self.endRemoveRows() + return True +#! [8] #! [9] +#! [9] + + +#! [main0] +if __name__ == '__main__': + app = QApplication(sys.argv) + +#! [main1] + numbers = ["One", "Two", "Three", "Four", "Five"] + model = StringListModel(numbers) +#! [main0] #! [main1] #! [main2] #! [main3] + view = QListView() +#! [main2] + view.setWindowTitle("View onto a string list model") +#! [main4] + view.setModel(model) +#! [main3] #! [main4] + + model.insertRows(5, 7, QModelIndex()) + for row in range(5, 12): + index = model.index(row, 0, QModelIndex()) + model.setData(index, f"{row+1}") + +#! [main5] + view.show() + sys.exit(app.exec()) +#! [main5] |