2

I have an Array List of 'n' number of different Chats That are Wrapped with a width below is the code for a TextArea Block

JTextArea chat2 = new JTextArea();
 chat2.setText("this is chat 2"); 
 chat2.setWrapStyleWord(true);
 chat2.setLineWrap(true);
 chat.setColumns(20); 
 chat2.setEditable(false);
 chat2.setBorder(borderLine);   
 chat2.setVisible(true);

And an Array List That looks Like

ArrayList<JTextArea> c = new ArrayList<JTextArea>();
c.add(chat2)

Already Tried

Vector itemsVector = new Vector(c);
JList chats = new JList(itemsVector);
 //CHAT PANEL SCROLLABLE
 JScrollPane scrollChats = new JScrollPane(chats);
 scrollChats.setBounds(0,60,1100,600);
 main.add(scrollChats); 

It didnt work got this output instead: text thats shown

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Jaison Thomas
  • 393
  • 1
  • 9
  • JList is the way to go, but you appear to be confusing the model with the display. The model should contain the chat Strings, or lists of Strings, and the display (or list renderer) would be where the JTextAreas *might* go – Hovercraft Full Of Eels Dec 19 '20 at 17:54
  • So i Send a List of Strings to the Jlist instead of a List of JTextArea. I can do that, but then how do i later add the wrapping or other UI properties?@HovercraftFullOfEels – Jaison Thomas Dec 19 '20 at 17:58
  • You state that you are displaying several chat collections, suggesting that your JList model would hold a `List>` or something like this. Then you'd have to work on list renderer that displays each `List` within a rendered JTextArea. This is just one way to consider doing this. – Hovercraft Full Of Eels Dec 19 '20 at 18:02
  • You would *NEVER* pass Swing components into a JList's model as that is most definitely not how it works (as you're finding out) – Hovercraft Full Of Eels Dec 19 '20 at 18:03
  • Sorry for not making it more clear by chat collection i meant one list of chats so it'd be List only. So i'm assuming what id have to do next is render the Jlist cells? – Jaison Thomas Dec 19 '20 at 18:06
  • 1
    That may be simple then -- create a `DefaultListModel`, fill it with the chat text, and then add it to your list. Done. – Hovercraft Full Of Eels Dec 19 '20 at 18:10
  • 1
    it gets tougher if you want to change the display depending on who posted the chat, but this can be done by proper use of renderers. – Hovercraft Full Of Eels Dec 19 '20 at 18:12
  • Will try to implement the reendered will comment on how it went – Jaison Thomas Dec 19 '20 at 18:19

1 Answers1

2

So, imagine a Chat class that holds a String that represents the chatter (or better, a well-defined User type object) as well text that this user is sending:

public class Chat {
    String name;
    String text;

    public Chat(String name, String text) {
        super();
        this.name = name;
        this.text = text;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

}

Then you could create a list model and a JList that hold objects of this type:

private DefaultListModel<Chat> chatListModel = new DefaultListModel<Chat>();
private JList<Chat> chatList = new JList<Chat>(chatListModel);

Then you could create a renderer that displays the Chatter's text as the default renderer text, and the chatter's name in a titled border that goes around the individual renderer (the default renderer is a JLabel):

private class ChatRenderer extends DefaultListCellRenderer {
    @Override
    public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
            boolean cellHasFocus) {
        Chat chat = (Chat) value;
        String text = chat.getText();
        String name = chat.getName();
        JLabel rendererComponent = (JLabel) super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus);
        rendererComponent.setBorder(BorderFactory.createTitledBorder(name));
        return rendererComponent;
    }
}

The whole thing could look like:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class FooGui01 extends JPanel {
    private DefaultListModel<Chat> chatListModel = new DefaultListModel<Chat>();
    private JList<Chat> chatList = new JList<Chat>(chatListModel);
    private JTextField inputField = new JTextField(20);
    private JButton submitButton = new JButton("Submit");
    
    public FooGui01() {
        chatList.setCellRenderer(new ChatRenderer());
        chatList.setPrototypeCellValue(new Chat("John", "abc def ghi jkl abc def ghi jkl abc def ghi jkl abc def ghi jkl abc def ghi jkl abc def ghi jkl "));
        chatList.setVisibleRowCount(10);
        JScrollPane scrollPane = new JScrollPane(chatList);
        scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        
        ActionListener listener = new SubmitListener();
        inputField.addActionListener(listener);
        submitButton.addActionListener(listener);
        submitButton.setMnemonic(KeyEvent.VK_S);
        
        JPanel submitPanel = new JPanel();
        submitPanel.setLayout(new BoxLayout(submitPanel, BoxLayout.LINE_AXIS));
        submitPanel.add(inputField);
        submitPanel.add(submitButton);
        
        setLayout(new BorderLayout());
        add(scrollPane);
        add(submitPanel, BorderLayout.PAGE_END);
    }
    
    // public method called by outside code that is wanting to pass chat to you
    public void submitChat(Chat chat) {
        if (SwingUtilities.isEventDispatchThread()) {
            chatListModel.addElement(chat);
        } else {
            SwingUtilities.invokeLater(() -> chatListModel.addElement(chat));
        }
    }

    private class SubmitListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            String text = inputField.getText();
            chatListModel.addElement(new Chat("Me", text));
            inputField.selectAll();
            inputField.requestFocusInWindow();
            
            // here you would send the chat text or object to a socket's output stream
        }
    }
    
    private class ChatRenderer extends DefaultListCellRenderer {
        @Override
        public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
                boolean cellHasFocus) {
            Chat chat = (Chat) value;
            String text = chat.getText();
            String name = chat.getName();
            JLabel rendererComponent = (JLabel) super.getListCellRendererComponent(list, text, index, isSelected, cellHasFocus);
            rendererComponent.setBorder(BorderFactory.createTitledBorder(name));
            return rendererComponent;
        }
    }
    
    public static void main(String[] args) {        
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("Foo");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            FooGui01 gui = new FooGui01();
            frame.add(gui);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • This is so informative thank you. So i've just been passing strings for test purposes made alot of code thats identical to urs i have a doubt abt the ChatRenderer.. i implemented ListCellRenderer and returning a jtextarea but it doesnt wrap the text it creates suffiect height to wrap, but the text is one long line... any suggestions? I tried adding it to a panel and returning the panel but didnt work :( . Its just wrapping text im having an issue with rn – Jaison Thomas Dec 19 '20 at 19:25
  • @JaisonThomas: show your [mre] code in your question (just as I've posted mine). Have you called `setLineWrap(true)` and `setWrapStyleWord(true)` on the JTextArea within your renderer? – Hovercraft Full Of Eels Dec 19 '20 at 19:29
  • Yes ive set `setLineWrap(true);` and `setWrapStyleWord(true);`, and given the dimenstions as `setSize(100,getPreferredSize().height);` it leaves appropriate space for the heigt it just doesnt wrap – Jaison Thomas Dec 19 '20 at 19:38
  • ive troubled you too much today, i was trying to build a more whatsapp related ui but i compiled ur code and it looks much better than anything i could build, im going to use the ui you provided and stick to that. again, Thanks a ton – Jaison Thomas Dec 19 '20 at 19:48
  • 1
    @JaisonThomas: some interesting things to try from the answers to [this question](https://stackoverflow.com/q/7306295/522444) – Hovercraft Full Of Eels Dec 19 '20 at 19:49