Standard Widget Toolkit ECESIS Eclipse Community Education Project An Eclipse Technology Research Subproject Standard Widget Toolkit Jak budować interfejs użytkownika?
Topics SWT czy Swing? Terminologia Prosty program w SWT Wzorzec Observer Widgets Menus Layouts Graphics Drag and Drop
Swing Biblioteka GUI w javie (javax.swing.*) Była mało wydajna (poprawiono w Java 1.4) Napisana w Javie (korzysta AWT – Java / C) Niezależna platformowo (daleko od OS) Swing java.awt sun.awt Operating system
SWT Zależna od platformy (dostępne implementacje dla większości popularnych platform) Wykorzystuje komponenty OS (JNI) – dispose! Tylko kontrolki nie obsługiwane przez dany system zostały stworzone Posiada wsparcie w postaci JFace JFace SWT JNI Windowing system Operating system
SWT vs. Swing Zależny od platformy Niezależny od platformy Niewydajny Wydajny (Komponenty z systemu operacyjnego) Wykorzystuje wzorzec observer Menadżery rozmieszczenia Niezależny od platformy Niewydajny Look and Feel Wykorzystuje wzorze observer Menadżery rozmieszczenia JFace SWT Swing JNI java.awt sun.awt Windowing system Operating system Operating system
org.eclipse.swt.SWT Klasa z polami static public Dostarcza stałe dla SWT Bez instancji (eg. SWT.BOLD) Stałe w SWT można sumować bitowo (eg. SWT.BOLD | SWT.ITALIC) SWT
Terminy Display Połączenie między SWT i systemem GUI danej platformy Wykorzystywana do zarządzania pętlą komunikatów i wątkami UI Shell Okno zarządzane przez Window menadżer danego OS Composite Widget, który może zawierać inne widgety Layout manager Klasa odpowiedzialna za zarządzanie rozkładem
Jak uruchomić program w SWT? classpath SWT.jar library (eclipse/plugins) Add to the JVM arguments Djava.library.path=<katalog z dll> albo wybrać Run as ... SWT Application JFace wymaga bibliotek: org.eclipse.jface_x.jar, org.eclipse.core.commands_x.jar, org.eclipse.equinox.common_x.jar, (org.eclipse.osgi) Podczas pisania pluginów nie trzeba się tym martwić!
Basic SWT application Snippet public static void main(String[] args) { Display display = new Display(); Shell shell = new Shell(display); Label label = new Label(shell, SWT.CENTER); label.setText(”Witaj świecie"); label.pack(); shell.pack(); shell.open(); while (!shell.isDisposed ()) { if (!display.readAndDispatch ()) display.sleep (); } display.dispose (); BaseSWTJFace w czystej formie, przygotowac projekt – zaleznosci bibliotek i wspolnie napisac najprostsza aplikację tlumaczac (potem będziemy raczej wklejac ale na poczatku warto żeby każdy napisal kawalek kodu) Snippet
Proszę nie dzwonić, to my zadzwonimy… Wzorzec Observer Następny proszę! Lalaaaalalaa! Dziękujemy. Proszę nie dzwonić, to my zadzwonimy… Broadway
Wzorzec Observer
SWT&Observer Object public void addListener (int eventType, Listener listener) Widget public interface Listener { void handleEvent (Event event); } Control Button Scrollable public void addSelectionListener (SelectionListener listener) public interface SelectionListener extends SWTEventListener { public void widgetSelected(SelectionEvent e); public void widgetDefaultSelected(SelectionEvent e); } Composite
Composite Pattern Idea
Wzorzec Composite
SWT&Composite public Control (Composite parent, int style) Object public Control (Composite parent, int style) Widget Button button = new Button(shell,SWT.PUSH); * Control Button Scrollable Composite
Widgets
Label Snippet Label label = new Label(shell, SWT.CENTER); label.setText("Hello World"); label.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_BLUE)); LabelsSnippet Snippet
Button Snippet Button button = new Button(shell, SWT.PUSH); button.setText("Click me!"); Button button = new Button(shell, SWT.CHECK); button.setText("Click me!"); Button button = new Button(shell, SWT.ARROW|SWT.RIGHT); Button button = new Button(shell, SWT.RADIO); button.setText("Click me!"); ButtonsSnippet Button button = new Button(shell, SWT.TOGGLE); button.setText("Click me!");
Button Usage Snippet Button {Click me!} was clicked! Button button = new Button(shell, SWT.PUSH); button.setText("Click me!"); button.addSelectionListener(new SelectionListener(){ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { System.out.println(e.getSource().toString()+" was clicked!"); }); ButtonsSnippet Button {Click me!} was clicked! Snippet
Text Snippet Text text = new Text(shell, SWT.SINGLE | SWT.BORDER); text.setText("Text"); Text text = new Text(shell, SWT.MULTI | SWT.BORDER | SWT.VERTICAL); text.setText("Text\nText"); TextsSnippet Text text = new Text(shell, SWT.PASSWORD | SWT.SINGLE | SWT.BORDER); text.setText("Text"); Snippet
Text Usage Text text = new Text(shell, SWT.SINGLE | SWT.BORDER); text.addVerifyListener(new VerifyListener(){ public void verifyText(VerifyEvent e) { if (e.text.matches("[0-9]*")){ e.doit = true; }else{ e.doit = false; } }); text.addModifyListener(new ModifyListener(){ public void modifyText(ModifyEvent e) { System.out.println(((Text)(e.widget)).getText()+ " - text after modification"); } }); TextsSnippet 2 - text after modification 23 - text after modification 232 - text after modification 2321 - text after modification 23212 - text after modification 232123 - text after modification 2321231 - text after modification Snippet
ProgressBar Snippet ProgressBar pb = new ProgressBar(shell, SWT.SMOOTH); pb.setMinimum(0); pb.setMaximum(100); pb.setSelection(34); ProgressbarSnippet ProgressBar pb = new ProgressBar(shell, SWT.SMOOTH | SWT.INDETERMINATE); pb.setMinimum(0); pb.setMaximum(100);
Slider and Scale Snippet Slider slider = new Slider(shell, SWT.HORIZONTAL); slider.setMinimum(0); slider.setMaximum(100); slider.setSelection(30); Snippet Scale scale = new Scale(shell, SWT.HORIZONTAL); scale.setMinimum(0); scale.setMaximum(100); scale.setSelection(30); SlidersSnippet
List Snippet List list = new List(shell, SWT.MULTI); list.add("First"); list.add("Second"); list.add("Third"); list.addSelectionListener(new SelectionListener(){ public void widgetDefaultSelected(SelectionEvent e) { System.out.println("Default action - double click(Windows)"); widgetSelected(e); } public void widgetSelected(SelectionEvent e) { System.out.println("Selected items:"); String[] selection = ((List)(e.widget)).getSelection(); for (int i = 0; i < selection.length; i++) { System.out.println(" - "+selection[i]+""); }); ListComboSnippet
Combo Snippet Combo combo = new Combo(shell, SWT.DROP_DOWN); combo.add("First"); combo.add("Second"); combo.add("Third"); combo.addSelectionListener(new SelectionListener(){ public void widgetDefaultSelected(SelectionEvent e) { System.out.println("Default action - Enter (Windows)"); widgetSelected(e); } public void widgetSelected(SelectionEvent e) { System.out.println("Selected "+((Combo)(e.widget)).getText()); }); ListComboSnippet
Tree Snippet Tree tree = new Tree(shell, SWT.SINGLE); TreeItem node1 = new TreeItem(tree, SWT.NULL); node1.setText("1. Main node"); TreeItem node11 = new TreeItem(node1, SWT.NULL); node11.setText("1.1 First sub node"); TreeItem node12 = new TreeItem(node1, SWT.NULL); node12.setText("1.2 First sub node"); tree.addTreeListener(new TreeListener(){ public void treeCollapsed(TreeEvent e) { System.out.println(((TreeItem)e.item).getText()+ " was collapsed"); } public void treeExpanded(TreeEvent e) { System.out.println(((TreeItem)e.item).getText()+ " was expanded"); }); Snippet TreeSnippet
Menu Snippet Menu menuBar = new Menu(shell, SWT.BAR); shell.setMenuBar(menuBar); MenuItem fileTitle = new MenuItem(menuBar, SWT.CASCADE); fileTitle.setText("File"); Menu fileMenu = new Menu(shell, SWT.DROP_DOWN); fileTitle.setMenu(fileMenu); MenuItem exitItem = new MenuItem(fileMenu, SWT.PUSH); exitItem.setText("Exit"); exitItem.addSelectionListener(new SelectionListener(){ public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { ((MenuItem)(e.widget)).getParent().getShell().close(); }); SWT.BAR SWT.DROP_DOWN SWT.POP_UP setManuBar – SWT.BAR setMenu – SWT.POP_UP SWT.CHECK SWT.CASCADE SWT.PUSH SWT.RADIO SWT.SEPARATOR Snippet
Layouts Kontroluje rozmiar i rozmieszczenie komponentów Klasy menadżerów, są podklasami abstrakcyjnej klasy Layout SWT udostępnia kilka podstawowych layout’ów FillLayout, rozmieszcza komponenty w rzędzie lub w kolumnie, równych rozmiarów, wypełniając dostępne miejsce RowLayout, ustawia komponenty w rzędzie lub kolumnie GridLayout, wpisuje komponenty w siatkę FormLayout, ustawia komponenty doczepiając je między sobą
Praca z Layout’ami Importujemy odpowiedni pakiet SWT: import org.eclipse.swt.layout.*; Aby przypisać Layout obiektowi klasy Composite użyj setLayout(Layout) Display display = new Display(); Shell shell = new Shell(display); shell.setLayout(new FillLayout());
Layout Data RowLayout -> RowData GridLayout -> GridData Klasy layout’ów często wykorzystują pomocnicze klasy nazywane ogólnie LayoutData RowLayout -> RowData GridLayout -> GridData FormLayout -> FormData Przypisanie danych układu Button button = new Button(shell, SWT.PUSH); button.setLayoutData(new RowData(10, 20));
FillLayout Ustawia komponenty w rzędzie lub kolumnie Wszystkie tego samego rozmiaru Bez zawijania wierszy Nie można zdefiniować marginesów i odstępów Wykorzystywany do: Umieszczanie przycisków na paskach zadań Umieszczania checkbox’ów w grupy If a Shell has a single Group child, FillLayout will cause the Group to completely fill the Shell.
FillLayout Example Display display = new Display(); Shell shell = new Shell(display); FillLayout fillLayout = new FillLayout(); fillLayout.type = SWT.VERTICAL; shell.setLayout(fillLayout); new Button(shell, SWT.PUSH).setText("1'st Button"); new Button(shell, SWT.PUSH).setText("Big Button"); new Button(shell, SWT.PUSH).setText("Button 3"); new Button(shell, SWT.PUSH).setText("Last Button"); shell.pack(); shell.open();
FillLayout Example Snippet fillLayout.type = SWT.VERTICAL; fillLayout.type = SWT.HORIZONTAL; FillLayoutSnippet Snippet
RowLayout RowLayout ma możliwość zawijania wierszy Można ustawiać marginesy i odległości Różne właściwości mogą zostać ustawione Wysokość i szerokość widget’ów Użyj obiektu klasy RowData
RowLayout Example RowLayout rowLayout = new RowLayout(); rowLayout.wrap = true; rowLayout.pack = true; rowLayout.justify = true; rowLayout.type = SWT.HORIZONTAL; rowLayout.marginLeft = 4; rowLayout.marginTop = 4; rowLayout.marginRight = 4; rowLayout.marginBottom = 4; rowLayout.spacing = 0; shell.setLayout(rowLayout);
RowLayout Example rowLayout.wrap = false; rowLayout.pack = false; rowLayout.justify = false;
RowData Example RowLayout rowLayout = new RowLayout(); shell.setLayout(rowLayout); Button button1 = new Button(shell, SWT.PUSH); button1.setText("First"); button1.setLayoutData(new RowData(50, 100)); Button button2 = new Button(shell, SWT.PUSH); button2.setText("Second"); button2.setLayoutData(new RowData(200, 400));
GridLayout Chyba najczęściej wykorzystywany Najbardziej rozbudowany Komponenty wpisane w siatkę Kolumny i rzędy dostowują się do wielkości zawartości Różne wartości mogą zostać ustawione Do komponentów można dodawać GridData
GridLayout Example GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 2; shell.setLayout(gridLayout); new Button(shell, SWT.PUSH).setText("B1"); new Button(shell, SWT.PUSH).setText("Second Button"); new Button(shell, SWT.PUSH).setText("Third Button"); new Button(shell, SWT.PUSH).setText("B4"); new Button(shell, SWT.PUSH).setText("B5"); new Button(shell, SWT.PUSH).setText("Button Number 6");
GridLayout Fields Pola makeColumnsEqualWidth narzuca kolumną równą szerokość marginWidth ustala lewy i prawy margines marginHeight ustala górny i dolny margines horizontalSpacing i verticalSpacing odległości między komponentami
GridData Zawiera wskazówki dla GridLayout Dodaje się za pomocą metody setLayoutData Button aButton = new Button(shell, SWT.PUSH); aButton.setText("FirstButton"); aButton.setLayoutData(new GridData());
GridData Fields horizontalAlignment: specyfikuje gdzie umiścić widget horyzontalnie lub wertykalnie w komórce siatki BEGINNING, CENTER, END, FILL horizontalIndent: umożliwia przesunięcie kontrolki w prawo o wybraną liczbę pixeli Użyteczne kiedy horizontalAlignment jest BEGINNING horizontalSpan i verticalSpan: jedna kontrolka może zajmować kilka komórek
GridData Fields grabExcessHorizontalSpace i grabExcessVerticalSpace: pozwala kontrolkom zwiększać rozmiar jeśli ich rodzic zmienia rozmiar widthHint i heightHint: zalecany rozmiar kontrolki GridDataSnippet Snippet
Ćwiczenie
Ćwiczenie
Ćwiczenie - rozwiązanie GridLayout gridLayout = new GridLayout(); gridLayout.numColumns = 3; shell.setLayout(gridLayout); new Label(shell, SWT.NONE).setText(„Name:"); Text userName = new Text(shell, SWT.SINGLE | SWT.BORDER); GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL); gridData.horizontalSpan = 2; userName.setLayoutData(gridData); … Każdy widget musi mieć własną instancję GridData
Ćwiczenie - rozwiązanie new Label(shell, SWT.NONE).setText(”Sex:"); Combo sex = new Combo(shell, SWT.NONE); sex.setItems(new String [] {"Male", "Female"}); gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL); gridData.horizontalSpan = 2; sex.setLayoutData(gridData); new Label(shell, SWT.NONE).setText("Photo:"); Canvas photo = new Canvas(shell, SWT.BORDER); gridData = new GridData(GridData.FILL_BOTH); gridData.widthHint = 80; gridData.heightHint = 80; gridData.verticalSpan = 3; photo.setLayoutData(gridData);
GridData Example
FormLayout Tworzy FormAttachments dla krawędzi widget’a Przechowuje attachments jako layout data Przyłącza krawędź relatywnie do Composite’a rodzica innego widget’a w ramach layout’u Pozwala w pełni wyspecyfikować położenie widgetu http://www.eclipse.org/articles/Article-Understanding-Layouts/Understanding-Layouts.htm
Graphics GC – Graphics Context (można rysować po wszystkich klasach które implementują interfejs Drawable (np. Image, Control, Canvas itd.) Jeśli używasz konstruktora GC(), nie zapomnij dispose! Rysowania dokonujemy wewnątrz metody paintControl(PaintEvent) należącej do PaintListener Composite.addPaintListener(new PaintListener(){ public void paintControl(PaintEvent event){ Display display = event.display; GC gc = event.gc gc.drawRectangle(0,0,10,10); } });
Color Domyślne kolory systemowe można uzyskać przy pomocy Display poprzez metodę getSystemColor(id) (SWT.COLOR...), ich nie wolno disposować Albo new Color(device, 255, 255, 255), te kolory należy usuwać Device -> Display, Printer
Fonts Domyśną czionkęmożna uzyskać poprzez klasę Display wywołując metodę getSystemFont() Albo stworzyć obiekt Font new Font(device, ”Arial”, 12, SWT.BOLD); new Font(device, new FontData(”Arial”,12,SWT.BOLD)); Device -> Display, Printer Należy je usuwać!
Drag and drop Drag Source – dostarcza dane które mają być upuszczone Ten sam widget Inny widget Inna aplikacja! Transfer object – obiekt do przenoszenia danych (np. dla plików FileTransfer – przechowuje lokalizacje plików) Drop Target – odbiorca danych
DragSource Example final Label dragLabel = new Label(shell, SWT.BORDER); dragLabel.setText("text to be transferred"); int operations = DND.DROP_MOVE | DND.DROP_COPY; DragSource source = new DragSource(dragLabel, operations); Transfer[] types = new Transfer[] { TextTransfer.getInstance() }; source.setTransfer(types); source.addDragListener(new DragSourceListener() { public void dragStart(DragSourceEvent event) { if (dragLabel.getText().length() == 0) { event.doit = false; } public void dragSetData(DragSourceEvent event) { if (TextTransfer.getInstance().isSupportedType(event.dataType)) { event.data = dragLabel.getText(); public void dragFinished(DragSourceEvent event) { if (event.detail == DND.DROP_MOVE) dragLabel.setText(""); });
DropTarget Example Snippet final Text dropText = new Text(shell, SWT.BORDER); operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT; DropTarget target = new DropTarget(dropText, operations); final TextTransfer textTransfer = TextTransfer.getInstance(); target.setTransfer(new Transfer[]{textTransfer}); target.addDropListener(new DropTargetAdapter() { public void drop(DropTargetEvent event) { if (textTransfer.isSupportedType(event.currentDataType)) { String text = (String) event.data; dropText.setText(text); } }); DragAndDropSnippet Snippet
SWT - Koniec Dziękuje slides.dispose()