Шаг 16 - Класс для буфера обмена (Clipboard)

Создание проекта

Дополняем наш проект. Нам нужно создать новый класс. Создадим его мы другим методом. Как положено. Описание класса в своем заголовочном файле, а реализация в своем файле. Для того, чтобы добавить в проект класс нужно перейти в окно Class View(просмотр классов), нажать правую кнопку мышки на элементе step16 classes и выбрать пункт меню New Class (новый класс).

16_1.gif (2858 b)

Появится диалоговое окно. Заполняем его.

16_2.gif (2516 b)

Внизу можно указать класс отца, но он нам не нужен. Посмотрите на ClassView, там Вы должны увидеть, что в проекте появился новый класс.

16_3.gif (1884 b)

Создаем код

Нам нужно подключить описание этого класс к нашему коду.

......
#include "resource.h"	// Идентификаторы ресурсов
#include "MyClip.h"	// описание нашего класса
#define IDC_MYBUTTON 100	// Идентификатор кнопки
......

В описание класса CMyClip нужно добавить описание двух функций.


// MyClip.h: interface for the CMyClip class.
//
/////////////////////////////////////////////

#if !defined(AFX_MYCLIP_H__3F50824B_6C97_11D5_B617_D466F313FE46__INCLUDED_)
#define AFX_MYCLIP_H__3F50824B_6C97_11D5_B617_D466F313FE46__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "afxwin.h"

class CMyClip 
{
public:
	CMyClip();
	virtual ~CMyClip();
	void CopyText(CString test);
	CString GetText();
};
#endif // !defined(AFX_MYCLIP_H__3F......__INCLUDED_)

И реализация функций:

// MyClip.cpp: implementation of the CMyClip class.
//
//////////////////////////////////////////////////////

#include "MyClip.h"
///////////////////////////////////////////
// Construction/Destruction
///////////////////////////////////////////

CMyClip::CMyClip()
{
}

CMyClip::~CMyClip()
{
}

CString CMyClip::GetText()
{
	char * buffer;	// указатель на данные
	if(AfxGetMainWnd()->OpenClipboard())	// если буфер обмена удалось открыть, то
	{
		buffer = (char*)GetClipboardData(CF_TEXT);// получить из буфера текст
		CloseClipboard();	// закрыть буфер обмена
		return buffer;	// вернуть результат
	}
	return "";
}

void CMyClip::CopyText(CString test)
{
	if (AfxGetMainWnd()->OpenClipboard())// если буфер обмена удалось открыть то
	{
		if (EmptyClipboard())	// Очистить буфер
		{
			HGLOBAL clipbuffer;
			char * buffer;	// указатель на данные
			clipbuffer = GlobalAlloc(GMEM_DDESHARE, test.GetLength()+1);// выделить память
			buffer = (char*)GlobalLock(clipbuffer);	// блокировать буфер
			strcpy(buffer, LPCSTR(test));	// копировать в него данные
			GlobalUnlock(clipbuffer);	// разблокировать
			SetClipboardData(CF_TEXT,clipbuffer);	// установить данные и тип
			if (!CloseClipboard()) AfxMessageBox("Error Close");// закрыть
		} else AfxMessageBox("Error Empty");
	} else AfxMessageBox("Error Open");
}

Объявите класс буфера и функцию реакции:

class CMainWnd : public CFrameWnd
{
public:
	CMainWnd();	// Конструктор по умолчанию
	void OnCopyBuffer();// копировать в буфер
	void OnOpen();	// эта функция вызовется при выборе меню Open
	......
	CMenu m_wndMenu;	// Это наш класс Меню
	CMyClip clip;	// Это класс буфера обмена
	DECLARE_MESSAGE_MAP();// таблица откликов
}

Необходимо создать реакцию на одинарное нажатие кнопки:

BEGIN_MESSAGE_MAP(CMainWnd, CFrameWnd)// таблица откликов на сообщения
	......
	ON_COMMAND(ID_OPEN,OnOpen)		// Реакция на выбор меню Open
	ON_BN_CLICKED(IDC_MYBUTTON,OnCopyBuffer)	// нажали на кнопку левой кнопкой мыши
	ON_COMMAND(ID_FILE_EXIT,MenuExit)		// Вот она, обработка реакции на выбор меню
	......

И реализацию реакции:

void CMainWnd::OnCopyBuffer()
{
	clip.CopyText("Hello My Text"); // копировать в буфер текст
}

Поменяем действия по нажатию на клавишу:

void CMainWnd::OnKeyDown( UINT, UINT, UINT)
{
	AfxMessageBox(clip.GetText());		// показать текст
}

Описание

В объявлении класса ничего нового, мы подключили стандартную библиотеку MFC для доступа к функциям. Ведь данный файл будет отдельным объектным файлом obj и ему необходим доступ к библиотекам. Смотрим функцию CopyText нам для работы необходимо открыть буфер. Но для этого необходим указатель на наше окно. Вот мы его и открываем OpenClipboard(), буфер открыть можно не всегда поэтому эта функция BOOL.

Дальше мы очищаем буфер и заводим две переменные. Буфер, как видите, очистить тоже можно не всегда. HGLOBAL - это указатель на переменную, но не простую, а на глобальную. К ней доступ будет из любого места памяти (из любой программы), ведь это же буфер обмена, правда?

Дальше для этого буфера выделяем память, по размеру как переданная строка+1 и с атрибутом GMEM_DDESHARE, что говорит про то, что мы не жадные и разрешаем к ней доступ. После этого мы блокируем память для копирования. Ведь у нас многозадачная среда, и если в момент копирования кто-то потянет руки к памяти, будет нехорошо. Одновременно приравнивая указатель с локальным buffer. Теперь будем копировать.

После копирования необходимо память разблокировать. И только потом установить в буфер текст, еще и указав тип. Ведь в буфере могут быть данные любого типа TEXT,RTF,BMP,WMF,OLE и т.д. После всех операций буфер нужно закрыть.

Функция GetText() получает данные, методика похожа, за исключением функции GetClipboardData() с указанием типа получаемой информации.

Теперь пробуем. Запустите блокнот NotePad. Запустите нашу программу. Введите в блокноте слово и скопируйте его в буфер. Перейдите в программу и нажмите на пробел. Вы увидите содержимое буфера.

16_4.gif (3290 b)

Теперь нажмите на кнопку. В буфер поместится текст. Вставьте его в блокнот. Там будет Hello My Text. Ну вот, немного терпения и все работает.

Шпаргалка

Откройте буфер:

......
if (AfxGetMainWnd()->OpenClipboard())// если буфер обмена удалось открыть то
......

Очистите:

......
if (EmptyClipboard())	// Очистить буфер
......

Выделите глобальную память и скопируете туда строку.

......
clipbuffer = GlobalAlloc(GMEM_DDESHARE, test.GetLength()+1);// выделить память
......
strcpy(buffer, LPCSTR(test));// копировать в него данные
......

Установите данные:

......
SetClipboardData(CF_TEXT,clipbuffer);// установить данные и тип
......

Закройте буфер:

......
if (!CloseClipboard()) AfxMessageBox("Error Close");// закрыть
......

Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Каев Артем - 08.09.99 (обновлено 29.06.2001)