IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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í.

Okno s prázdnou konverzací - Server pro klientské aplikace v Javě

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 Tabu 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.

Příklad konverzace - Server pro klientské aplikace v Javě

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 61x (141.84 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Java chat - Klient - Dokončení 1. část
Všechny články v sekci
Server pro klientské aplikace v Javě
Přeskočit článek
(nedoporučujeme)
Kvíz - Server pro klientské aplikace Java
Článek pro vás napsal Petr Štechmüller
Avatar
Uživatelské hodnocení:
2 hlasů
Autor se věnuje primárně programování v Javě, ale nebojí se ani webových technologií.
Aktivity