• Kurs MUI - część 3

20.02.2005 14:37, autor artykułu: Grzegorz Kraszewski
odsłon: 2999, powiększ obrazki, wersja do wydruku,

Projektowanie interfejsu graficznego.

W tym odcinku omówię to, co w znacznej mierze zadecydowało o sukcesie MUI, czyli efektownie wyglądający interfejs graficzny. Główną jego cechą (niespotykaną nawet w "wiodących" pakietach programistycznych na PC) jest tak zwany dynamiczny layout. Oznacza to, że programista nie określa pozycji gadżetów w oknie w pikselach. Pozycje te obliczane są przez MUI przed każdym otwarciem okna. Programista określa jedynie wzajemne położenie gadżetów, np. gadżet A ma być nad gadżetem B, a gadżet C po lewej gadżetu D. Na podstawie tych informacji MUI automatycznie oblicza położenie i rozmiary wszystkich obiektów w oknie. Dzięki temu użytkownik może używać różnych czcionek, odstępów między gadżetami, różnych gadżetów standardowych (np. strzałek od suwaka). Obiekty będą zawsze miały taką wielkość aby dostosować się do pomysłów użytkownika. Drugą korzyścią jaką odnosi użytkownik jest możliwość skalowania okien w czasie działania programu, rozmieszczenie obiektów jest wtedy wyliczane od nowa.

Określanie wzajemnego położenia obiektów

Informację o wzajemnym rozmieszczeniu obiektów w oknie przekazuje się MUI poprzez odpowiednie ich grupowanie. MUI posiada cztery rodzaje grup: grupy pionowe, poziome, tablicowe i o rozmieszczeniu definiowanym przez użytkownika. Domyślnym rodzajem grupy jest grupa pionowa. Grupa to oczywiście obiekt klasy MUIC_Group. Do każdej grupy możemy dołączać elementy w momencie jej tworzenia korzystając z atrybutu MUIA_Group_Child. Oto uproszczony przykład definicji grupy pionowej:

grupa = MUI_NewObject (MUIC_Group,
  MUIA_Group_Child, obiekt_D,
  MUIA_Group_Child, obiekt_G,
  MUIA_Group_Child, obiekt_Z,
  TAG_END);


MUI Obiekty zostaną rozmieszczone jak na rysunku, a więc pionowo od góry do dołu w takiej kolejności w jakiej dołączyliśmy je do grupy. Jeżeli pozwalają na to ograniczenia rozmiarów obiektów, wszystkie obiekty w grupie pionowej mają tę samą szerokość. Jeżeli jakiś obiekt będzie węższy, zostanie wycentrowany w poziomie.

Bardzo podobna jest grupa pozioma. Grupę poziomą uzyskujemy przez podanie atrybutu MUIA_Group_Horiz o wartości TRUE. Jak łatwo się domyślić, grupa zdefiniowana jak poniżej:

grupa = MUI_NewObject (MUIC_Group,
  MUIA_Group_Horiz, TRUE,
  MUIA_Group_Child, obiekt_D,
  MUIA_Group_Child, obiekt_G,
  MUIA_Group_Child, obiekt_Z,
  TAG_END);


MUI będzie wyglądała jak na rysunku. Analogicznie do grupy pionowej wszystkie obiekty w grupie poziomej mają tę samą wysokość, jeżeli nie zaistnieją jakieś ograniczenia. Jak łatwo zgadnąć, ewentualny obiekt niższy od pozostałych zostanie wyśrodkowany w pionie.

Grupa tablicowa umożliwia rozmieszczenie większej liczby gadżetów w formie tablicy. Grupę tablicową można zdefiniować na dwa sposoby podając ilość wierszy lub kolumn:

MUIA_Group_Columns
MUIA_Group_Rows


W dotychczasowych wersjach MUI nie ma różnicy czy użyjemy jednego czy drugiego sposobu, więc chcąc zdefiniować np. grupę 24 gadżetów w 4 kolumnach i 6 wierszach to możemy z tym samym skutkiem użyć MUIA_Group_Columns, 4 jak i MUIA_Group_Rows, 6. Trzeba pamiętać, żeby liczba gadżetów w grupie była podzielna bez reszty przez ilość podanych wierszy czy kolumn. Rozmieszczając gadżety w grupie tablicowej MUI stara się, aby wszystkie obiekty w danej kolumnie miały jednakową szerokość, a jednocześnie wszystkie obiekty w danym wierszu miały jednakową wysokość. Obiekty w grupie rozmieszczane są kolejno wierszami od lewej do prawej. Przykładowa grupa tablicowa pokazana jest na rysunku.

MUI W grupie o ustawieniu definiowanym przez użytkownika możemy podać funkcję, która pobierze od MUI dane na temat dostępnego miejsca i wyznaczy pozycje wszystkich gadżetów należących do grupy. Ponieważ możliwość ta rzadko jest potrzebna i stanowi niejako wyższy stopień wtajemniczenia, omówię ją w jednej z następnych części.

Wydawałoby się, że trzy możliwości ułożenia obiektów (pion, poziom i tablica) nie dają zbyt wielkiej możliwości manewru. Znacznie rozszerza je nam możliwość zagnieżdżania grup. Po prostu elementem grupy może być inna grupa, ilość poziomów zagnieżdżenia jest nieograniczona. Dodatkowym przydatnym sposobem jest użycie obiektu klasy MUIC_Rectangle. Obiekt ten jest po prostu pustym miejscem w oknie i znakomicie przydaje się do drobnych zmian w ustawieniu. Jak napisałem wyżej, obiekt w grupie pionowej jeżeli jest węższy od pozostałych będzie wyśrodkowany w pionie, jednak umieszczając zamiast tego obiektu grupę, w której znajdzie się ten obiekt i obiekt Rectangle, możemy wyrównać obiekt do lewej lub do prawej, a nawet wyjustować obiekty z obu stron. Przykłady przedstawione są na rysunku.

MUI

Innym zastosowaniem obiektu Rectangle jest środkowanie obiektu w obu wymiarach. Często mamy obiekt o ustalonej wysokości i szerokości, ale chcemy, żeby grupa w której ten obiekt jest umieszczony, była skalowalna w pionie i poziomie. Należy wtedy obiekt "obłożyć" czterema obiektami Rectangle, korzystając z jednej grupy pośredniej, jak na rysunku.

MUI

Obiektami Rectangle możemy też wypełnić brakujące puste miejsca w grupie tablicowej. Przykład takiego zastosowania można zobaczyć w głównym oknie programu Public Screen Inspector (PSI) wchodzącym w skład pakietu MUI.

Wpływanie na rozmiary gadżetów

Zasadniczą funkcję w procesie określania rozmiarów gadżetów odgrywa klasa MUIC_Area. Cokolwiek jest umieszczone w oknie programu, jest obiektem klasy MUIC_Area lub którejś z wielu jej klas pochodnych. W klasie tej są przechowywane informacje dotyczące rozmiarów obiektu oraz możliwości ich zmian. Zmiany te nie mogą być dowolne, wyobraźmy sobie przycisk z tekstem napisanym czcionką o wysokości 11 punktów zmniejszony do wysokości czterech pikseli... Tak więc skalowanie nie dotyczy wszystkich gadżetów i nie w tym samym stopniu. Na przykład gadżet typu ListView może zmieniać zarówno szerokość, jak i wysokość. Gadżet tekstowy (typu Text, czy String) może zmieniać tylko szerokość, wysokość jest zdeterminowana przez użytą czcionkę. I w końcu przycisk graficzny (z obrazkiem) ma z reguły niezmienną szerokość i wysokość. Klasa MUIC_Area umożliwia nam kontrolę procesu określania rozmiarów poprzez szereg atrybutów. Ponieważ wszystkie rodzaje gadżetów są klas pochodnych od MUIC_Area, więc do wszystkich możemy stosować omówione poniżej atrybuty:

MUIA_FixWidth
MUIA_FixHeight


Te dwa atrybuty pozwalają na sztywne ustalenie szerokości i wysokości obiektu w pikselach. Atrybutów tych nie powinno się używać bez wyraźnej potrzeby, ograniczają one bowiem działanie dynamicznego skalowania. Najlepiej nie używać ich w ogóle, są inne, które pozwalają nam na regulację wielkości w bardziej subtelny sposób.

MUIA_FixWidthTxt 
MUIA_FixHeightTxt 


To para już nieco bardziej użytecznych, choć wciąż nie zalecanych do używania atrybutów. Ustalają one rozmiary obiektu według rozmiarów napisu podanego jako wartość atrybutu. Czcionka użyta do wyznaczenia rozmiarów jest czcionką przypisaną obiektowi automatycznie lub przez atrybut MUIA_Font. W praktyce atrybuty te są rzadko potrzebne, ponieważ obiekty zawierające tekst same dobierają swoje rozmiary do tego tekstu.

MUIA_MaxHeight
MUIA_MaxWidth


Te atrybuty pozwalają na ograniczenie maksymalnej wielkości obiektu w pikselach.

MUIA_HorizWeight
MUIA_VertWeight
MUIA_Weight


Te trzy atrybuty, w przeciwieństwie od powyższych są bardzo przydatne i często używane. Pozwalają one określić zależności między wielkością obiektów w grupie. MUI rozmieszczając obiekty w grupie standardowo przydziela każdemu taką samą ilość miejsca, jeżeli wymiar któregoś z nich nie jest ograniczony w inny sposób. Jeżeli więc mamy np. trzy obiekty, a miejsce na nie ma 300 pikseli, to każdy obiekt będzie miał 100 pikseli. Jeżeli jednak każdemu obiektowi damy inną wartość MUIA_Weight ich procentowy udział w zagospodarowaniu wolnej przestrzeni zmieni się. Jeżeli obiekty A i B będą miały MUIA_Weight równe 100, a obiekt C 200, obliczenie zostanie przeprowadzone następująco. Suma atrybutów daje 400, więc obiekty A i B dostaną po 100/400 (1/4) dostępnego miejsca, a więc w przykładzie po 75 pikseli, a obiekt C dostanie 200/400 (1/2), czyli 150 pikseli. Krótko mówiąc jeżeli to tylko będzie możliwe, obiekt C będzie dwa razy większy od pozostałych w grupie. Dlaczego napisałem "jeśli tylko to możliwe"? Bo ograniczenia dotyczące maksymalnej i minimalnej wielkości obiektu mają większy priorytet. Dlatego np. gadżet z tekstem nie zareaguje na MUIA_VertHeight, bo jego wielkość w pionie jest ustalona. Atrybuty MUIA_HorizWeight i MUIA_VertWeight pozwalają na oddzielną regulację proporcji obiektów w pionie i w poziomie, MUIA_Weight ustala proporcje jednocześnie w obu wymiarach.

Jeżeli chcemy poznać rozmiar jakiegoś obiektu do dyspozycji mamy atrybuty:

MUIA_TopEdge
MUIA_BottomEdge
MUIA_LeftEdge
MUIA_RightEdge


Te cztery atrybuty opisują położenie odpowiednio górnej, dolnej, lewej i prawej krawędzi obiektu. Mamy też atrybuty opisujące bezpośrednio jego szerokość i wysokość:

MUIA_Width
MUIA_Height


Wszystkie te atrybuty mają wartości wyrażone w pikselach w odniesieniu do lewego górnego rogu okna (wraz z ramkami). Są one atrybutami tylko do odczytu i co ważne ich wartości są prawidłowe tylko wtedy, gdy okno zawierające dany obiekt jest otwarte.

Wygląd gadżetów

Samo rozmieszczenie gadżetów to jeszcze nie wszystko, należy zadbać o odpowiedni ich wygląd. Przede wszystkim trzeba określić obiektom ramkę i tło, oraz, w przypadku gadżetów z tekstem, czcionkę. Służą do tego atrybuty:

MUIA_Background - tło,
MUIA_Frame - ramka,
MUIA_Font - czcionka.


Jeżeli nie podamy dla obiektu ramki, nie będzie miał żadnej, jeżeli nie podamy tła - obiekt "odziedziczy" tło po grupie go zawierającej. Nie podając czcionki powodujemy użycie przez MUI czcionki wybranej przez użytkownika jako normalna. Jeżeli ustawiamy obiektom te atrybuty, wybieramy właśnie wartości ustawione przez użytkownika w preferencjach, mają one umowne identyfikatory. Oczywiście chcemy aby nasze GUI było czytelne, więc do odpowiednich gadżetów używamy odpowiednich ramek, czcionek i teł. Program, w którym gadżety tekstowe mają ramki przycisków i odwrotnie, obsługuje się niezbyt przyjemnie, niestety takie programy się zdarzają... Identyfikatorów poszczególnych typów ramek itd. nie będę tu wymieniał, są one zdefiniowane w pliku "libraries/mui.h" ("libraries/mui.m" w języku E). Wspomnę jedynie o możliwości tworzenia ramek z tytułem. Takie ramki często stosuje się do grup, aby optycznie wydzielić grupę gadżetów o wspólnym przeznaczeniu. W przypadku wzięcia grupy w ramkę należy również ustawić jej odpowiednie tło (MUII_GroupBack). Grupę w zatytułowanej ramce tworzymy więc w następujący sposób:

grupa = MUI_NewObject (MUIC_Group
  MUIA_Background, MUII_GroupBack,
  MUIA_Frame, MUIV_Frame_Group,
  MUIA_FrameTitle, "Ważna grupa",
  /* ... */
  TAG_END);


Ustawienie właściwej czcionki to czynność bardzo ważna. Trzeba poświęcić jej trochę uwagi, a zdarzają się przy tym błędy nawet w bardzo znanych programach. Do dyspozycji mamy następujące czcionki: MUIA_Font_Normal, MUIA_Font_Tiny, MUIA_Font_Big - są to trzy czcionki standardowe, używane w typowych sytuacjach (to znaczy, gdy nie zachodzi konieczność użycia którejś z czcionek wymienionych poniżej). Czcionką Normal robimy np. podpisy (etykiety) do gadżetów. Czcionkę Tiny stosujemy do jakichś mało ważnych napisów, a Big gdy chcemy coś napisać wołami (np. w okienku "O programie").

MUIA_Font_Button - do wszelkich przycisków i gadżetów cyklicznych.

MUIA_Font_List - czcionka używana w gadżetach listowych (ListView).

MUIA_Font_Fixed - czasem potrzebna jest czcionka nieproporcjonalna.

MUIA_Font_Title - to jest czcionka używana na tytuły grup. Tytuły ramek są wyświetlane tą czcionką automatycznie, ale gdy chcemy coś zatytułować "ręcznie" powinniśmy użyć tej czcionki.

I to by było na tyle tym razem, w następnej części przyjrzymy się szczegółowo kilku najczęściej używanym klasom gadżetów. Tradycyjnie dołączam przykładowy program - proste GUI do przykładu z poprzedniej części. Również tym razem w dwóch wersjach - E i C. A więc do klawiatur Panie i Panowie, życzę czerwonego Guru :-). Dodatek - tutaj.

 głosów: 2   
dodaj komentarz
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem