0

Question

I'm creating a GUI for a message application. the frame's layout is BorderLayout: chat on the western border, list of users on the Eastern border, and user input on the southern border.

The problems:

  1. The panels aren't adhering to the Borderlayout. When I called method revalidate(), The setMinimumSize() is no longer respected.

  2. Panels with scrolls stretch outside of their border when components are added. I tried adding a maximum size / PreferredSize, but the scroll function stops working. I tried revalidating the JPanel and JScrollPane after every added component, but it had no effect.

Answers

  1. problem n.01 was solved by understanding how different layout manager treat different sizes. BorderLayout requires setPreferredSize(new Dimension(width,height))

  2. This problem was somewhat a follow-up/related problem. This was fixed by revaldiate() the frame,in turn the JScrollPane, after every single component added.

Thanks adra :)

I used all the size options I'm aware of, but the JTextArea spill out of its frame.

this.setMinimumSize(new Dimension(width, height));
this.setMaximumSize(new Dimension(width, height));
this.setPreferredSize(new Dimension(width, height));
this.setSize(new Dimension(width, height));

Problem visualized

When running the program without revalidate

revalidating the frame

problem n.02 after solving problem n.01

GUI code

Frame

package View;
import Control.Controller;

import javax.swing.*;
import java.awt.*;
import static java.awt.Color.*;

public class ChatFrame extends JFrame {
    private Controller controller;

    private ChatView wp;
    private UserList ep;
    private UserInput sp;


    private int width = 1400;
    private int height = 800;


    public ChatFrame(){
        super("El 3yal");
        this.setSize(width, height);
        this.setLocation(20,0);
        this.getContentPane().setLayout(new BorderLayout(20,20));
        this.setResizable(false);
        this.setVisible(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        setUp();
    }

    public void setUp(){
        wp = new ChatView(1000,600,controller,this);
        addScroll(wp, BorderLayout.WEST, 1000, 600);
        ep = new UserList(380, 600, controller, this);
        addScroll(ep, BorderLayout.EAST, 380, 600);
        sp = new UserInput(800, 200, controller, this);
        this.add(sp, BorderLayout.SOUTH);
        revalidate();

    }

    public void addScroll(JPanel pnl, String str, int w, int h){
        JScrollPane jsp = new JScrollPane(pnl);
        jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
        jsp.setSize(new Dimension(w, h));
        jsp.getVerticalScrollBar().setUnitIncrement(16);
        jsp.setBorder(BorderFactory.createLineBorder(Color.black));
        this.add(jsp, str);
    }

    public Controller getController() {
        return controller;
    }
    public ChatView getWp() {
        return wp;
    }
    public UserList getEp() {
        return ep;
    }
    public UserInput getsPnl() {
        return sp;
    }

}

class test{

    public static void main(String[] args){
        ChatFrame frame = new ChatFrame();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                frame.getWp().receive("hadsag", "Hello i want to say hi", null);
                for(int i = 0; i < 15; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    frame.getWp().receive("Hadsag", "Hello i want to say hi", new ImageIcon("files/icon.jpeg"));
                }
            }
        });
        thread.start();
    }
}

chat view panel

package View;

import Control.Controller;

import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;

public class ChatView extends JPanel {
    private ChatFrame frame;
    private Controller controller;

    private int width;
    private int height;


    public ChatView(int width, int height, Controller controller, ChatFrame frame) {
        super();
        this.frame = frame;
        this.controller = controller;
        this.width = width;
        this.height = height;
        setUp();
    }

    public void setUp(){
        this.setMinimumSize(new Dimension(width, height));
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        this.setBorder(BorderFactory.createLineBorder(Color.black));

    }

    public void receive(String name, String txt, ImageIcon pic){
        Box box = Box.createHorizontalBox();
        box.setMinimumSize(new Dimension(600, 170));
        box.setSize(new Dimension(600, 170));

        TextArea lblText = new TextArea("< " + name + " > : " + txt);
        lblText.setEditable(false);
        lblText.setFont(new Font("Serif", Font.PLAIN, 12));
        lblText.setMinimumSize(new Dimension(400, 20));
        lblText.setMaximumSize(new Dimension(600, 170));
        box.add(lblText, LEFT_ALIGNMENT);

        JLabel lblPic = new JLabel();
        lblPic.setMinimumSize(new Dimension(100, 150));
        lblPic.setMaximumSize(new Dimension(100, 150));
        if(pic != null) {
            Image image = pic.getImage();
            image = image.getScaledInstance(100, 150, java.awt.Image.SCALE_SMOOTH);
            pic = new ImageIcon(image);
            lblPic.setIcon(pic);
        }
        box.add(lblPic, RIGHT_ALIGNMENT);

        this.add(box);
/*
        TextArea chatText = new TextArea();
        chatText.setEditable(false);
        chatText.append("< "+name+" > : " + txt);
        chatText.setFont(new Font("Serif", Font.PLAIN, 10));
        chatText.setMinimumSize(new Dimension(600,20));
        chatText.setMaximumSize(new Dimension(600,60));
        this.add(chatText, LEFT_ALIGNMENT);

        this.add(Box.createRigidArea(new Dimension(0,5)));

        Image image = pic.getImage();
        image = image.getScaledInstance(100, 150, java.awt.Image.SCALE_SMOOTH);
        pic = new ImageIcon(image);
        JLabel lblPic = new JLabel();
        lblPic.setIcon(pic);
        lblPic.setMinimumSize(new Dimension(600,150));
        lblPic.setMaximumSize(new Dimension(600,250));
        this.add(lblPic, LEFT_ALIGNMENT);
*/
        this.add(Box.createRigidArea(new Dimension(0,5)));

        this.revalidate();

    }
}

user List

     package View;
    
    import Control.Controller;
    
    import javax.swing.*;
    import java.awt.*;
    
    public class UserList extends JPanel {
    private ChatFrame frame;
    private Controller controller;

    private int width;
    private int height;

    private JLabel lblUsers;

    public UserList(int width, int height, Controller controller, ChatFrame frame) {
        super(null);
        this.frame = frame;
        this.controller = controller;
        this.width = width;
        this.height = height;

        this.setSize(width, height);
        this.setBorder(BorderFactory.createLineBorder(Color.black));
        this.setLayout(new BoxLayout(this,BoxLayout.PAGE_AXIS));
        setUp();
        addComponents();
    }

    public void setUp(){
        this.setMinimumSize(new Dimension(width, height));
        this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
        this.setBorder(BorderFactory.createLineBorder(Color.black));
    }

    public void addComponents(){
        lblUsers = new JLabel("Users");
        this.setMinimumSize(new Dimension(50,50));
        this.add(lblUsers);

    }
}

**User Input Panel**

    package View;

import Control.Controller;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;

public class UserInput extends JPanel {
private ChatFrame frame;
private Controller controller;

private int width;
private int height;

private JButton pic, send;
private JTextArea message;


public UserInput(int width, int height, Controller controller, ChatFrame frame) {
    super();
    this.frame = frame;
    this.controller = controller;
    this.width = width;
    this.height = height;
    this.setSize(width, height);
    setUp();
    addComponents();
}

public void setUp(){
    this.setMinimumSize(new Dimension(width, height));
    this.setLayout(new FlowLayout());
    this.setBorder(BorderFactory.createLineBorder(Color.black));

}

public void addComponents(){
    pic = new JButton("attach image");
    pic.setMinimumSize(new Dimension(200,200));
    pic.addActionListener(l->changePP());
    this.add(pic);


    message = new JTextArea("write here!");
    message.setMinimumSize(new Dimension(400,200));
    this.add(message);

    send = new JButton("send");
    send.setMinimumSize(new Dimension(200,200));
    send.addActionListener(l->sendMessage());
    this.add(send);

    revalidate();
}

public void sendMessage(){

}

private void changePP() {
    JFileChooser fileChooser = new JFileChooser();
    fileChooser.setAcceptAllFileFilterUsed(false);
    fileChooser.addChoosableFileFilter(new FileFilter() {
        @Override
        public boolean accept(File f) {
            String filename = f.getName();
            if (f.isDirectory()) {
                return true;

            } else if (filename.endsWith("jpg'") || filename.endsWith("jpeg") || filename.endsWith("png") || filename.endsWith("gif")) {
                return true;
            } else {
                return false;
            }
        }

        @Override
        public String getDescription() {
            return "Images";
        }
    });

    int option = fileChooser.showOpenDialog(frame);
    if(option == JFileChooser.APPROVE_OPTION){
        File sourceFile = fileChooser.getSelectedFile();

        String extension = "";
        int i = sourceFile.getAbsolutePath().lastIndexOf('.');
        if (i > 0) {
            extension = sourceFile.getAbsolutePath().substring(i+1);
        }

        File destinationFile  = new File("files/sent." + extension);
        try {
            Files.copy(sourceFile.toPath(),destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
        pic.setIcon(new ImageIcon("files/sent." + extension));

    }else{
        JOptionPane.showMessageDialog(null, "Error selecting image");
    }
}

}

hadsag
  • 11
  • 3
  • `this.setVisible(true);` should be the last thing you do when setting up your GUI. In other words it should come after `setUp();` – Abra Feb 21 '22 at 19:00
  • `jsp.setSize(new Dimension(w, h));` should be `jsp.setPreferredSize(new Dimension(w, h));` – Abra Feb 21 '22 at 19:01
  • `Thread thread = new Thread(new Runnable() {` You are updating your GUI on a thread which is **not** the [Event Dispatch Thread](https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html) (EDT). Not recommended. – Abra Feb 21 '22 at 19:03
  • Each component in _Swing_ has a minimum size, a maximum size, a preferred size and a [size](https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/Component.html#getSize()). You need to learn how the different [layout managers](https://docs.oracle.com/javase/tutorial/uiswing/layout/index.html) treat those sizes. – Abra Feb 21 '22 at 19:08

1 Answers1

0

The problems:

The panels aren't adhering to the Borderlayout. When I called method revalidate(), The setMinimumSize() is no longer respected.

Panels with scrolls stretch outside of their border when components are added. I tried adding a maximum size / PreferredSize, but the scroll function stops working. I tried revalidating the JPanel and JScrollPane after every added component, but it had no effect.

Answers

problem n.01 was solved by understanding how different layout manager treat different sizes. BorderLayout requires setPreferredSize(new Dimension(width,height))

This problem was somewhat a follow-up/related problem. This fixed itself by revaldiate() the frame,in turn the JScrollPane, after every single component added. To further elaborate:

The JPanel with the components should not have a preferred size, only a minimum size. This allows components to infinitely be added without resizing components or cutting them off. The JScrollePane is the one that should have the attribute of preferredSize() [i added min size, max size and size all the same but I am not sure if they have an effect]. then you revalidate the JPanel, The JScrollPane and the frame (maybe an overkill, idk but this is my solution) after every single component added

Thanks adra :)

hadsag
  • 11
  • 3