Vánoční nadílka Vánoční nadílka
Vánoční akce! Daruj lepší budoucnost blízkým nebo sobě. Až +50 % zdarma na dárkové poukazy. Více informací

Lekce 24 - Java chat - Klient - Dokončení 2. část

Java Server pro klientské aplikace Java chat - Klient - Dokončení 2. část

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

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í

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

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.


 

Stáhnout

Staženo 8x (144.63 kB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

 

Článek pro vás napsal Petr Štechmüller
Avatar
Jak se ti líbí článek?
1 hlasů
Autor se věnuje primárně programování v Jave, ale nebojí se ani webových technologií.
Aktivity (4)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!