Jak korzystać ze Schowka
Wstęp
W dokumencie tym znajdują się informacje w oparciu, o które można w łatwy sposób stworzyć dla własnej aplikacji metody obsługujące zapis i odczyt danych ze Schowka.
- Podstawowe informacje o Schowku.
- Metody wykorzystywane przy obsłudze Schowka.
- Formaty zapisu danych do Schowka.
- Przykład wykorzystania Schowka.
Informacje podstawowe
Schowek (ang. Clipboard) jest jedną z metod komunikacji pomiędzy procesami dostępnych w systemie Windows, umożliwia wymianę danych między aplikacją źródłową (umieszczającą dane w Schowku) i docelową (odczytującą dane). Schowek jest również używany do przekazywania danych w operacjach OLE.
Do obsługi Schowka przeznaczone są polecenia Wklej (ang. Paste) z Wytnij (ang. Cut), Kopiuj (ang. Copy) z menu Edycja (ang. Edit), odpowiednio powiązane w MFC z następującymi identyfikatorami: ID_EDIT_PASTE, ID_EDIT_CUT, ID_EDIT_COPY. Można dodać do klasy widoku (format zapisywanych za pomocą kreatora ClassWizard danych może być zależny od widoku) metody obsługi uruchamiane po wybraniu odpowiedniej opcji z menu. W metodach tych musi zostać zaimplementowana realizacja następujących czynności:
Wycinanie i kopiowanie danych do Schowka:
- otwarcie Schowka (OpenClipboard)
- określenie elementów, które mają zostać przekopiowane (np. zidentyfikowanie fragmentu tekstu zaznaczonego w widoku dokumentu)
- zapisanie zaznaczonych danych do pliku w pamięci (można wykorzystać np. obiekt klasy CMemFile który jest alokowanym w pamięci RAM i zaserializować do niego odpowiednie dane)
- przekazanie pliku do Schowka (SetClipboardData)
- zamknięcie Schowka (CloseClipboard)
Wklejanie danych ze Schowka do dokumentu:
- otwarcie Schowka (OpenClipboard)
- sprawdzenie czy w Schowku znajdują się dane w wymaganym formacie (format jest jednoznacznie określany przez identyfikator będący liczbą typu UINT)
- pobranie uchwytu do danych zawartych w schowku (GetClipboardData)
- odczyt danych "wskazywanych" przez uchwyt pobrany w poprzednim punkcie
- odświeżenie widoku w celu przedstawienia skopiowanych danych
- zamknięcie Schowka (CloseClipboard)
Podstawowe metody wykorzystywane przy obsłudze Schowka
OpenClipboard BOOL OpenClipboard() Otwiera Schowek, jeśli operacja przebiegnie prawidłowo zostaje zwrócona wartość TRUE w przeciwnym przypadku FALSE (aby uzyskać szczegółowe informacje o zaistniałym błędzie można skorzystać z funkcji GetLastError).
CloseClipboard BOOL CloseClipboard() Zamyka Schowek, gdy operacja zakończy się sukcesem zwraca wartość różną od zera w przeciwnym przypadku zero.
SetClipboardData HANDLE SetClipboardData(UINT uFormat, HANDLE hMem) Metoda wstawia do Schowka dane w określonym formacie, jeśli wszystko przebiegnie prawidłowo zwraca uchwyt do danych, jeśli wystąpi błąd zwraca NULL. Argument uFormat specyfikuje format danych, jeśli nie jest to standardowy format obsługiwany przez Schowek musi zostać wcześniej zarejestrowany (RegisterClipboardFormat) hMem identyfikuje dane zapisane w wyspecyfikowanym formacie, jest to uchwyt do globalnie zaalokowanego obszaru pamięci RAM, np. obiekt typu CMemFile
GetClipboardData HANDLE GetClipboardData(UINT uFormat) Pobiera ze Schowka dane w wyspecyfikowanym formacie, jeśli działanie zakończy się sukcesem zwraca uchwyt do pobranych danych, w przeciwnym przypadku NULL Argument uFormat określa format danych, które mają zostać pobrane ze Schowka
Przykładowe formaty zapisu danych
Poniżej przedstawiono przykładowe formaty zapisu danych do Schowka standardowo zarejestrowane w systemie Windows:
Nazwa formatu Znaczenie CF_BITMAP Uchwyt do bitmapy (HBITMAP). CF_DIB Obiekt w pamięci zawierający strukturę BITMAPINFO definiującą wymiary i kolory bitmapy. CF_ENHMETAFILE Uchwyt do obrazu typu enhanced metafile (HENHMETAFILE). CF_METAFILEPICT Uchwyt do struktury definiującej format obrazu zapisanego w metapliku (METAFILEPICT). CF_PALETTE Uchwyt do palety kolorów. Jeśli aplikacja zapisuje do schowka informacje zależne od palety należy w schowku umieścić również odpowiednią paletę. CF_OEMTEXT Format tekstu zawierający znaki w trybie OEM. Każda linia kończy się kombinacją "powrót karetki + nowa linia (ang. linefeed)" (CR+LF) a znak NULL określa koniec danych. CF_TEXT Format tekstowy. Każda linia kończy się kombinacją (CR+LF) a znak NULL określa koniec danych. Ten format należy stosować dla tekstu ANSI. CF_WAVE Reprezentuje dane audio w standardowym formacie wave, próbkowane z częstotliwością 11 lub 22 kHz. W większości przypadków aplikacja korzysta ze schowka przekazując bądź odczytując dane zapisane we własnym, nietypowym formacie, konieczne jest wówczas zgłoszenie w systemie takiego formatu co umożliwi jednoznaczną identyfikacje typu danych zawartych w schowku..
Operacja rejestracji własnego formatu danych przechowywanych w schowku wymaga wykorzystania funkcji:UINT CWnd::RegisterClipboardFormat(LPCTSTR lpszFormat);Metoda ta jako argument przyjmuje niezerowy string będący nazwą nowo rejestrowanego formatu danych przechowywanych w schowku a zwraca wartość typu UINT będącą identyfikatorem tego formatu. W przypadku błędu podczas rejestracji zostaje zwrócona wartość 0. Wywołanie tej metody z odpowiednim argumentem należy umieścić w konstruktorze klasy widoku.
//////////////////////////////////////////////////////// // CClipSampleView.cpp - klasa widoku. // konstruktor klasy widoku, CClipSampleView::CClipSampleView() { // zarejestrowanie formatu danych w schowku, m_nClipboardFormat = ::RegisterClipboardFormat(_T("BGAK.ClipSample.1")); ... }
Przykład wykorzystania Schowka
Poniżej zostały przedstawione metody ilustrujące korzystanie ze Schowka. Realizują one kopiowanie i wklejanie danych charakterystycznych dla pewnej aplikacji, zapisanych w zgłoszonym wcześniej formacie m_nClipboardFormat. Po zaimplementowaniu funkcji my_SaveData, my_LoadData i zgłoszeniu odpowiedniego formatu danych przedstawiony kod może służyć jako szkielet dla rzeczywistych metod realizujących obsługę Schowka.
//////////////////////////////////////////////////////// // CClipSampleView.cpp - klasa widoku. ... // Kopiowanie danych do Schowka. void CClipSampleView::OnEditCopy() { // utworzenie pliku w pamięci RAM "memFile" i obiektu // archiwizacji danych "ar" powiązanego z tym plikiem, CSharedFile memFile; CArchive ar(&memFile, CArchive::store|CArchive::bNoFlushOnDelete); // własna funkcja serializująca do "ar" wymagane informacje my_SaveData(ar); ar.Flush(); // zamknięcie pliku w pamięci (uchwyt do pliku zapisany w hData), HGLOBAL hData = memFile.Detach(); // otwarcie Schowka, if (OpenClipboard()) { // przesłanie do schowka wymaganych danych i zamknięcie Schowka, ::SetClipboardData(m_nClipboardFormat, hData); CloseClipboard(); } else AfxMessageBox(IDS_CANNOT_OPEN_CLIPBOARD, MB_OK | MB_ICONWARNING); } // Pobranie danych ze Schowka. void CGraphView::OnEditPaste() { // otwarcie Schowka if (OpenClipboard()) { // pobranie uchwytu do danych o wybranym formacie przechowywanych // w Schowku HANDLE hData = ::GetClipboardData(m_nClipboardFormat); if (hData != NULL) { // właściwy odczyt danych ze Schowka, CSharedFile memFile; memFile.SetHandle(hData, FALSE); CArchive ar(&memFile, CArchive::load); // własna procedura zapisująca odczytane dane do dokumentu, my_LoadData(ar); ar.Close(); memFile.Detach(); } else AfxMessageBox(IDS_CANNOT_GET_CLIPBOARD_DATA, MB_OK | MB_ICONWARNING); // zamknięcie Schowka CloseClipboard(); } else AfxMessageBox(IDS_CANNOT_OPEN_CLIPBOARD, MB_OK | MB_ICONWARNING); }