Lekce 24 - Java chat - Klient - Dokončení 2. část
V minulé lekci, Java chat - Klient - Dokončení 1. část, jsme započali práce na GUI našeho chat klienta v Javě.
V dnešním posledním Java tutoriálu dokončíme implementaci chat klienta a tím i uzavřeme celou sérii o tvorbě Java serveru.
Obsluha pro zobrazení konverzace
Začneme tím, že zobrazíme konverzaci s vybraným uživatelem. Při
dvojitém kliknutí na uživatele v ListView
se zobrazí buď nová
záložka s konverzací, nebo se přepne na již existující konverzaci. Ve
třídě MainController
vytvoříme novou konstantu, která bude
obsahovat anonymní funkci, která bude obsluhovat dvojité kliknutí do
ListView
:
private final EventHandler <<? super MouseEvent> listContactsClick = event -> { final int clickCount = event.getClickCount(); if (clickCount != 2) { return; } final ChatContact contact = lvContactList.getSelectionModel().getSelectedItem(); if (contact == null) { return; } showConversation(contact); };
Na začátku se zkontroluje, zda-li jsme opravdu klikli 2x. Pokud podmínka
není splněna, nebude se nic provádět. Dále zkontrolujeme, že jsme klikli
na nějaký kontakt a ne do prázdného místa. Pokud jsme klikli na kontakt,
zobrazíme konverzaci metodou showConversation()
.
Zobrazení vybrané konverzace
Vybranou konverzaci budeme zobrazovat pomocí metody
showConversation()
:
private void showConversation(ChatContact contact) { final Optional <ChatTab> optionalTab = paneChatContainer.getTabs() .stream() .filter(tab -> tab.getUserData() == contact) .map(tab -> (ChatTab) tab) .findFirst(); if (optionalTab.isPresent()) { paneChatContainer.getSelectionModel().select(optionalTab.get()); } else { paneChatContainer.getTabs().add(makeNewTab(contact)); } }
Metoda přijímá jako parametr instanci třídy ChatContact
,
která představuje kontakt, pro který chceme zobrazit konverzaci. Nejdříve
se podíváme, zda-li je již konverzace v TabPane
přítomna.
Pokud ano, jednoduše na ní přepneme metodou select()
. V
opačném případě vytvoříme novou záložku s konverzací a vložíme ji
mezi ostatní konverzace.
Vytvoření nové konverzace
Vytvoření nové konverzace necháme na samostatnou metodu, kterou nazveme
makeNewTab()
:
private ChatTab makeNewTab(ChatContact chatContact) { final ChatTab chatTab = new ChatTab(chatContact); chatTab.setUserData(chatContact); return chatTab; }
Nejdříve vytvoříme novou instanci třídy ChatTab
. Metodou
setUserData()
nastavíme vlastní uživatelská data. Těchto dat
pak využíváme v předchozím kódu, kde filtrujeme Tab
podle
zadaného kontaktu.
Registrace obsluhy pro zobrazení konverzace
Nakonec v metodě initialize()
zaregistrujeme obsluhu na
kliknutí pro ListView
:
lvContactList.setOnMouseClicked(this.listContactsClick);
Test funkčnosti
Nyní, když pustíte server, pustíte klienta, připojíte se na server a
zobrazí se v ListView
jediný kontakt - Vy, můžete na tento
kontakt 2x kliknout a zobrazí se v pravé části okna nová záložka s
konverzací.

Odeslání zprávy
V následující části implementujeme odeslání zprávy. Do textového pole budeme moci psát pouze tehdy, je-li vybrána nějaká konverzace. Tlačítko pro odeslání bude přístupné pouze za předpokladu, že textové pole obsahuje nějaký text. Začneme tedy implementací těchto podmínek.
Ovládání prvků
Ovládání prvků nastavíme v metodě initialize()
. Nejdříve
ovládání tlačítka. Tlačítku nabindujeme vlastnost
disableProperty()
na textProperty().isEmpty()
.
btnSend.disableProperty().bind(txtMessage.textProperty().isEmpty());
Textové pole nabindujeme podobným způsobem:
txtMessage.disableProperty().bind(paneChatContainer.getSelectionModel().selectedItemProperty().isNull());
Obsluha tlačítka pro odeslání zprávy
Při stisku tlačítka odeslat se odešle zpráva. Již máme veškerou potřebnou logiku implementovanou, stačí ji jen zavolat:
private void handleSendMessage(ActionEvent actionEvent) { final ChatTab tab = (ChatTab) paneChatContainer.getSelectionModel().getSelectedItem(); if (tab == null) { return; } final String id = ((ChatContact) tab.getUserData()).getId(); final String message = txtMessage.getText(); chatService.sendMessage(id, message); txtMessage.clear(); txtMessage.requestFocus(); }
Nejdříve se otestuje, zda-li máme otevřený Tab
. Pokud ne,
metoda nic neprovede. Id kontaktu získáme z uživatelských dat v
Tab
u a obsah zprávy z textového pole. Nakonec zavoláme naši
service, která se postará o odeslání zprávy. Následuje vymazání
textového pole a požadavek o získání fokusu, abychom mohli znovu psát.
Zobrazení zpráv
Přijaté zprávy již mají implementovanou veškerou logiku, takže po odeslání zprávy se automaticky zobrazí. Pokud zrovna konverzace nebude zobrazena, zobrazí se v kontakt listu napravo od jména počet nepřečtených zpráv.
Informace o psaní
Nyní implementujeme funkci, která bude uživatele informovat, zda-li klient
na druhém konci píše, či nikoliv. Ve třídě MainController
založíme novou třídní konstantu, která bude obsahovat anonymní funkci,
která se bude volat při změně obsahu textového pole se zprávou:
private ChangeListener <<? super String> messageContentListener = (observable, oldValue, newValue) -> { final ChatTab tab = (ChatTab) paneChatContainer.getSelectionModel().getSelectedItem(); if (tab == null) { return; } final String id = ((ChatContact) tab.getUserData()).getId(); chatService.notifyTyping(id, !newValue.isEmpty()); };
Důležité je volání metody notifyTyping()
na posledním
řádku funkce, pomocí které budeme informovat, zda-li uživatel píše, či
nikoliv.
Ošetření přepnutí konverzací
Je pěkné, že jsme informovali uživatele, že píšeme, ale může se stát, že během psaní se přepneme do jiné konverzace, protože si uvědomíme, že zpráva je určena někomu jinému. Vytvoříme tedy listener, který bude reagovat na změnu konverzace. Založíme další třídní konstantu, která bude obsahovat anonymní funkci reagující na změnu konverzace:
private ChangeListener <<? super Tab> tabChangeListener = (observable, oldValue, newValue) -> { if (oldValue != null) { final ChatTab oldTab = (ChatTab) oldValue; final String id = ((ChatContact) oldTab.getUserData()).getId(); chatService.notifyTyping(id, false); } if (newValue != null) { if (!txtMessage.getText().isEmpty()) { final ChatTab newTab = (ChatTab) newValue; final String id = ((ChatContact) newTab.getUserData()).getId(); chatService.notifyTyping(id, true); } } else { txtMessage.clear(); } };
Funkce dostane jako parametry oldValue
(stará konverzace) a
newValue
(nová konverzace). Pokud se opravdu přepínáme ze
staré konverzace, tak hodnota oldValue
nebude null
a
informujeme uživatele ve staré konverzaci, že již nepíšeme zprávu pro
něj. Pokud jsme se přepli do nové konverzace a textové pole pro zprávu
obsahuje nějaký text, tak informujeme nového uživatele, že nejspíš
píšeme zprávu pro něj.
Registrace posluchače psaní
Nakonec zaregistrujeme posluchače na změnu konverzace v metodě
initialize()
:
paneChatContainer.getSelectionModel().selectedItemProperty().addListener(this.tabChangeListener);
Test indikátoru psaní
Nyní, když otevřete konverzaci a začnete psát, změní se ikona v Tabu na velice jednoduchou animaci.
Výsledek
Níže můžete vidět výsledného chat klienta. U kontaktů se zobrazuje počet nepřečtených zpráv. Dále indikátor psaní se zobrazuje v tabu. Pokud je konverzace delší, zobrazí se scrollbar.

Ukončení série
Tímto bychom měli uzavřenou celou sérii o tvorbě jednoduchého chat klienta. Klient samozřejmě zaslouží ještě řadu vylepšení, které nechám na samotných čtenářích. Doufám, že se vám seriál líbil a pokud budete mít jakékoliv připomínky, dole jsou k dispozici komentáře.
V následujícím kvízu, Kvíz - Server pro klientské aplikace Java, si vyzkoušíme nabyté zkušenosti z kurzu.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 64x (141.84 kB)
Aplikace je včetně zdrojových kódů v jazyce Java