poniedziałek, stycznia 05, 2009

Swing - największe zło Java'y ;-)

Wiecie co?
Już chyba wiem czemu Java nie trafiła nigdy do mainstreamu aplikacji desktopowych.

To wszystko z powodu Swinga.

I nie chodzi o jego wygląd, bo brzydki nie jest, ale o jego programowanie.

Dziś dodałem do OpenOffice.org2GoogleDocs bardziej intuicyjne [mam nadzieję ;-)] UI do updatowania i eksportowania dokumentów do Google Docs.

Idea jest taka: gdy użytkownik kliknie na ikonkę pokazujemy mu okienko eksportu i zakładamy, że użytkownik chce stworzyć nowy dokument:

rysunek 1


Jeżeli użytkownik chce zamiast utworzenia nowego dokumentu zdecydować się na aktualizację istniejącego to wybiera dokument z listy:


rysunek 2


Gdy go wybierze widzi coś takiego:

rysunek 3


Jeżeli kliknie na edytorku i zmieni nazwę dokumentu to zakładamy, że chce stworzyć nowy dokument [może kiedyś to zmienię tak by user mógł zrobić update i zmienić nazwę, na razie to wydaje mi się być bardziej logiczne]:

rysunek 4


Niby banał... ale...
Samo wyświetlenie listy, którą widzimy na rysunku 2 to nowa klasa:

class MyCellRenderer extends JComponent implements ListCellRenderer

której zadaniem jest stworzenie komponentu który ma zostać wyświetlony na liście.
Sama klasa MyCellRenderer liczy sobie ponad 60 linii :-)
Własny "edytorek" widoczny na wszystkich rysunkach [czyli to gdzie znajduje się nazwa pliku i gdzie można ją edytować] to kolejna klasa:

class MyEditorRenderer extends JComponent implements ComboBoxEditor

Klasa MyEditorRenderer liczy sobie prawie 100 linii [z tym, że zawiera jeszcze dwie klasy wewnętrzne w sobie].
Ale żeby edytorek działał tak, że że w momencie zmiany tekstu w nim zmieniał się także tekst obok [czyli z [update] na [new]] konieczne są jeszcze dwie nowe klasy ;-)
Anonimowy listener implementujący DocumentListener [kod tutaj], którego zadaniem jest wychwytywanie zmian w treści dokumentu [czyli wartości przechowywanej w edytorku], który ma tą przypadłość, że jest wywoływany także wtedy gdy ustawiamy właśnie nazwę dokumentu [czyli tekst w JTextField], a to niestety dzieje się tak jakby trochę poza naszą kontrolą bo chyba w wątku EDT i nie mamy nad tym kontroli [czyli nie możemy tego wykryć].
Oraz anonimowego listenera rozszerzającego MouseAdapter [kod tutaj], którego zadanie sprowadza się tylko do tego by w momencie kliknięcia edytorka podpiąć do niego poprzednią klasę......

Straszny mętlik, nie? ;-)

W dHTMLu, czyli w moim przypadku HTMLu i JavaScript'cie byłoby tego o wiele mniej.
Zakładając, że miałbym już komponent podobny do JComboBox to zaimplementowanie czegoś takiego jak to wyżej byłoby o jakieś 50 razy prostsze ;-)
A całe czary z obserwowaniem edytorka załatwiłoby proste zdarzenie onChange ;-)

W swoim 30 letnim życiu ;-) miałem już do czynienia z paroma sposobami obsługi GUI, ale ten w Swingu jest straszny. Zrozumienie WinAPI w sposób pozwalający mi na pisanie w miarę rozbudowanych aplikacji zajęło mi całe 2 albo 3 dni, w przypadku Delphi w ogóle nie musiałem się tym przejmować, to samo w WinForms... Swinga używałem przez półtora roku pracy w Motoroli, od ponad roku w tworzeniu OpenOffice.org2GoogleDocs i nadal niewiele potrafię...

Np. w ramach moich zabaw z rysowaniem kodu postanowiłem pójść inną drogą i dla każdego elementu języka takiego jak IfStatement, ForStatement i podobne stworzyć nowy komponent Swing, który narysuje odpowiednio kod...... I wynik w chwili obecnej jest taki:

Niby nie jest źle... ale, czy ktoś może mi powiedzieć czemu w IfStatement po prawej stronie pod c++; i c--; nie narysowały się linie? Przecież ja je rysuję i one się też rysują, ale później znikają.......
W ramach dmuchania na zimne zmieniłem kod paintComponent komponentu by wyglądał tak:

protected void paintComponent(Graphics g) {
int x1 = thenComp.getLocation().x+thenComp.getWidth()/2;
int x2 = elseComp.getLocation().x+elseComp.getWidth()/2;
int y1 = upperPanel.getLocation().y+upperPanel.getHeight();
int y2 = lowerPanel.getLocation().y;
g.setColor(Color.RED);
g.drawLine(x1, y1, x1, y2);
g.drawLine(x2, y1, x2, y2);
super.paintComponent(g);
g.setColor(Color.RED);
g.drawLine(x1, y1, x1, y2);
g.drawLine(x2, y1, x2, y2);
}

Czyli maluje 2 razy te nieszczęsne linie! I nic :-) Nie ma ich :-)
Próbowałem też innych ujęć, wg. tego jak to się powinno robić [czyli np. super metoda była wykonywana na obrazku, który później sam rysowałem i inne takie] i nic....
BorderLayout wie lepiej i coś robi żeby mu było wygodniej.

I jak tu się dziwić temu, że ludzie nie piszą zbyt wiele w Swingu? ;-)

Teraz będzie JavaFX, która obiecuje między innymi wygodniejsze tworzenie GUI, ale nie do końca im wierzę. Widziałem kawałki kodu i robiłem nawet jakiś przykład i jest to chyba nawet bardziej zakręcone.


Podobne postybeta
Najkrótsza droga do przyszłości - Polymer ;-)
Pomnóżmy sobie duże liczby ;-)
Trygonometria trudna
Potworność ;-) czyli mnożenie w 90 liniach ;-)
Nie podoba mi się idea "wszystko jest aplikacją webową"