Spis treści:

Kategoria:C#Word


Word w C# - Proste style i kolory

Upiększanie dokumentu

W poprzednich częściach pokazałem, w jaki sposób tworzyć proste dokumenty Word i jak korzystać z interfejsów Selection i Range. Jeżeli ktoś nie opanował jeszcze w pełni tamtych interfejsów - nie ma obaw. Będą się one pojawiały jeszcze wiele razy, praktycznie w każdym przykładzie.

Dokumenty Word to coś więcej niż notatnik. Gdybyśmy potrzebowali zwykłego tekstu, nie uruchamialibyśmy całej maszyny COM z komponentem wykonywalnym WINWORD.exe. Zwykle dokumenty są w jakiś sposób formatowane - używamy pogrubień, pochyleń, podkreśleń, zmieniamy kolory. Tym też się zaraz zajmiemy. Od początku staram się opisywać dwa sposoby pracy z dokumentami Word - COM i XML. Tak też będzie ze stylami. Na wersję XML trzeba poczekać.

Pochylenie, pogrubienie, podkreślenie i kolor

Liczba styli i sposobów formatowania tekstu jest ogromna, więc skorzystam z techniki małych kroków. Zajmę się małym podzbiorem wszystkich możliwości, a dokładniej wymienionymi w tytule atrybutami pochylenia, pogrubienia, podkreślenia i koloru. Efekt, który zamierzam osiągnąć pokazany jest na poniższej ilustracji:

Pochylenie, pogrubienie, podkreślenie i kolor czcionki w dokumencie Word
Rys. 1. Pochylenie, pogrubienie, podkreślenie i kolor czcionki w dokumencie Word.

Dokument składa się z czterech linii tekstu, które są:

  1. pogrubiona
  2. pochylona
  3. podkreślona stylem
  4. pokolorowana gradientem

Wyjaśnień wymaga gradient. Nie jest to jakaś wbudowana funckja Word, tylko pewien trik, sztuczka. Każda litera ma, najzwyczajniej w świecie, inny kolor. Poierwszy znak jest czarny, drugi mniej czarny, a bardziej szary, aż do ostatniego, który jest biały. Wygląda ciekawie, a jest bardzo proste do zrealizowania poprzez interfejsy automatyzmu Word. Ręczne stworzenie takiego dokumentu i dopasowanie kolorów do kolejnych liter byłoby bardzo czasochłonne. Przejdźmy do kodu, czyli do części właściwej.

Style Word z kodu C#

Pełna implementacja zadania pokazana jest poniżej. Popatrzmy na zaprezentowany listing:

using System;
using Word = Microsoft.Office.Interop.Word;

class Program
{
    static void Main(string[] args)
    {
        object missing = Type.Missing;
        Word._Application wordApplication = new Word.Application();
        const string fadeText = "0123456789";
        try
        {
            Word._Document wordDocument = wordApplication.Documents.Add();

            var para = wordDocument.Paragraphs.Add();
            para.Range.Text = "Linia 1";
            para.Range.Bold = 1;
            para.Range.InsertParagraphAfter();

            para.Range.Text = "Linia 2";
            para.Range.Bold = 0;//Wyłącz pogrubienie
            para.Range.Italic = 1;
            para.Range.InsertParagraphAfter();

            para.Range.Text = "Linia 3";
            para.Range.Italic = 0;//Wyłącz pochylenie
            para.Range.Underline = Word.WdUnderline.wdUnderlineDotDash;
            para.Range.InsertParagraphAfter();

            para.Range.Text = fadeText;
            para.Range.Underline = Word.WdUnderline.wdUnderlineNone;
            for (int i = 0; i < fadeText.Length; i++)
            {
                //Oblicz nasycenie koloru, odcień szarości
                int saturation = 255 * (i + 1) / fadeText.Length;
                wordDocument.Range(para.Range.Start+i, para.Range.Start+1+i).Font.Color =
                    FromRGB(saturation, saturation, saturation);
            }
        }
        finally
        {
            wordApplication.Visible = true;
        }
    }

    //Przyjęło się, że kolory podawane są w postaci RGB (Red-Green-Blue,
    //Czerwony-Zielony-Niebieski). W Word kolejność jest nieco inna - GRB.
    public static Word.WdColor FromRGB(int red, int green, int blue)
    {
        return (Word.WdColor)(red + 0x100 * green + 0x10000 * blue);
    }
}

Jak to zwykle w programowaniu bywa, to samo zadanie można wykonać na wiele sposobów. Nie jest to jedyny i najlepszy sposób na rozwiązanie przedstawionego problemu.

Objaśnienia

W kodzie pojawia się szereg rozwiązań, które mogą być nieznane. Po pierwsze, operacje wykonywane są na kolejnych paragrafach. Pierwszy paragraf tworzony jest poprzez wywołanie metody Add() kolekcji Paragraphs. Taki paragraf ma swój zakres (obiekt Range). To dla tego zakresu definiujemy styl i wstawiamy tekst. Każdy kolejny paragraf dadawany jest poprzez wywołanie metody InsertParagraphAfter() na obiekcie bieżącego zakresu. Trzeba wiedzieć o jednym efekcie ubocznym: InsertParagraphAfter() oprócz tworzenia nowego paragrafu zmienia obiekt zakresu tak, że obejmuje on obszar tego nowego paragrafu. To tak, jak naciśnięcie klawisza Enter w Word. Przechodzimy do nowej linii, a włączone formatowanie zostaje do tej nowej linii przeniesione. Konsekwencją takiego projektu jest fakt, że wszelkie ustawione i niechciane sposoby formatowania należy wyłączyć.

Oddzielnym zaganieniem jest tekst gradientowy. Nasycenie, tak to sobie nazwijmy, szarości, jest wyliczane oddzielnie dla każdej litery, proporcjonalnie do jej pozycji w pełnym tekście. Atrybut koloru przypisywany jest do czcionki w postaci typu wyliczeniowego WdColor. Typ WdColor pozornie nas ogranicza, ale trzeba wiedzieć o jednej rzeczy: istnieje niejawna konwersja pomiędzy tym typem a typem int. To pozwala nam nieco uelastycznić cały algorytm.

Żeby nie było zbyt łatwo, w pakiecie Office przyjęto niekonwencjonalny sposób oznaczania kolorów. Zwykle stosuje się konwencję RGB (czerwony,zielony niebieski) lub ARGB (przeżroczystość,czerwony,zielony niebieski). Tutaj barwy składowe są trochę poprzestawiane. Aby utworzyć dowolny kolor należy zastosować kolejność GRB (zielony,czerwony,niebieski). Tak to zostało zrobione w metodzie FromRGB. Mnożnik 0x100 oznacza przesunięcie bitiowe o 8 miejsc, natomiast 0x10000 to przesunięcie o 16 miejsc w lewo. Tak uzyskaną sumę ważoną poszczególnych barw składowych należy jeszcze rzutować na typ wyliczeniowy WdColor.

Style dla obiektu Selection

Wspomniałem, że nie jest to jedyne rozwiązanie. Jak wiemy, operacje tekstowe można realizować poprzez obiekt zakresu i poprzez obiekt zaznaczenia (Selection). Poniżej przedstawiłem tę drugą opcję. Rozwiązanie jest bardzo podobne, ale warto je pokazać. Przyjrzyjmy się poniższemu listingowi:

using System;
using Word = Microsoft.Office.Interop.Word;

class Program
{
    static void Main(string[] args)
    {
        object missing = Type.Missing;
        Word._Application wordApplication = new Word.Application();
        const string fadeText = "0123456789";
        try
        {
            Word._Document wordDocument = wordApplication.Documents.Add();

            var selection = wordApplication.Selection;
            selection.Font.Bold = 1;
            selection.TypeText("Linia 1");
            selection.TypeParagraph();

            selection.Font.Bold = 0;//Wyłącz pogrubienie
            selection.Font.Italic = 1;
            selection.TypeText("Linia 2");
            selection.TypeParagraph();

            selection.Font.Italic = 0;//Wyłącz pochylenie
            selection.Font.Underline = Word.WdUnderline.wdUnderlineDotDash;
            selection.TypeText("Linia 3");
            selection.TypeParagraph();

            selection.Font.Underline = Word.WdUnderline.wdUnderlineNone;
            for (int i = 0; i < fadeText.Length; i++)
            {
                //Oblicz nasycenie koloru, odcień szarości
                int saturation = 255 * (i + 1) / fadeText.Length;
                selection.Font.Color = FromRGB(saturation, saturation, saturation);
                selection.TypeText(fadeText.Substring(i, 1));
            }
        }
        finally
        {
            wordApplication.Visible = true;
        }
    }

    //Przyjęło się, że kolory podawane są w postaci
    //RGB (Red-Green-Blue,Czerwony-Zielony-Niebieski).
    //W Word kolejność jest nieco inna - GRB.
    public static Word.WdColor FromRGB(int red, int green, int blue)
    {
        return (Word.WdColor)(red + 0x100 * green + 0x10000 * blue);
    }
}

Praca z selection wydaje się bardziej zbliżona do tego, co wykonujemy w Word pisząc tekst ręcznie. Wykonywane czynności wyglądałyby najprawdopodobniej następująco: klikamy w ikonę pogrubienia (Bold=1), wpisujemy tekst (TypeText) i naciskamy Enter (TypeParagraph). W drugiej linii odznaczamy pogrubienie (Bold=0) i zaznaczamy pochylenie (Italic=1), wpisujemy tekst (TypeText) i naciskamy Enter (TypeParagraph). Podobnie postępujemy z kolejnymi liniami.

Podsumowanie

Praca z prostymi stylami nie jest szczególnie trudna. Większy problem, zwłaszcza podczas pracy z dużymi dokumentami, stanowi odpowiednie ustawienie pozycji kursora (Selection) lub określenie zakresu (Range). Myślę, że w miarę zwiększania złożoności pokazywanych przykładów, praca ze wspomnianymi obiektami stanie się prostsza i bardziej zrozumiała. Wkrótce przedstawię, jak podobne wymagania zrealizować w postaci pliku XML i znacznikowej reprezentacji dokumentu Word.

Kategoria:C#Word

, 2013-12-20

Brak komentarzy - bądź pierwszy

Dodaj komentarz
Wyślij
Ostatnie komentarze
Dzieki za rozjasnienie zagadnienia upsert. wlasnie sie ucze programowania :).
Co się stanie gdy spróbuję wyszukać:
SELECT * FROM NV_Airport WHERE Code='SVO'
SELECT * FROM V_Airport WHERE Code=N'SVO'
(odwrotnie są te N-ki)
Będzie konwersja czy nie znajdzie żadnego rekordu?