24. diel - Java chat - Klient - Dokončenie 2. časť
V minulej lekcii, Java chat - Klient - Dokončenie 1. časť , sme začali práce na GUI nášho chat klienta v Jave. V dnešnom poslednom Java tutoriálu dokončíme implementáciu chat klienta a tým aj uzavrieme celú sériu o tvorbe Java servera.
Obsluha pre zobrazenie konverzácie
Začneme tým, že zobrazíme konverzáciu s vybraným užívateľom. Pri
dvojitom kliknutí na užívateľa v ListView
sa zobrazí buď
nová záložka s konverzáciou, alebo sa prepne na už existujúce
konverzáciu. V triede MainController
vytvoríme novú konštantu,
ktorá bude obsahovať anonymné funkciu, ktorá bude obsluhovať dvojité
kliknutie 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čiatku sa skontroluje, či ak sme naozaj klikli 2x. Ak podmienka nie je
splnená, nebude sa nič robiť. Ďalej skontrolujeme, že sme klikli na nejaký
kontakt a nie do prázdneho miesta. Ak sme klikli na kontakt, zobrazíme
konverzáciu metódou showConversation()
.
Zobrazenie vybrané konverzácie
Vybranú konverzáciu budeme zobrazovať pomocou metódy
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)); } }
Metóda prijíma ako parameter inštanciu triedy ChatContact
,
ktorá predstavuje kontakt, pre ktorý chceme zobraziť konverzáciu. Najskôr
sa pozrieme, či je už konverzácie v TabPane
prítomná. Ak áno,
jednoducho na nej prepneme metódou select()
. V opačnom prípade
vytvoríme novú záložku s konverzáciou a vložíme ju medzi ostatné
konverzácie.
Vytvorenie novej konverzácie
Vytvorenie novej konverzácie necháme na samostatnú metódu, ktorú nazveme
makeNewTab()
:
private ChatTab makeNewTab(ChatContact chatContact) { final ChatTab chatTab = new ChatTab(chatContact); chatTab.setUserData(chatContact); return chatTab; }
Najskôr vytvoríme novú inštanciu triedy ChatTab
. Metódou
setUserData()
nastavíme vlastné používateľské dáta. Týchto
dát potom využívame v predchádzajúcom kóde, kde filtrujeme
Tab
podľa zadaného kontaktu.
Registrácia obsluhy pre zobrazenie konverzácie
Nakoniec v metóde initialize()
zaregistrujeme obsluhu na
kliknutie pre ListView
:
lvContactList.setOnMouseClicked(this.listContactsClick);
Test funkčnosti
Teraz, keď pustíte server, pustíte klienta, pripojíte sa na server a
zobrazí sa v ListView
jediný kontakt - Vy, môžete na tento
kontakt 2x kliknúť a zobrazí sa v pravej časti okna nová záložka s
konverzáciou.
Odoslanie správy
V nasledujúcej časti implementujeme odoslanie správy. Do textového poľa budeme môcť písať len vtedy, ak je vybraná nejaká konverzácie. Tlačidlo pre odoslanie bude prístupné iba za predpokladu, že textové pole obsahuje nejaký text. Začneme teda implementáciou týchto podmienok.
Ovládanie prvkov
Ovládanie prvkov nastavíme v metóde initialize()
. Najskôr
ovládanie tlačidla. Tlačidlu nabindujeme vlastnosť
disableProperty()
na textProperty().isEmpty()
.
btnSend.disableProperty().bind(txtMessage.textProperty().isEmpty());
Textové pole nabindujeme podobným spôsobom:
txtMessage.disableProperty().bind(paneChatContainer.getSelectionModel().selectedItemProperty().isNull());
Obsluha tlačidlá pre odoslanie správy
Pri stlačení tlačidla odoslať sa odošle správa. Už máme všetku potrebnú logiku implementovanú, stačí ju len zavolať:
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(); }
Najskôr sa otestuje, či ak máme otvorený Tab
. Ak nie,
metóda nič nevykoná. Id kontaktu získame z užívateľských dát v
Tab
ua obsah správy z textového poľa. Nakoniec zavoláme našu
service, ktorá sa postará o odoslanie správy. Nasleduje vymazanie textového
poľa a požiadavku o získanie fokusu, aby sme mohli znovu písať.
Zobrazenie správ
Prijaté správy už majú implementovanú všetku logiku, takže po odoslaní správy sa automaticky zobrazí. Pokiaľ práve konverzácie nebude zobrazená, zobrazí sa v kontakt liste napravo od mena počet neprečítaných správ.
Informácie o písaní
Teraz implementujeme funkciu, ktorá bude používateľa informovať, či ak
klient na druhom konci píše, alebo nie. V triede MainController
založíme novú triednu konštantu, ktorá bude obsahovať anonymné funkciu,
ktorá sa bude volať pri zmene obsahu textového poľa so sprá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 volanie metódy notifyTyping()
na poslednom
riadku funkcie, pomocou ktorej budeme informovať, či ak používateľ píše,
alebo nie.
Ošetrenie prepnutie konverzácií
Je pekné, že sme informovali používateľa, že píšeme, ale môže sa stať, že počas písania sa prepneme do inej konverzácie, pretože si uvedomíme, že správa je určená niekomu inému. Vytvoríme teda listener, ktorý bude reagovať na zmenu konverzácie. Založíme ďalšie triedne konštantu, ktorá bude obsahovať anonymné funkciu reagujúce na zmenu konverzácie:
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(); } };
Funkcia dostane ako parametre oldValue
(stará konverzácie) a
newValue
(nová konverzácia). Ak sa naozaj prepíname zo starej
konverzácie, tak hodnota oldValue
nebude null
a
informujeme užívateľa v starej konverzáciu, že už nepíšeme správu pre
neho. Ak sme sa prepli do novej konverzácie a textové pole pre správu
obsahuje nejaký text, tak informujeme nového používateľa, že najskôr
píšeme správu pre neho.
Registrácia poslucháčov písanie
Nakoniec zaregistrujeme poslucháčov na zmenu konverzácie v metóde
initialize()
.
paneChatContainer.getSelectionModel().selectedItemProperty().addListener(this.tabChangeListener);
Test indikátora písania
Teraz, keď otvoríte konverzáciu a začnete písať, zmení sa ikona v Tabu na veľmi jednoduchú animáciu.
Výsledok
Nižšie môžete vidieť výsledného chat klienta. U kontaktov sa zobrazuje počet neprečítaných správ. Ďalej indikátor písania sa zobrazuje v tabu. Ak je konverzácia dlhší, zobrazí sa scrollbar.
Ukončenie série
Týmto by sme mali uzavretú celú sériu o tvorbe jednoduchého chat klienta. Klient samozrejme zaslúži ešte rad vylepšení, ktoré nechám na samotných čitateľoch. Dúfam, že sa vám seriál páčil a ak budete mať akékoľvek pripomienky, dole sú k dispozícii komentáre.
V nasledujúcom kvíze, Kvíz - Server pre klientske aplikácie Java, si vyskúšame nadobudnuté skúsenosti z kurzu.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 63x (141.84 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java