Выбрать главу

Доступ к буферу обмена в Qt осуществляется при помощи статической функции QApplication::clipboard(). Вызывая функцию QClipboard::setText(), мы делаем текст доступным через буфер обмена; причем этот текст могут использовать и данное, и другие приложения, поддерживающие работу с простыми текстами. Применяемый нами формат со знаками табуляции и новой строки в качестве разделителей понятен многим приложениям, включая Excel от компании Microsoft.

Рис. 4.5. Копирование выделенных ячеек в буфер обмена.

Функция QTableWidget::selectedRange() возвращает список выделенных диапазонов. Мы знаем, что может быть не более одного диапазона, потому что мы задали в конструкторе режим выделения QAbstractItemView::ContiguousSelection. Для удобства мы определяем функцию selectedRange(), которая возвращает выделенный диапазон:

01 QTableWidgetSelectionRange Spreadsheet::selectedRange() const

02 {

03 QList<QTableWidgetSelectionRange> ranges = selectedRanges();

04 if (ranges.isEmpty())

05 return QTableWidgetSelectionRange();

06 return ranges.first();

07 }

Если выделение вообще имеет место, мы возвращаем первую (и единственную) выделенную область. Мы никогда не встретимся с ситуацией, когда не выбрано никакой области, поскольку в режиме ContiguousSelection текущая ячейка рассматривается как выделенная. Однако такую ситуацию мы все же обрабатываем, чтобы защититься от ошибки в нашей программе, приводящей к отсутствию текущей ячейки.

01 void Spreadsheet::paste()

02 {

03 QTableWidgetSelectionRange range = selectedRange();

04 QString str = QApplication::clipboard()->text();

05 QStringList rows = str.split('\n');

06 int numRows = rows.count();

07 int numColumns = rows.first().count('\t') + 1;

08 if (range.rowCount() * range.columnCount() != 1

09 && (range.rowCount() != numRows

10 || range.columnCount() !=numColumns)) {

11 QMessageBox::information(this, tr("Spreadsheet"),

12 tr("The information cannot be pasted because the copy "

13 "and paste areas aren't the same size."));

14 return;

15 }

16 for (int i = 0; i < numRows; ++i) {

17 QStringList columns = rows[i].split('\t');

18 for (int j = 0; j < numColumns; ++j) {

19 int row = range.topRow() + i;

20 int column = range.leftColumn() + j;

21 if (row < RowCount && column < ColumnCount)

22 setFormula(row, column, columns[j]);

23 }

24 }

25 somethingChanged();

26 }

Слот paste() соответствует пункту меню Edit | Paste (Правка | Вставить). Мы считываем текст из буфера обмена и вызываем статическую функцию QString::split() для разбиения строки и представления ее в виде списка QStringList. Каждая строка таблицы представлена в этом списке одной строкой.

Затем мы определяем размеры области копирования. Номер строки в таблице является номером строки в QStringList; номер столбца является номером символа табуляции в первой строке плюс 1. Если выделена только одна ячейка, мы используем ее в качестве верхнего левого угла области вставки; в противном случае мы используем текущую выделенную область для вставки.

При выполнении операции вставки мы в цикле проходим по строкам и разбиваем каждую строку на значения ячеек, снова используя функцию QString::split(), но теперь в качестве разделителя применяется знак табуляции. Рис. 4.6 иллюстрирует эти действия.

Рис. 4.6. Вставка текста из буфера обмена в электронную таблицу.

01 void Spreadsheet::del()

02 {

03 foreach (QTableWidgetltem *item, selectedItems())

04 delete item;

05 }

Слот del() соответствует пункту меню Edit | Delete (Правка | Удалить). Для очистки ячеек достаточно использовать оператор delete для каждого объекта Cell. Объект QTableWidget замечает, когда удаляются его элементы QTableWidgetltem, и автоматически перерисовывает себя, если какой-нибудь из элементов оказывается видимым. Если мы вызываем функцию cell(), указывая координаты удаленной ячейки, то она возвратит нулевой указатель.

01 void Spreadsheet::selectCurrentRow()

02 {

03 selectRow(currentRow());

04 }

05 void Spreadsheet::selectCurrentColumn()

06 {