JTabbedPane na ligolu (max os x)

Maszyna wirtualna Javy na maku nie jest napisana przez SUN'a, tylko przez samego Apple'a. Dobry Wujek chciał, żeby programy napisane w javie wyglądały bardziej "makowo" niż "metalowo". Napisał więc własny LookAndFeel - Aqua. I o ile można się zgodzić, że gdzieniegdzie wygląda ładnie, to jednak niekiedy Wujek przegiął. Pomijam drobnostki w stylu guzików, które różnią się w przypadku, gdy doda się do nich ikonkę od tych tylko z napisem. Dużo większy problem jest w przypadku zakładek, czyli JTabbedPane. Dla jednej, dwóch czy też trzech zakładek z krótkimi nazwami jest wszystko ok. Problem pojawia się gdy chcemy mieć więcej zakładek. W większości L&F możemy sterować zachowaniem paska zakładek - czy ma być utrzymana jedna linia, czy też mają się zawijać tak, aby wszystkie były widoczne. Na ligolu działa tylko jedna opcja - zawsze jeden wiersz. Być może wynika on z zasady, że im prostsze, tym lepsze, ale akurat w tym przypadku stanowi ogromy problem.


To jest przykładowy pasek z ulubionego przeze mnie środowiska deweloperskiego - IntelliJ Idea. Miałem tam otwartych z 10 czy 15 plików. Na pasku zmieściły się tylko trzy.

Pewną próbą wyjścia z sytuacji jest możliwość wciśnięcia (myszką) jednej ze strzałek po bokach - wtedy pojawi się lista ukrytych zakładek. Jednak i tu jest pewien szkopuł - pojawiają się ukryte zakładki, ale tylko po danej stronie. Oznacza to, że chcąc sprawdzić jakie pliki mam otwarte i znaleźć ten, na których chcę się przełączyć muszę kliknąć na lewą strzałkę. Jak nie znajdę, to potem prawą strzałkę. Uciążliwe i mocno niewygodne.





Rozwiązaniem dużej ilości zakładek jest umieszczenie ich z prawej lub lewej strony. Standardowo (metalowo) napisy umieszczane są wtedy poziomo, co powoduje, że nawet jak zakładek będzie sporo, to wszystkie będą widoczne.
A co przygotował nam Wujek? Ano pomyślał, że ładniej będzie, jak napisy będą pionowe. W efekcie nic nie widać (albo widać jedną pozycję Happy). Dostosowanie JTabbedPane do "standardowego" wyglądu na ligolu ma zatem sens w szczególności wtedy, gdy wykorzystujemy większą ilość zakładek. Dla mnie... praktycznie zawsze Happy
Co możemy zatem zrobić? Możemy oczywiście próbować standardowego dla javy L&F czyli cross-platform metalu. Ale niestety to niesie za sobą komplikacje związane ze zmianą mapowań skrótów klawiszy (np. kopiuj/wklej). Z tymi skrótami to w ogóle jest odrębny temat, ale używać metalu na maku w zasadzie się nie da. Najlepiej by było zatem, gdyby można było zostawić Apple'owy ale nieco go zmodyfikować...
Na szczęście da się Happy
Wrzucenie poniższego kodu gdzieś w inicjalizacji aplikacji pozwoli cieszyć się normalnymi zakładkami. Cała magia tkwi w podmianie
UI dla TabbedPane i podaniu właściwych wartości w poszczególnych atrybutach konfiguracyjnych. Posłużyłem się wartościami domyślnymi z wieloplatformowego L&F. Pozostawienie zakomentowanych wierszy da lepsze dopasowanie kolorystyczne. Cały kod można oczywiście umieścić niezależnie od docelowej platformy - uaktywni się tylko na makach (intelowych, wcześniej tego problemu nie było, bo Wujek jeszcze nie rozwinął skrzydeł Happy).


final String lcOSName = System.getProperty("os.name").toLowerCase();
final boolean MAC_OS_X = lcOSName.startsWith("mac os x");
if (MAC_OS_X) {
System.out.println("MAC OS detected (" + lcOSName + "), setting extra UIManager resources for TabbedPane");
UIManager.put("TabbedPaneUI", "javax.swing.plaf.metal.MetalTabbedPaneUI");
UIManager.put("TabbedPane.selectedTabPadInsets", new Insets(2, 2, 2, 1));
UIManager.put("TabbedPane.tabsOpaque", Boolean.TRUE);
UIManager.put("TabbedPane.darkShadow", new Color(122, 138, 153));
//UIManager.put("TabbedPane.background", new Color(184,207,229));
UIManager.put("TabbedPane.selectHighlight", new Color(255, 255, 255));
//UIManager.put("TabbedPane.foreground", new Color(51,51,51));
UIManager.put("TabbedPane.textIconGap", 4);
UIManager.put("TabbedPane.highlight", new Color(255, 255, 255));
UIManager.put("TabbedPane.unselectedBackground", new Color(238, 238, 238));
UIManager.put("TabbedPane.tabRunOverlay", 2);
UIManager.put("TabbedPane.light", new Color(238, 238, 238));
UIManager.put("TabbedPane.tabsOverlapBorder", Boolean.FALSE);
UIManager.put("TabbedPane.selected", new Color(200, 221, 242));
UIManager.put("TabbedPane.contentBorderInsets", new Insets(4, 2, 3, 3));
UIManager.put("TabbedPane.contentAreaColor", new Color(220, 221, 242));
UIManager.put("TabbedPane.tabAreaInsets", new Insets(2, 2, 0, 6));
UIManager.put("TabbedPane.contentOpaque", Boolean.TRUE);
UIManager.put("TabbedPane.focus", new Color(99, 130, 191));
UIManager.put("TabbedPane.tabAreaBackground", new Color(218, 218, 218));
UIManager.put("TabbedPane.shadow", new Color(184, 207, 229));
UIManager.put("TabbedPane.tabInsets", new Insets(0, 9, 1, 9));
UIManager.put("TabbedPane.borderHightlightColor", new Color(99, 130, 191));
}

Co otrzymamy w zamian? Niech poniższe screeny mówią same za siebie Happy


i jeszcze widok zakładek umieszczonych na dole.


Na koniec taka mała uwaga - użytkownicy mojej ulubionej IDEI zapewne zauważyli, że ten problem dotyka także i ich (w każdym razie do wszystkich wersji przed 8-mką). Posłużyłem się powyższą sztuczką podmiany właściwości L&F, ale ponieważ nie mam dostępu do kodów źródłowych to musiałem... ale o tym napiszę następnym razem Happy

blog comments powered by Disqus