Цель лекции: Научиться создавать приложения, поддерживающие обмен данными путём использования буфера обмена целевой операционной системы, а также механизма "перетащил и бросил" (drag and drop)
Одной из часто возникающих пользовательских задач является обмен данными между приложениями, либо частями одного приложения. Помимо загрузки данных из файлов, это реализуется использованием буфера обмена (
Буфер обмена — это специальный буферный участок памяти компьютера, выделяемый операционной системой для временного хранения переносимых данных. Он позволяет вырезать, копировать и вставлять данные как внутри одного приложения, так и между разными приложениями.
Как дополнение к буферу обмена реализуется механизм перетаскивания, который заключается в перемещении мышью информации из одного объекта в другой. Например, можно перемещать между папками файлы, а также другие папки, сбрасывать файлы из файлового менеджера на соответствующие приложения, запуская процедуры обработки содержащейся информации.
Рассмотрим оба эти способа обмена данными на примере одной программы, простейшего текстового редактора. Он будет поддерживать основные операции работы с буфером обмена целевой операционной системы (вырезать, скопировать, вставить), а также открытие текстовых файлов для редактирования посредством механизма "drag and drop".
В основе механизма перетаскивания лежат две операции: захвата и собственно перетаскивания и сброса. Виджет может быть при этом как источником перемещения информации, так и её приёмником.
Для поддержки в приложении Juce приёма сбрасываемых данных, класс компонента, отвечающего за это, должен быть унаследован либо от класса DragAndDropTarget (в случае, если виджет служит приёмником информации от других частей приложения), либо от FileDragAndDropTarget (в случае, если происходит обмен данными между программами).
Создадим класс ).
#ifndef _TTextEditor_h_
#define _TTextEditor_h_
//--------------------------------------------------
#include "../JuceLibraryCode/JuceHeader.h"
//--------------------------------------------------
// Класс текстового редактора - приёмника информации при выполнении
// операции перетаскивания
class TTextEditor : public TextEditor,
public FileDragAndDropTarget
{
public:
TTextEditor(const String sComponentName = L"TextEditor");
~TTextEditor();
// Проверяет, необходимо ли обрабатывать сброшенные файлы
bool isInterestedInFileDrag(const StringArray);
// Функция обработки файлов, сброшенных на компонент
void filesDropped(const StringArray, int, int);
};
//---------------------------------------------------
#endif
Класс FileDragAndDropTarget включает две чистые виртуальные функции:
virtual bool FileDragAndDropTarget::isInterestedInFileDrag(const StringArray files) — вызывается для проверки, заинтересован ли компонент-приёмник в обработке предлагаемого набора перетаскиваемых файлов files. Принимаемый параметр — абсолютные пути к этому набору файлов. В том случае, если метод возвращает true, компонент должен выполнять какие-то действия, связанные с этим типом объектов;virtual void FileDragAndDropTarget::filesDropped(const StringArray files, int x, int y) — вызывается, когда пользователь сбросил файлы на компонент, после чего над этими файлами можно совершать какие-то действия. Первый параметр метода аналогичен таковому у предыдущей функции. Параметры x и y содержат координаты указателя мыши относительно компонента-приёмника.Помимо вышеперечисленных, класс FileDragAndDropTarget включает ряд других виртуальных методов:
virtual void FileDragAndDropTarget::fileDragEnter(const StringArray files, int x, int y) — вызывается, когда пользователь начинает перетаскивать над компонентом файлы;virtual void FileDragAndDropTarget::fileDragMove(const StringArray files, int x, int y) — вызывается, когда пользователь перетаскивает над компонентом файлы (т.е. данный метод объединяет действие функций fileDragEnter и fileDragExit).Однако для нашего примера достаточно написать реализацию методов ).
#include "TTextEditor.h"
//---------------------------------------------------
#define tr(s) String::fromUTF8(s)
//---------------------------------------------------
TTextEditor::TTextEditor(const String sComponentName)
: TextEditor(sComponentName)
{
Font NewFont(20.0);
this->setFont(NewFont);
this->setMultiLine(true);
this->setReturnKeyStartsNewLine(true);
this->setReadOnly(false);
this->setScrollbarsShown(true);
this->setCaretVisible(true);
this->setPopupMenuEnabled(true);
this->setText(String::empty);
}
//----------------------------------------------------
TTextEditor::~TTextEditor()
{
}
//----------------------------------------------------
bool TTextEditor::isInterestedInFileDrag(const StringArray)
{
// Обрабатываются любые файлы
return true;
}
//----------------------------------------------------
void TTextEditor::filesDropped(const StringArray sFiles, int iX, int iY)
{
// Получаем брошенный на компонент файл
// по пути к нему
File DroppedFile(sFiles[0]);
// Если это текстовый файл...
if(DroppedFile.getFileExtension() == ".txt")
{
// выводим его содержимое на компонент
FileInputStream Input(DroppedFile);
this->setText(Input.readEntireStreamAsString());
repaint();
}
// Иначе выводим предупреждение
else AlertWindow::showMessageBox(
AlertWindow::WarningIcon,
tr("Ошибка"),
tr("Неподдерживаемый тип файла!"),
tr("Принять"), 0
);
}
//----------------------------------------------
Как видно из листинга, после того, как пользователь бросил на наш компонент ).
Помимо текстового редактора, компонент содержимого нашей программы будет включать меню, содержащее пункты ). Описание работы с меню см. в лекции 15 .
(рис 20.1) Работа простейшего текстового редактора с поддержкой drag and drop
Объявление класса компонента содержимого представлено в листинге 20.3 .
#ifndef _TCentralComponent_h_
#define _TCentralComponent_h_
//--------------------------------------------------
#include "../JuceLibraryCode/JuceHeader.h"
//--------------------------------------------------
class TTextEditor;
//--------------------------------------------------
// Класс компонента содержимого.
// Наследует класс модели меню
class TCentralComponent : public Component,
public MenuBarModel
{
public:
TCentralComponent();
~TCentralComponent();
// Идентификаторы команд меню
enum TMenuOptions
{
FileOpen = 1, // Открыть файл
FileQuit = 2, // Завершить работу с программой
EditCut = 3, // Вырезать текст
EditCopy = 4, // Скопировать текст в буфер
EditPaste = 5 // Вставить текст из буфера
};
void paint(Graphics);
void resized();
// Функции, наследуемые от MenuBarModel
const StringArray getMenuBarNames();
void menuItemSelected(int, int);
private:
// Наш текстовый редактор
// с поддержкой drag and drop
TTextEditor* pTextEditor;
// Изображения - пиктограммы меню
Image ImageOpen_png;
Image ImageExit_png;
Image ImageCut_png;
Image ImageCopy_png;
Image ImagePaste_png;
// Предотвращает создание копии конструктора и оператора =
TCentralComponent(const TCentralComponent);
const TCentralComponent operator= (const TCentralComponent);
};
//-----------------------------------------------
#endif
Как мы знаем из лекции 8 , класс TextEditor включает собственные методы вырезания (cut), копирования (copy) и вставки (paste) информции, однако в Juce имеется специальный класс для работы с буфером обмена целевой операционной системы, SystemClipboard. Последний содержит два метода:
static void SystemClipboard::copyTextToClipboard(const String text) — копирует текст text в буфер обмена;static const String SystemClipboard::getTextFromClipboard() — вставляет текст из буфера.Для того, чтобы вырезать текст в буфер, мы вначале копируем в буфер обмена выделенный пользователем текст с помощью метода ).
void TCentralComponent::menuItemSelected(int iMenuItemID, int iTopLevelMenuIndex)
{
// Обработчики команд меню
switch(iMenuItemID)
{
// Если выбран пункт "Выход"...
case FileQuit:
{
// Завершаем работу программы
JUCEApplication::quit();
break;
}
// Если выбран пункт "Открыть"...
case FileOpen:
{
// Задаём в качестве стартовой директории для поиска файла
// папку "Документы" текущего пользователя
File InitialFile;
InitialFile =
InitialFile.getSpecialLocation(File::userDocumentsDirectory);
// В качестве фильтра поиска файлов задаём текстовый файл
WildcardFileFilter TextFileFilter(
"*.txt",
String::empty,
tr("Текстовые файлы")
);
// Компонент для отображения списка файлов
FileBrowserComponent FileBrowser(
FileBrowserComponent::openMode |
FileBrowserComponent::canSelectFiles,
InitialFile, TextFileFilter, NULL);
// Диалог для отображения FileBrowser
FileChooserDialogBox OpenFileDialog(
tr("Открыть файл"),
tr("Выберите текстовый файл, который вы хотите открыть..."),
FileBrowser, false, Colours::azure
);
OpenFileDialog.setSize(600, 400);
// Если пользователь выбрал файл...
if(OpenFileDialog.show())
{
// открываем его
InitialFile = FileBrowser.getSelectedFile(0);
FileInputStream Input(InitialFile);
pTextEditor->setText(Input.readEntireStreamAsString());
}
}
// Если выбран пункт "Вырезать"...
case EditCut:
{
// Работает аналогично pTextEditor->cut();
SystemClipboard::copyTextToClipboard(
pTextEditor->getHighlightedText());
pTextEditor->insertTextAtCaret(String::empty);
break;
}
// Если выбран пункт "Копировать"...
case EditCopy:
{
// Работает аналогично pTextEditor->copy();
SystemClipboard::copyTextToClipboard(
pTextEditor->getHighlightedText());
break;
}
// Если выбран пункт "Вставить"...
case EditPaste:
{
// Работает аналогично pTextEditor->paste();
pTextEditor->insertTextAtCaret(
SystemClipboard::getTextFromClipboard());
break;
}
}
Реализацию механизма drag and drop, связанную с обменом данными между двумя частями одной и той же программы показывает демонстрационное приложение ).
(рис 20.2) Работа демонстрационного приложения Juce (демонстрируется технология drag and drop между частями одного приложения)
Посмотреть реализацию примера можно, перейдя в папку <каталог Juce>/juce/extras/JuceDemo/Source/demos и открыв файл DragAndDropDemo.cpp.
Виджет в правом нижнем углу программы, как понятно, наследует классу DragAndDropTarget. Его функции-члены аналогичны описанным выше для FileDragAndDropTarget: носят те же имена и выполняют те же действия, за исключением метода virtual void DragAndDropTarget::itemDropped(const String sourceDescription, Component* sourceComponent, int x, int y). Подобно методу filesDropped класса FileDragAndDropTarget, он вызывается тогда, когда пользователь бросил что-либо на компонент-приёмник. В качестве источника перетаскиваемых объектов для DragAndDropTarget выступает виджет класса, унаследованного от DragAndDropContainer. Последний обеспечивает возможность перетаскивания для своих дочерних компонентов, а также блоков текста.
В демонстрационном приложении Juce субкомпонентами виджета, унаследованного от DragAndDropContainer, являются как список — источник перетаскиваемых объектов, так и виджет-приёмник, класс которого наследует DragAndDropTarget.
Для того чтобы начать перетаскивание, любой субкомпонент может просто вызвать метод void DragAndDropContainer::startDragging(const var sourceDescription, Component* sourceComponent, const Image dragImage = Image::null, bool allowDraggingToOtherJuceWindows = false, const Point<int>* imageOffsetFromMouse = nullptr) для того, чтобы вступить во взаимодействие с объектом класса, унаследованного от DragAndDropTarget.
Метод принимает следующие параметры:
sourceDescription — строка или какая-либо переменная, используемая для описания перетаскиваемого объекта. Она передаётся компоненту-приёмнику;sourceComponent — перетаскиваемый компонент;dragImage — изображение, появляющееся под указателем мыши при перетаскивании. Если параметр принимает нулевое значение, вместо этого будет отображаться миниатюра перетаскиваемого объекта;allowDraggingToOtherJuceWindows — в случае, если параметр принимает значение true, перетаскиваемый компонент отображается как отдельное окно окружения рабочего стола, которое может быть перетащено на объект класса, унаследованного от DragAndDropTargets, как родительского компонента, так и другого приложения;imageOffsetFromMouse — если параметр dragImage не является нулевым изображением, то значение этого параметра задаёт смещение пиктограммы от указателя мыши. Если параметр не задан, то указатель мыши будет располагаться в центре изображения. Если dragImage — нулевое изображение, то этот параметр будет проигнорирован.DragAndDropContainer:static bool DragAndDropContainer::performExternalDragDropOfFiles(const StringArray files, bool canMoveFiles) — позволяет перетащить и сбросить набор файлов на другое приложение;static bool DragAndDropContainer::performExternalDragDropOfText(const String text) — позволяет перетащить и сбросить на другое приложение блок текста text.В этой лекции вы познакомились с классами Juce, предоставляющими доступ к буферу обмена целевой операционной системы (SystemClipboard), а также реализующими обмен данными посредством механизма "перетащил и бросил" (DragAndDropTarget и FileDragAndDropTarget). Источником объектов, принимаемых DragAndDropTarget служит DragAndDropContainer.
Напишите программу, позволяющую перетаскивать блок текста из одной её части в другую.
Архив с исходными текстами примера Вы можете скачать здесь
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.