ээдд. Прохоренок_Н_А__Дронов_В_А_Python_3_и_PyQt_5_Разработка_приложен. Николай Прохоренок Владимир Дронов
Скачать 7.92 Mb.
|
QtCore.Qt , при сортировке регистр символов учитываться не будет, а если CaseSensitive — то будет; setSortLocaleAware(<Флаг>) — если в качестве параметра указать значение True , при сортировке будут учитываться настройки локали; setFilterFixedString(<Фрагмент>) — выбор из модели элементов, которые содержат заданный фрагмент. Если указать пустую строку, в результат попадут все строки из базовой модели. Метод является слотом; setFilterRegExp() — выбор из модели элементов, соответствующих указанному регу- лярному выражению. Если указать пустую строку, в результат попадут все строки из базовой модели. Форматы метода: setFilterRegExp( В первом формате указывается экземпляр класса QRegExp , а во втором — строка с шаб- лоном регулярного выражения. Второй формат метода является слотом; setFilterWildcard(<Шаблон>) — выбор из модели элементов, соответствующих указан- ной строке, которая может содержать подстановочные знаки: 528 Часть II. Библиотека PyQt 5 • ? — один любой символ; • * — нуль или более любых символов; • [...] — диапазон значений. Остальные символы трактуются как есть. Если в качестве параметра указать пустую строку, в результат попадут все элементы из базовой модели. Метод является слотом; setFilterKeyColumn(<Индекс>) — задает индекс столбца, по которому будет произво- диться фильтрация. Если в качестве параметра указать значение -1 , будут просматри- ваться элементы во всех столбцах. По умолчанию фильтрация производится по первому столбцу; setFilterRole(<Роль>) — задает роль (см. разд. 22.3), по которой производится фильт- рация. По умолчанию сортировка производится по роли DisplayRole ; setFilterCaseSensitivity(<Режим>) — если в качестве параметра указать атрибут CaseInsensitive класса QtCore.Qt , при фильтрации регистр символов учитываться не будет, а если CaseSensitive — то будет; setDynamicSortFilter(<Флаг>) — если в качестве параметра указано значение False , при изменении базовой модели не будет производиться повторная сортировка или фильт- рация. 22.8. Использование делегатов Все три представления, рассмотренные в разд. 22.5, дают возможность редактирования тек- ста их элементов. Например, в таблице (класс QTableView ) мы можем дважды щелкнуть мышью на любом элементе, после чего в нем появится поле ввода. Введем в это поле новый текст и нажмем клавишу За редактирование данных в представлении отвечает особый класс, называемый делегатом. Он создает компонент, в котором будет выполняться редактирование значения ( редактор), задает его параметры, заносит в него само редактируемое значение, а по окончании редак- тирования переносит его назад, в модель. По умолчанию в качестве делегата используется класс QItemDelegate из модуля QtWidgets А в качестве компонента-редактора применяется однострочное поле ввода (класс QLineEdit , рассмотренный нами в главе 21). Если мы хотим использовать для редактирования значения в каком-либо столбце или стро- ке другой редактор — например, многострочное поле ввода, поле ввода даты или целого числа, мы создадим другой делегат и назначим его представлению. Класс, представляющий делегат, должен быть унаследован от класса QStyledItemDelegate Иерархия наследования классов QItemDelegate и QStyledItemDelegate : QObject – QAbstractItemDelegate - QItemDelegate QObject – QAbstractItemDelegate - QStyledItemDelegate В новом классе-делегате нам следует переопределить следующие методы: createEditor() — создает компонент, который будет использоваться для редактирова- ния данных, и задает его параметры. Формат метода: createEditor(self, <Родитель>, <Настройки>, <Индекс>) Глава 22. Списки и таблицы 529 Вторым параметром передается ссылка на компонент-представление, который станет родителем создаваемого редактора (список, таблица или иерархический список). Треть- им параметром передается экземпляр класса QStyleOptionViewItem , хранящий дополни- тельные настройки делегата. Четвертым параметром можно получить индекс текущего элемента модели, представленный экземпляром класса QModelIndex Метод createEditor() должен создать компонент-редактор, задать для него в качестве родителя компонент-представление (он передается вторым параметром) и вернуть соз- данный компонент в качестве результата. Чтобы отказаться от использования собственного делегата и указать представлению ис- пользовать делегат по умолчанию, в методе createEditor() следует вернуть значение None ; setEditorData() — заносит в компонент-редактор, созданный в методе createEditor() , данные из текущего элемента модели, тем самым подготавливая редактор для редакти- рования этих данных. Формат метода: setEditorData(self, <Редактор>, <Индекс>) Вторым параметром передается компонент-редактор, а третьим — индекс текущего эле- мента модели в виде экземпляра класса QModelIndex ; updateEditorGeometry() — задает размеры редактора соответственно размерам области, отведенной под него в компоненте-представлении. Формат: updateEditorGeometry(self, <Редактор>, <Настройки>, <Индекс>) Вторым параметром передается ссылка на компонент-редактор, третьим — ссылка на экземпляр класса QStyleOptionViewItem , хранящий настройки делегата, четвертым — индекс текущего элемента модели, представленный экземпляром класса QModelIndex Размеры отведенной под редактор области мы можем получить из атрибута rect экземп- ляра класса QStyleOptionViewItem , переданного третьим параметром (полное описание класса QStyleOptionViewItem приведено на странице https://doc.qt.io/qt-5/qstyleoption viewitem.html, а описание класса QStyleOption , от которого он порожден, — на страни- це https://doc.qt.io/qt-5/qstyleoption.html); setModelData() — по окончании редактирования переносит значение из редактора в те- кущий элемент модели. Формат: setModelData(self, <Редактор>, <Модель>, <Индекс>) Вторым параметром передается ссылка на компонент-редактор, третьим — ссылка на модель, четвертым — индекс текущего элемента модели, представленный экземпляром класса QModelIndex Полное описание класса QAbstractItemDelegate можно найти на странице https://doc.qt.io/ qt-5/qabstractitemdelegate.html, класса QitemDelegate — на странице https://doc.qt.io/qt-5/ qitemdelegate.html, а класса QStyledItemDelegate — на странице https://doc.qt.io/qt-5/ qstyleditemdelegate.html. Для назначения делегатов представлению следует применять следующие методы, унаследо- ванные от класса QAbstractItemView : setItemDelegate( — назначает делегат для всего представления. В параметре передается класс делегата, унаследованный от класса QAbstractItemDelegate ; 530 Часть II. Библиотека PyQt 5 setItemDelegateForColumn(<Индекс столбца>, — назначает делегат для столбца представления с указанным индексом. В параметре передается класс делегата, унаследованный от класса QAbstractItemDelegate ; setItemDelegateForRow(<Индекс строки>, — назначает деле- гат для строки представления с указанным индексом. В параметре передается класс де- легата, унаследованный от класса QAbstractItemDelegate Если в какой-либо ячейке представления действуют одновременно два делегата, задан- ные для столбца и для строки, будет использоваться делегат, заданный для строки. В качестве примера рассмотрим небольшое складское приложение (листинг 22.4), позво- ляющее править количество каких-либо имеющихся на складе позиций с применением поля ввода целочисленных значений (класс QSpinBox ). Листинг 22.4. Использование делегата from PyQt5 import QtCore, QtWidgets, QtGui import sys # Создаем класс делегата class SpinBoxDelegate(QtWidgets.QStyledItemDelegate): def createEditor(self, parent, options, index): # Создаем компонент-редактор, используемый для правки значений # количества позиций editor = QtWidgets.QSpinBox(parent) editor.setFrame(False) editor.setMinimum(0) editor.setSingleStep(1) return editor def setEditorData(self, editor, index): # Заносим в компонент-редактор значение количества value = int(index.model().data(index, QtCore.Qt.EditRole)) editor.setValue(value) def updateEditorGeometry(self, editor, options, index): # Указываем размеры компонента-редактора editor.setGeometry(options.rect) def setModelData(self, editor, model, index): # Заносим исправленное значение количества в модель value = str(editor.value()) model.setData(index, value, QtCore.Qt.EditRole); app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QTableView() window.setWindowTitle("Использование делегата") sti = QtGui.QStandardItemModel(parent = window) lst1 = ['Дискета', 'Бумага для принтера', 'Барабан для принтера'] lst2 = ["10", "3", "8"] for row in range(0, 3): item1 = QtGui.QStandardItem(lst1[row]) item2 = QtGui.QStandardItem(lst2[row]) sti.appendRow([item1, item2]) Глава 22. Списки и таблицы 531 sti.setHorizontalHeaderLabels(['Товар', 'Кол-во']) window.setModel(sti) # Назначаем делегат второму столбцу таблицы window.setItemDelegateForColumn(1, SpinBoxDelegate()) window.setColumnWidth(0, 150) window.resize(300, 150) window.show() sys.exit(app.exec_()) Результат выполнения кода из листинга 22.4 показан на рис. 22.4. Рис. 22.4. Использование делегата ГЛ А В А 23 Работа с базами данных PyQt 5 включает в свой состав средства для работы с базами данных формата SQLite, MySQL, Oracle, PostgreSQL и др., не требующие установки никаких дополнительных Python-библиотек. С помощью этих средств мы можем выполнять любые SQL-запросы и обрабатывать их результаты, получать доступ к отдельным таблицам базы, работать с тран- закциями, а также использовать особые модели для вывода содержимого таблиц или запро- сов в любом из компонентов-представлений, рассмотренных в главе 22. В НИМАНИЕ ! Для успешного доступа к базам данных всех форматов, кроме SQLite и ODBC, требуется установить соответствующий клиент, поскольку в комплект поставки PyQt он не входит. Все классы, обеспечивающие работу с базами данных и рассмотренные в этой главе, опре- делены в модуле QtSql 23.1. Соединение с базой данных За соединение с базой данных и обработку транзакций отвечает класс QSqlDatabase Чтобы установить соединение с базой, следует вызвать статический метод addDatabase() этого класса. Формат вызова: addDatabase(<Формат базы данных>[, connectionName=""]) Первым параметром указывается строка, обозначающая формат открываемой базы данных. Поддерживаются следующие форматы: QMYSQL (MySQL), QODBC (ODBC), QPSQL (PostgreSQL), QSQLITE2 (SQLite версии 2) и QSQLITE (SQLite версии 3). Вторым параметром можно задать имя соединения, что может оказаться полезным, если приложение работает сразу с несколькими базами. Если имя соединения не указано, уста- навливаемое соединение будет помечено как используемое по умолчанию. Метод addDatabase() возвращает экземпляр класса QSqlDatabase , представляющий базу данных, с которой установлено соединение. Теперь мы можем задать параметры базы, вос- пользовавшись одним из приведенных далее методов QSqlDatabase : setHostName(<Хост>) — задает хост, на котором расположена база данных. Используется только для серверов данных наподобие MySQL; setPort(<Номер порта>) — задает номер порта, через который будет выполнено под- ключение к хосту. Используется только для серверов данных и лишь в том случае, если сервер настроен на использование порта, отличного от порта по умолчанию; Глава 23. Работа с базами данных 533 setDatabaseName(<Имя или путь к базе данных>) — задает имя базы данных (для серве- ров данных), путь к ней (для «настольных» баз данных, таких как SQLite) или полный набор параметров подключения (если используется ODBC); setUserName(<Имя>) — задает имя для подключения к базе. Используется только для серверов данных; setPassword(<Пароль>) — задает пароль для подключения к базе. Используется только для серверов данных; setConnectOptions(<Параметры>) — задает набор дополнительных параметров для под- ключения к базе в виде строки. Набор поддерживаемых дополнительных параметров различен в зависимости от выбранного формата и приведен в документации по классу QSqlDatabase Для работы с базой предназначены следующие методы класса QSqlDatabase : open() — открывает базу данных. Возвращает True , если база была успешно открыта, и False — в противном случае; В НИМАНИЕ ! Перед созданием соединения с базой данных обязательно следует создать объект прило- жения (экземпляр класса QApplication). Если этого не сделать, PyQt не сможет загрузить драйвер указанного формата баз данных, и соединение не будет создано. Открываемая база данных уже должна существовать на диске или сервере. Единственное исключение — база формата SQLite, которая, в случае ее отсутствия, будет создана авто- матически. open(<Имя>, <Пароль>) — открывает базу данных с указанными именем и паролем. Воз- вращает True , если база была успешно открыта, и False — в противном случае; isOpen() — возвращает True , если база данных в настоящее время открыта, и False — в противном случае; isOpenError() — возвращает True , если при попытке открытия базы данных возникли ошибки, и False — в противном случае; transaction() — запускает транзакцию, если формат базы поддерживает таковые. Если же формат базы не поддерживает транзакции, то не делает ничего. Возвращает True , если транзакция была успешно запущена, и False — в противном случае; commit() — завершает транзакцию, если формат базы поддерживает таковые. Если же формат базы не поддерживает транзакции, то не делает ничего. Возвращает True , если транзакция была успешно завершена, и False — в противном случае; rollback() — отменяет транзакцию, если формат базы поддерживает таковые. Если же формат базы не поддерживает транзакции, то не делает ничего. Возвращает True , если транзакция была успешно отменена, и False — в противном случае; lastError() — возвращает сведения о последней возникшей при работе с базой ошибке в виде экземпляра класса QSqlError ; connectionName() — возвращает строку с именем соединения с базой или пустую строку для соединения по умолчанию; tables([type=Tables]) — возвращает список таблиц, хранящихся в базе. В параметре type можно указать тип таблиц в виде одного из атрибутов класса QSql или их комбина- ции через оператор | : 534 Часть II. Библиотека PyQt 5 • Tables — 1 — обычные таблицы; • SystemTables — 2 — служебные таблицы; • Views — 4 — представления; • AllTables — 255 — все здесь указанное; record(<Имя таблицы>) — возвращает сведения о структуре таблицы с переданным име- нем, представленные экземпляром класса QSqlRecord , или пустой экземпляр этого клас- са, если таблицы с таким именем нет; primaryIndex(<Имя таблицы>) — возвращает сведения о ключевом индексе таблицы с переданным именем, представленные экземпляром класса QSqlIndex , или пустой эк- земпляр этого класса, если таблицы с таким именем нет; close() — закрывает базу данных. Также нам могут пригодиться следующие статические методы класса QSqlDatabase : contains([connectionName=""]) — возвращает True , если имеется соединение с базой данных с указанным именем, и False — в противном случае; connectionNames() — возвращает список имен всех созданных соединений с базами данных. Соединение по умолчанию обозначается пустой строкой; database([connectionName=""][, ][open=True]) — возвращает сведения о соединении с базой данных, имеющем указанное имя, в виде экземпляра класса QSqlDatabase . Если в параметре open указано значение True , база данных будет открыта. Если такового соеди- нения нет, возвращается некорректно сформированный экземпляр класса QSqlDatabase ; cloneDatabase( — создает копию указанного в пер- вом параметре соединения с базой и дает ему имя, заданное во втором параметре. Воз- вращаемый результат — экземпляр класса QSqlDatabase , представляющий созданную копию соединения; removeDatabase(<Имя соединения>) — удаляет соединение с указанным именем. Соеди- нение по умолчанию обозначается пустой строкой; isDriverAvailable(<Формат>) — возвращает True , если указанный в виде строки формат баз данных поддерживается PyQt, и False — в противном случае; drivers() — возвращает список всех поддерживаемых PyQt форматов баз данных. В листинге 23.1 показан код, выполняющий соединение с базами данных различных форма- тов и их открытие. Листинг 23.1. Соединение с базами данных различных форматов from PyQt5 import QtWidgets, QtSql import sys # Создаем объект приложения, иначе поддержка баз данных не будет работать app = QtWidgets.QApplication(sys.argv) # Открываем базу данных SQLite, находящуюся в той же папке, что и файл # с этой программой con1 = QtSql.QSqlDatabase.addDatabase('QSQLITE') con1.setDatabaseName('data.sqlite') Глава 23. Работа с базами данных 535 con1.open() con1.close() # Открываем базу данных MySQL con2 = QtSql.QSqlDatabase.addDatabase('QMYSQL') con2.setHostName("somehost"); con2.setDatabaseName("somedb"); con2.setUserName("someuser"); con2.setPassword("password"); con2.open(); con2.close() # Открываем базу данных Microsoft Access через ODBC con3 = QtSql.QSqlDatabase.addDatabase("QODBC"); con3.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb)}; |