Grafika

Pakiet SWT udostępnia mechanizm obsługi grafiki, który pozwala rysować i wyświetlać obrazy w widgetach. Mechanizm ten pozwala na osiągnięcie zadowalających efektów bez potrzeby programowania interfejsu graficznego, ponieważ widgety obsługują malowanie ikon, tekstu i innych danych. Jeśli jednak tworzona aplikacja ma wyświetlać nietypową grafikę lub implementowany jest nietypowy, rysowany widget, niezbędne jest zaznajomienie się z podstawowymi obiektami rysunkowymi w pakiecie SWT.

Kontekst graficzny

Kontekst graficzny, GC, to centralny punkt mechanizmu obsługi grafiki w pakiecie SWT. Jego interfejs API opisuje wszystkie możliwości pakietu SWT w zakresie grafiki.

Kontekstu GC można używać do rysowania w polu sterującym (najbardziej typowy przypadek), na obrazie, na ekranie lub do portu drukarki. Podczas rysowania w polu sterującym używany jest kontekst GC, przekazywany w zdarzeniu paint pola sterującego. W przypadku rysowania na obrazie, na ekranie lub do portu drukarki należy utworzyć kontekst GC skonfigurowany specjalnie do tego celu, a następnie usunąć go, gdy przestanie być potrzebny.

Mając już kontekst GC, można określać jego atrybuty, które sterują wyglądem grafiki rysowanej w danym kontekście, na przykład kolor, szerokość linii i czcionka.

Skorowidz funkcji API dla kontekstu GC zawiera pełne zestawienie funkcji graficznych.

Czcionki

Do operowania czcionkami w pakiecie SWT służą klasy Font i FontData.

Klasa FontData opisuje charakterystykę czcionki. Obiekt FontData można utworzyć, definiując nazwę czcionki, jej styl oraz wielkość. Klasa FontData zawiera funkcje API przeznaczone do odczytywania tych atrybutów. Ponieważ klasa FontData nie powoduje przydzielenia żadnych zasobów systemu operacyjnego, utylizowanie jej instancji nie jest konieczne.

Klasa Font definiuje sam obiekt graficzny reprezentujący czcionkę używaną przez rysujące funkcje API. Obiekt Font dla obiektu ekranu (Display) tworzy się, kojarząc obiekt Display oraz obiekt FontData odpowiedniej czcionki. Obiekt Font może być także celem zapytania o związany z nim obiekt FontData.

Gdy obiekt Font, któremu przydzielono zasoby systemowe, przestanie być potrzebny, należy go zutylizować.

Kolory

Operowanie kolorami jest analogiczne do operowania czcionkami. Obiekt Color dla obiektu ekranu (Display) tworzy się, podając wartości RGB właściwego koloru. Gdy kolor, któremu przydzielono zasoby systemowe, przestanie być potrzebny, należy go zutylizować.

Metoda getSystemColor(int) obiektu Display pozwala odczytywać predefiniowane kolory systemowe danej platformy. Nie ma potrzeby zwalniania kolorów uzyskanych tym sposobem.

Model kolorów został szczegółowo omówiony w artykule SWT color model.

Obrazy

Klasy Image, ImageData oraz ImageLoader są używane do manipulowania obrazami w pakiecie SWT.

Obiekt ImageData opisuje rzeczywiste piksle obrazu przy użyciu klasy PaletteData, określającej używane wartości kolorów. Klasa ImageData stanowi opis obrazu, który jest niezależny od urządzenia i platformy.

Klasa ImageLoader ładuje i zapisuje obiekt ImageData w plikach o różnych formatach. Aktualnie pakiet SWT obsługuje ładowanie i zapisywanie obrazów w formatach BMP (Windows Bitmap), ICO (Windows Icon), JPEG, GIF i PNG.

Obiekt Image stanowi rzeczywisty obiekt graficzny reprezentujący obraz używany przez rysujące funkcje API. Obraz jest tworzony dla określonego obiektu ekranu (Display). Tworzenie obrazów może się odbywać na kilka sposobów:

Bez względu na sposób utworzenia obiektu Image zawsze należy pamiętać o jego zutylizowaniu.

Cykl życia obiektu graficznego

Większość obiektów graficznych używanych do rysowania w pakiecie SWT wymaga przydzielenia zasobów systemu operacyjnego, co wymaga później jawnego zwolnienia tych zasobów. Obowiązuje tu zasada omówiona już wcześniej. Jeśli obiekt jest tworzony za pomocą konstruktora, musi zostać usunięty. Jeśli dostęp do obiektu jest uzyskiwany z innego miejsca, nie należy go usuwać.

Tworzenie

Obiekty graficzne takie jak konteksty graficzne, czcionki, kolory i obrazy otrzymują przydzielone zasoby systemu operacyjnego od razu po utworzeniu obiektu. Właściwy moment utworzenia obiektu graficznego zależy od przewidywanego sposobu jego użycia.

Obiekty graficzne intensywnie używane w całej aplikacji powinny być tworzone równocześnie z widgetami. Ta zasada dotyczy najczęściej kolorów i czcionek. W innych przypadkach zalecane jest tworzenie obiektów graficznych na bieżąco. Na przykład kontekst graficzny można utworzyć w ramach jednej z procedur obsługi zdarzenia dla widgetu w celu przeprowadzenia określonych obliczeń.

W przypadku implementowania widgetu niestandardowego zazwyczaj zasoby dla obiektów graficznych przydziela się w ramach konstruktora, jeśli zawsze są wykorzystywane. Można je przydzielać na bieżąco, jeśli obiekty nie są używane zawsze lub jeśli ich użycie zależy od stanu pewnego atrybutu.

Malowanie

Po przydzieleniu zasobów na potrzeby obiektów graficznych można przystąpić do malowania. Operację malowania należy zawsze wykonywać wewnątrz funkcji nasłuchiwania dla zdarzenia malowania. Istnieją rzadko spotykane sytuacje, zwłaszcza w przypadku widgetów niestandardowych, gdzie malowanie odbywa się w odpowiedzi na inne zdarzenie. Takie podejście nie jest jednak zalecane. Jeśli faktycznie zachodzi potrzeba malowania w trakcie obsługiwania innego zdarzenia, należy najpierw spróbować użyć metody redraw(), co spowoduje wygenerowanie kolejnego zdarzenia malowania w systemie operacyjnym. Rysowanie poza metodą malującą powoduje zignorowanie optymalizacji pod kątem platformy i może prowadzić do błędów zależnych od liczby oczekujących zdarzeń malowania w kolejce zdarzeń.

Po odebraniu zdarzenia malowania przekazany zostanie także kontekst graficzny GC wstępnie skonfigurowany do rysowania w widgecie. Tego kontekstu GC nie należy zwalniać! Nie został on utworzony przez kod aplikacji.

Dla wszelkich innych obiektów graficznych należy przydzielać zasoby podczas obsługi zdarzenia (albo wcześniej). Poniżej przedstawiono fragment kodu z przykładu org.eclipse.swt.examples.HelloWorld5. Kolor czerwony (red) został już przydzielony wcześniej, podczas tworzenia widgetu, można go więc tutaj użyć.

   shell.addPaintListener (new PaintListener () {
      public void paintControl (PaintEvent event) {
         GC gc = event.gc;
         gc.setForeground (red);
         Rectangle rect = event.widget.getClientArea ();
         gc.drawRectangle (rect.x + 10, rect.y + 10, rect.width - 20, rect.height - 20);
         gc.drawString (resHello.getString("Hello_world"), rect.x + 20, rect.y + 20);
      }
   });

Utylizowanie obiektu

Każdy obiekt graficzny utworzony przez kod aplikacji musi zostać usunięty gdy tylko przestanie być potrzebny.

Dobór momentu utylizacji zależy od momentu utworzenia obiektu. Jeśli obiekt graficzny został utworzony podczas tworzenia widgetu, najczęściej należy dodać do widgetu funkcję nasłuchiwania dla zdarzenia dispose i zutylizować grafikę w chwili utylizowania widgetu. Jeśli obiekt jest tworzony na bieżąco podczas malowania, należy go zutylizować po skończeniu malowania.

Poniższy fragment kodu przedstawia nieco zmienioną wersję znanej już funkcji nasłuchiwania. W tym przykładzie kolor red jest tworzony i usuwany podczas malowania.

   shell.addPaintListener (new PaintListener () {
      public void paintControl (PaintEvent event) {
         GC gc = event.gc;
         Color red = new Color (event.widget.getDisplay (), 0xFF, 0, 0);
         gc.setForeground (red);
         Rectangle rect = event.widget.getClientArea ();
         gc.drawRectangle (rect.x + 10, rect.y + 10, rect.width - 20, rect.height - 20);
         gc.drawString (resHello.getString ("Hello_world"), rect.x + 20, rect.y + 20);
         red.dispose ();
      }
   });