Qt сохранение в excel
This page discusses various available options for working with Microsoft Excel documents in your Qt application. Please also read the general considerations outlined on the Handling Document Formats page.
One needs to distinguish between two different formats (this page deals with both of them):
Legacy "Excel Spreadsheet" format | "Office Open XML Workbook" format | |
---|---|---|
classification: | binary BIFF-based | XML-based |
main filename extension: | .xls | .xlsx |
main internet media type: | application/vnd.ms-excel | application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
default format of Excel: | until Excel 2003 | since Excel 2007 |
Contents
Reading / Writing
Using Excel itself
If you are exclusively targeting the Windows platform and Microsoft Excel will be installed on all target machines, then you can use Qt's ActiveX framework to access Excel's spreadsheet processing functionality through OLE automation. For an introductory code example (and a way to list the API provided by the Excel COM object), consult this how-to.
DLL file name | COM object name | platforms | license | |
---|---|---|---|---|
Microsoft Excel | ? | Excel.Application | Windows | commercial |
Using ODBC
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "xlsx_connection"); db.setDatabaseName("DRIVER=;DBQ=" + QString("c:\\path\\to\\your\\file\\file.xlsx")); if(db.open())
The above code print all of column1's values to the debug output. It works for *.xls and *.xlsx and the other excel file formats.
By default OBDC uses the first row as names for the columns, you are supposed to be able to change this with the 'FirstRowHasNames' option in the connection settings, however there is a bug (see KB288343). Keep in mind that you are using a database and that each column has his own datatype, so if your second row contains text and your third row contains numbers, sql will pick one of these datatypes. If a few rows contain text and the rest of them contain floating numbers, sql will make the text appear and will make the numbers disappear.
Using independent parser/writer libraries
For a more portable solution, you could take a look at some of the available third-party C/C++ libraries for parsing/writing Excel files:
Note that these libraries differ in their scope and general approach to the problem.
Using manual XML processing
Files using the XML-based (.xlsx) format could be processed using Qt's XML handling classes (see Handling Document Formats). Third-party libraries can help you in dealing with the container format that wraps the actual XML files:
API | supported platforms | license | |
---|---|---|---|
libopc | C | Win, Mac, Linux, … | permissive |
Using batch conversion tools
Краткое руководство по чтению и написанию Excel в Qt
Многие увидят, как читать и писать в Excel QAxObject При выполнении операции многие люди обнаружат проблему, попробовав ее, что происходит медленно, очень медленно! Так много людей приходят к выводу, что QAxObject Метод чтения и записи excel нежелателен и неэффективен. Чтобы
Позже я попытался использовать ODBC и другие интерфейсы типа базы данных для чтения и записи.Даже если бы я столкнулся с китайскими сбоями, скорость чтения слишком большого Excel все равно была бы медленной. Чтобы
Наконец, прочитав некоторый открытый исходный код, я обнаружил, что для чтения Excel под Windows я все еще использую QAxObject Самый быстрый! Да, просто используйте QAxObject Самое быстрое чтение и письмо! ! ! (Прочитать 100000 ячеек за 229 мс)
Когда вы будете читать Excel в будущем (под win), вам не нужно рассматривать другие методы, используйте QAxObject Ничего страшного, рычаги скорости, медленные из-за ошибки! Поговорим о том, как повысить эффективность чтения.
Я не буду здесь говорить о том, как открыть или создать Excel, а сосредоточусь на том, как быстро читать в Excel. Чтобы
Метод работы с Excel с Qt можно найти в Интернете, и чтение выполняется с использованием метода, подобного следующему:
Основная причина медленного чтения: sheet->querySubObject("Cells(int, int)", row, col)
Представьте, что есть 10000 единиц и вам нужно 10 000 звонить querySubObject , 90% руководств в Интернете не говорят об этом querySubObject произведено QAxObject* Лучше удалить вручную, хотя в родительском QAxObject Он будет управлять своей памятью, но родительский объект не будет уничтожен, а дочерний объект не будет уничтожен.Если он вызывается 10 000 раз, будет создано 10 000. QAxObject Объект
Выгода отQT быстро читает файлы Excel с большим объемом данныхВ этой статье ниже описывается, как быстро читать и писать в Excel.
Принцип - один звонок querySubObject Прочитать все данные в память
Может использоваться в VBA UsedRange Вернуть все использованные диапазоны ячеек и использовать атрибуты Value Получите все значения этих ячеек.
На данный момент полученное значение представляет собой таблицу, но Qt превращает ее в переменную QVariant для хранения, которая фактически является QList<QList<QVariant> > , Чтобы манипулировать содержимым в это время, вам нужно поставить это QVariant Преобразовать в QList<QList<QVariant> >
Сначала посмотрите на функцию для получения всей ячейки (здесь ExcelBase - это пакет классов для чтения и записи в Excel):
Код this->sheet Это лист, который был открыт и используется при получении содержимого. this->sheet->querySubObject("UsedRange"); Вы можете получить все диапазоны.
Следующая функция castVariant2ListListVariant помещает QVariant Преобразовать в QList<QList<QVariant> >
Чтобы все содержимое Excel было преобразовано в QList<QList<QVariant>> Сохранить где QList<QList<QVariant> > в QList<QVariant> Для содержимого каждой строки строки помещаются в самый внешний QList по порядку.
Для Excel следующим образом:
После чтения QList<QList<QVariant> > Структура следующая:
Давайте посмотрим, насколько высока скорость чтения этого Excel
Вот Excel с 1000 строками, 100 столбцами и в общей сложности 100 000 ячеек. На открытие потребовалось некоторое время, а на чтение 100 000 ячеек ушло 229 миллисекунд.
Код чтения выглядит следующим образом: (полный исходный код см. Ниже)
Приведенные выше m_xls и m_datas являются переменными-членами:
Чтение, требующее много времени:
100000 - это всего 0,2 секунды
Точно так же может пройти QAxObject *usedRange = this->sheet->querySubObject("UsedRange"); Добейтесь быстрого чтения и быстрого письма
Перед быстрым написанием нужно получить диапазон записанной ячейки: Range(const QString&)
Если A1 в excel - это первая строка и первый столбец, то A1: B2 - это диапазон от первой строки, первого столбца, до второй строки, второго столбца.
Чтобы записать в этот диапазон, также через соответствующий QList<QList<QVariant> > , Подробнее см. Следующий код:
Эта функция предназначена для записи данных из A1
В функции convertToColName Чтобы преобразовать количество столбцов в количество столбцов, представленных буквами в excel, эта функция реализована рекурсией:
Взгляните на время, необходимое для написания Excel:
Для записи 100000 данных требуется 262 мсек, и это очень быстро и эффективно.
Модули xlrd и xlwt обязательных для изучения модулей Python (обработка файлов Excel)
Каталог статей
1. Введение
В работе Python excel в основном используются две библиотеки: xlrd и xlwt, то есть xlrd предназначен для чтения Excel, а xlwt - для записи библиотеки Excel.
Модуль xlrd: может читать таблицы .xls, .xlsx
Модуль xlwt: может записывать в таблицу .xls (Невозможно записать файлы .xlsx! ! !)
2. Способ установки
Модуль xlrd и модуль xlwt не являются встроенными модулями и должны быть установлены вручную.
Три, описание формы Excel
Эти два модуля очень интуитивно понятны для определения структуры таблицы Excel, и обычные привычки использования таблицы Excel в основном одинаковы.
Есть три уровня:Книга-Лист-Ячейка。
- Книга - это файл с расширением .xls / .xlsx.
- В книге есть несколько листов, к которым можно получить доступ по индексу или имени.
- Рабочий лист содержит несколько строк и несколько столбцов.Основной единицей на пересечении строк и столбцов является ячейка, а содержимое записывается в ячейку. Доступ к ячейкам можно получить по индексу строки и столбца.
В питонеКнига-Лист-Ячейка, Как объект
- WorkBook: объект Workbook
- Лист: объект формы
- Ячейка: объект таблицы
Четыре, xlrd читает файлы Excel
4.1 Получение объекта WorkBook
параметр: Имя файла - это путь к открываемому файлу электронной таблицы.
возвращаемое значение: Объект xlrd.book.Book
4.1 объект таблицы операций xlrd
В одном Excel может быть несколько листов, тогда вы можете получить нужную информацию о листе следующими способами.
метод | Функции |
---|---|
workbook.sheet_names() | Получите названия всех листов и сохраните их в виде списка |
workbook.sheet_by_index(1) | Получить объект листа по индексу |
workbook.sheets() | Получить все объекты листа |
sheet.nrows | Получить все строки указанного листа |
sheet.ncols | Получить количество всех столбцов на указанном листе |
workbook.sheet_by_name(‘sheet’) | Получить объект листа в соответствии с именем листа |
Файл операции (score table.xlsx):
Пример кода:
4.2 объект ячейки операции xlrd
метод | Функции |
---|---|
sheet.cell(row,col) | Получить объект ячейки указанной строки и столбца |
sheet.row_slice(row,start_col,end_col) | Получить объект ячейки определенного столбца указанной строки. |
sheet.col_slice(col,start_row,end_row) | Получить объект ячейки из нескольких строк указанного столбца. |
sheet.cell_value(row,col) | Получить значение указанной строки и столбца. |
sheet.row_values(row,start_col,end_col) | Получение значений определенных столбцов указанной строки является расширенным использованием sheet.row_slice. |
sheet.col_values(col,start_row,end_row) | Получение значения нескольких строк указанного столбца - это расширенное использование sheet.col_slice. |
Пример кода:
Тип данных ячейки
метод | описание | возвращаемое значение |
---|---|---|
xlrd.XL_CELL_TEXT(Text) | Тип текста | 1 |
xlrd.XL_CELL_NUMBER(Number) | Числовой тип | 2 |
xlrd.XL_CELL_DATE(Date) | Тип даты и времени | 3 |
xlrd.XL_CELL_BOOLEAN(Bool) | Логический тип | 4 |
xlrd.XL_CELL_EMPTY | Пустой тип данных | 0 |
Пример кода:
Пять, xlwt записывает в файл Excel
5.1 Простые рабочие шаги
Импортируйте модуль xlwt.
Создайте объект Workbook.
Создайте объект Sheet.
Запишите данные в указанную строку и столбец под Листом. Если вы хотите добавить новую ячейку к исходному объекту книги, вам нужно вызвать put_cell, чтобы добавить ее.
Сохранить как файл Excel
5.2 Справочник по общему API
Объект книги
- кодировка: установите кодировку символов, по умолчанию - ascii, замените на utf-8, и выведите китайский язык в excel.
- style_compression: указывает, нужно ли сжимать, обычно не используется.
Общие методы объектов Workbook
метод | параметр | возвращаемое значение | Функции |
---|---|---|---|
add_sheet(sheetname,cell_overwrite_ok = False ) | sheetname -Имя, используемое для этого рабочего листаcell_overwrite_ok Указывает, можно ли перезаписать ячейку, по умолчанию - False | Добавить в объект рабочего листа | Создайте рабочий лист в книге |
save(filename_or_stream ) | filename_or_stream - Это строка, содержащая имя файла, файл Excel будет сохранен (записан) на диск с указанным именем. | нет | Сохраните книгу как файл в локальном формате Excel |
Атрибуты книги
Атрибуты | Функции |
---|---|
Owner | Установить владельца документа |
country_code | Код страны |
wnd_protect | Защита окон |
backup_on_save | Бэкап при сохранении |
tabs_visible | видна ли вкладка |
dates_1904 | Следует ли использовать систему дат 1904 года |
use_cell_values | Значение ячейки |
default_style | Стиль по умолчанию |
colour_RGB | цвет |
vscroll_visible | Видна ли вертикальная полоса прокрутки |
hscroll_visible | Видна ли горизонтальная полоса прокрутки |
wnd_mini | Свернуть окно |
wnd_visible | Видно ли окно |
tab_width | ширина табуляции |
active_sheet | Лист деятельности |
Height | высота |
Width | ширина |
Hpos | Абсцисса |
Vpos | Ось Y |
Protect | защита |
obj_protect | Защита объекта |
Простой пример:
5.3 Пример кода
5.4 Установка стилей для Excel
1. Создайте таблицу и получите объект рабочего листа.
2. Установите ширину столбца, cols_num - количество столбцов.
3. Установите высоту строки.
4. Установите стиль ячейки Excel.
5. Записываем данные в ячейку.
6. Дополнение
При установке цвета шрифта или цвета фона ячейки вы можете использовать параметр 0x0D в исходном коде для представления разных цветов или вы можете использовать 0-127 для представления разных цветов.
В предыдущей части я рассказывал о создании модуля для запуска SQL-запросов и оболочки, в которой эти модули запускаются. После недолгой работы с запросами возникает очевидный вопрос — а как воспользоваться результатом выборки, кроме как посмотреть на экране?
Для этого стоит сделать дополнительные инструменты экспорта и копирования данных. Экспортировать будем в файл в формате Excel, а копировать в системный буфер в формате HTML.
Но для начала прилепим к нашему главному окну панель инструментов.
Панель инструментов
Напомню, что наше приложение призвано быть простым, универсальным и расширяемым. Чтобы тулбар тоже сделать универсальным и расширяемым, вынесем его определение в файл конфигурации, а выполняемые функции будут находиться во внешних модулях, явно не импортируемых в модуле тулбара. Таким образом добавление новой кнопки и функции сведется к прописыванию их в конфигурационном файле и добавлению модуля в каталог программы.
Для панелей инструментов в Qt есть готовый класс QToolBar, от него породим свой ToolBar. Сейчас нам достаточно одного тулбара, но заложимся на возможность добавления в программу нескольких панелей. Каждой панели нужен свой конфигурационный файл со своим набором кнопок, поэтому имя файла будем передавать параметром при создании тулбара.
Конфигурационный файл будет традиционно в формате Ini и кодировке UTF-8.
Синтаксис определения кнопок в наших руках, в простейшем случае нам нужны три вещи:
— текст на кнопке
— модуль, содержащий функцию кнопки
— функция кнопки
Определимся, что функция кнопки принимает один параметр — текущее дочернее окно. Что именно будет делать модуль с ним — задача модуля кнопки, а задача тулбара ограничивается только его вызовом.
Создадим такой файл tools.ini:
Теперь в питоне разбираем определения из Ini-файла:
Метод выполнения, назначенный всем кнопкам, будет импортировать нужный модуль и вызывать из него назначенную кнопке функцию. Чтобы нам не прописывать каждый модуль в перечне импорта тулбара, воспользуемся библиотекой importlib. Осталось только узнать, что за кнопка была нажата и от какого QAction пришел сигнал — за это отвечает стандартный метод QObject.sender(), далее возьмем сохраненные в нем параметры и сделаем то, что задумано в модуле (что бы это ни было).
Осталось добавить нашу панель в наше главное окно (модуль tasktree.py)
Можем запустить и проверить, появилась ли панель:
Может быть не так симпатично, как на первой картинке, главное, что работает.
Модуль функций инструментов
Теперь самое время сделать модуль с функциями кнопок. Модуль у нас будет один, потому что функции экспорта и копирования будут работать с одним источником данных и по одинаковым правилам, нет смысла разносить их по разным модулям.
Наши функции будут работать с таблицами данных QTableView, который мы использовали в модулях для просмотра результатов запроса. Чтобы сохранить независимость модулей, определять нужный компонент будем «на лету» — либо это текущий выбранный (focused) компонент QTableView в текущем окне, либо первый попавшийся нужного класса среди дочерних элементов текущего окна.
Из таблицы получаем список выбранных ячеек. Если ничего не выбрано, то принудительно выбираем всё.
Наверное, вы уже в курсе, что в Qt вы не получаете массив данных напрямую, вместо этого вы работаете с индексами в модели. Индекс QModelIndex представляет собой простую структуру и указывает на конкретную позицию данных (строку row() и столбец column(), а в иерархии указание на индекс родителя parent()). Получив индекс, можно из него получить сами данные методом data().
Мы получили список индексов выбранных ячеек в модели, но индексы в этом списке следуют в том порядке, в котором пользователь их выделял, а не отсортированные по строкам и столбцам. Нам же удобнее будет работать не со списком, а с словарем (позиция → индекс) и сортированными списками задействованных строк и столбцов.
Еще стоит учесть, что QTableView по умолчанию позволяет выделять несвязанные ячейки, потому в списке индексов могут быть ячейки, практически случайно расположенные:
Поэтому в d.rows есть каждая использованная строка, в d.columns есть каждый использованный столбец, но их сочетание необязательно есть в d.indexes.
Еще нам для пущей красоты нужен перечень наименований столбцов, который выводятся в QTableView. Получим их из модели методом headerData:
До сих пор код для экспорта и копирования был одинаковым, но теперь пошли различия.
Экспорт в Excel
Для экспорта в файлы Excel я воспользовался пакетом xlsxwriter. Он устанавливается, как обычно, через pip:
Документация пакета вполне подробная и понятная, с примерами, поэтому останавливаться на нем не буду. Суть в том, что запись идет по ячейкам, адресуемым по номеру строки и столбца. Если нужно дополнительное форматирование, то нужно определить стиль и указывать его при записи ячейки.
Имя xlsx-файла, в который будем экспортировать, запросим у пользователя, у Qt есть такая функция. В PyQt функция возвращает список из выбранного имени файла и использованного фильтра. Если вернулся список из пустых строк, то это означает, что пользователь отказался от выбора.
Танцы вокруг QDateTime добавлены из-за разного понимания даты/времени в Python, Qt и Excel — во-первых, пакет xlsxwriter умеет работать с питоновским datetime, но не умеет с QDateTime из Qt, поэтому приходится дополнительно его конвертировать специальной функцией toPyDateTime; во-вторых, Excel умеет работать только с датами с 01.01.1900, а всё, что было до этого времени для Excel — просто строка.
Результат экспорта в Excel:
Копирование в системный буфер в формате HTML
Не всегда нужен отдельный файл с выборкой, часто, особенно когда данных немного, удобнее скопировать их в табличном виде в системный буфер (clipboard), а затем вставить в нужное место, будь то Excel, Word, редактор веб-страниц или что-то другое.
Наиболее универсальным способом копирования табличных данных через буфер — это обычный формат HTML. В Windows, *nix и MacOS сильно разные способы работы с буфером (не говоря о том, что их несколько), поэтому хорошо, что Qt скрывает от нас детали реализации.
Всё, что нам нужно — создать объект QMimeData, заполнить его через метод setHtml фрагментом HTML-разметки, и отдать в системный clipboard, который доступен через QApplication
Таблицу собираем построчно, начиная с заголовков.
Результат, вставленный в Word:
Здесь границы таблицы видны только благодаря включенной в Word настройке "Показывать границы текста", на самом деле они невидимы. Чтобы таблица копировалась с явными границами, нужно изменить стиль таблицы в тэге table. Предоставляю это сделать вам.
Заключение
Итак, мы получили способ добавления в наш инструмент новых функций, причем функции добавляются и работают независимо от того, какими источниками данных мы будем пользоваться и как их отображать — модули, работающие с данными, ничего не знают о тулбарах и их функциях, тулбары не связаны ни с модулями данных, ни с функциями кнопок, а функции кнопок, не зная ни о тулбарах, ни о модулях данных, просто пытаются обработать текущий визуальный компонент известным им способом.
Исходники, использованные в примерах, как и ранее, выложены на github под лицензией MIT.
Читайте также: