So I have a program that utilizes JFrame and JPanel and such. I have multiple JPanels with JTextAreas within them, like a list. I'm trying to create JScrollPane that allows me to scroll through all the JPanels, top to bottom. To do that, I'm trying to get the height of all JPanels + spaces in between (which is 55... pixels?). However when using function JPanel.getHeight(), it gives me the height of the JPanel without the additional line wrap. Why's that?
UserInterface.java
package groupid;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.json.simple.JSONObject;
import org.junit.internal.TextListener;
public class UserInterface {
//Sort Options - Different Ways to Short Data
static String sortOptions[] = {"A - Z","Z - A","Recently Created","Oldest Created","Recently Modified"};
//Main Frame Components
static ImageIcon icon;
static JFrame mainFrame = new JFrame();
static JPanel mainPanel;
static JScrollPane mainScrollPane;
//Main Panel Components
static JPanel rightPanel;
static JPanel sidePanel;
//Right Panel Components
static JPanel topPanel;
static JPanel searchPanel;
static JLabel searchLabel;
static JTextField searchBar;
static String searchText;
static JPanel sortPanel;
static JLabel sortByLabel;
static JPanel bottomPanel;
static JPanel addButtonPanel;
static JButton addButton;
static JPanel flowPanel;
static JPanel footerPanel;
static JPanel titlePanel;
static JLabel titleLabel;
static JPanel heightPanel;
static JTextArea valueLabel;
static String clipboardString;
static Boolean pasteBool;
static Boolean startUp;
public static void main(String[] args) {
Database.startUp();
UserInterface.jFrameCreate();
}
static Action paste = new AbstractAction("Paste") {
@Override
public void actionPerformed(ActionEvent e) {
try {
clipboardString = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
} catch (UnsupportedFlavorException | IOException e1) {
e1.printStackTrace();
}
pasteBool = true;
new AddToClippyBoard();
pasteBool = false;
}
};
public static void jFrameCreate(){
startUp = true;
mainFrame.setVisible(true);
mainFrame.setSize(1600, 900);
mainFrame.setTitle("ClippyBoards");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setResizable(true);
mainFrame.setFocusable(true);
mainFrame.setLayout(new BorderLayout(10,0));
mainFrame.addWindowListener(new WindowAdapter() { // Exits out of application
@Override
public void windowClosing(WindowEvent e) {
Database.saveFile();
mainFrame.dispose();
}
});
icon = new ImageIcon("EggSMP.png");
mainFrame.setIconImage(icon.getImage());
mainFrame.getContentPane().setBackground(new Color(100,100,100));
// Right Panel - Panel that holds bottom panel and main panel
rightPanel = new JPanel(new BorderLayout(5,5));
rightPanel.setBackground(new Color(150,150,150));
rightPanel.setPreferredSize(new Dimension(1200,500));
mainFrame.add(rightPanel,BorderLayout.CENTER);
mainPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,20,20));
mainPanel.setPreferredSize(new Dimension(1000,0));
mainPanel.setBackground(new Color(230,230,230));
mainScrollPane = new JScrollPane(mainPanel);
mainScrollPane.createVerticalScrollBar();
mainScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
mainScrollPane.getVerticalScrollBar().setUnitIncrement(20);
rightPanel.add(mainScrollPane); // adds mainPanel, with scroll bar
KeyStroke ctrlV = KeyStroke.getKeyStroke(KeyEvent.VK_V,InputEvent.CTRL_DOWN_MASK);
mainPanel.getActionMap().put("Paste", paste);
mainPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ctrlV, "Paste");;
// Side Panel - Navigate and organize folders
sidePanel = new JPanel(new FlowLayout());
sidePanel.setPreferredSize(new Dimension(500,100));
sidePanel.setBackground(new Color(220,228,232));
mainFrame.add(sidePanel,BorderLayout.WEST);
//Top Panel - Search Bar & Sorting Options
topPanel = new JPanel(new BorderLayout());
topPanel.setPreferredSize(new Dimension(1000,50));
topPanel.setBackground(new Color(230,230,230));
rightPanel.add(topPanel,BorderLayout.NORTH);
//Search Panel - Holds Search Bar
searchPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING,5,12));
searchPanel.setPreferredSize(new Dimension(500,50));
searchPanel.setBackground(new Color(230,230,230));
topPanel.add(searchPanel,BorderLayout.EAST);
//Search Label
searchLabel = new JLabel();
searchLabel.setFont(new Font("Arial",Font.BOLD,20));
searchLabel.setText("Search:");
searchPanel.add(searchLabel);
//Search Bar - Search for Items within
searchBar = new JTextField();
searchBar.setPreferredSize(new Dimension(250,30));
searchBar.setBackground(new Color(250,250,250));
searchBar.setFont(new Font("Arial",Font.PLAIN,20));
searchBar.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void removeUpdate(DocumentEvent e) {
jFrameRefresh();
searchText = searchBar.getText();
}
@Override
public void insertUpdate(DocumentEvent e) {
jFrameRefresh();
searchText = searchBar.getText();
}
@Override
public void changedUpdate(DocumentEvent e) {
jFrameRefresh();
searchText = searchBar.getText();
}
});
searchPanel.add(searchBar);
//Sort Panel - Holds Sort Filter
sortPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,5,12));
sortPanel.setPreferredSize(new Dimension(600,50));
sortPanel.setBackground(new Color(230,230,230));
topPanel.add(sortPanel,BorderLayout.WEST);
//Sort Label
icon = new ImageIcon(new ImageIcon("SortBlack.png").getImage().getScaledInstance(30, 30, Image.SCALE_DEFAULT));
sortByLabel = new JLabel();
sortByLabel.setFont(new Font("Arial",Font.BOLD,20));
sortByLabel.setText("Sort By:");
sortByLabel.setIcon(icon);
sortPanel.add(sortByLabel);
//sort Filter - Sorts data by selected filter
JComboBox<String> sortBy = new JComboBox<String>(sortOptions);
sortBy.setPreferredSize(new Dimension(200,30));
sortBy.setFont(new Font("Arial",Font.PLAIN,20));
sortPanel.add(sortBy);
// Bottom Panel - Undecided
bottomPanel = new JPanel(new BorderLayout());
bottomPanel.setPreferredSize(new Dimension(100,50));
bottomPanel.setBackground(new Color(220,228,232));
rightPanel.add(bottomPanel,BorderLayout.SOUTH);
// Button Panel - Holds Add Button
addButtonPanel = new JPanel();
addButtonPanel.setPreferredSize(new Dimension(50,50));
addButtonPanel.setBackground(new Color(220,228,232));
bottomPanel.add(addButtonPanel,BorderLayout.EAST);
// Add Button - Will open window to import new info
addButton = new JButton("+");
addButton.setFont(new Font("Arial",Font.BOLD,20));
addButton.setAlignmentX(JPanel.CENTER_ALIGNMENT);
addButton.setAlignmentY(JPanel.CENTER_ALIGNMENT);
addButtonPanel.add(addButton);
addButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==addButton) {
pasteBool = false;
new AddToClippyBoard();
}
}
});
startUp = false;
jFrameRefresh();
}
public static void jFrameRefresh() {
mainPanel.removeAll();
loadClippy();
System.out.println("repaint");
mainFrame.revalidate();
mainFrame.repaint();
}
public static void loadClippy() {
int mainPanelSize = 0;
for (int i = 0; i < Database.jsonArray.size(); i++) {
JSONObject tempObject = (JSONObject) Database.jsonArray.get(i);;
flowPanel = new JPanel(new BorderLayout());
flowPanel.setBackground(new Color(220,220,220));
mainPanel.add(flowPanel);
footerPanel = new JPanel();
footerPanel.setPreferredSize(new Dimension(1000,5));
footerPanel.setBackground(new Color(220,220,220));
flowPanel.add(footerPanel,BorderLayout.SOUTH);
titlePanel = new JPanel(new BorderLayout());
titlePanel.setPreferredSize(new Dimension(1000,50));
titlePanel.setBackground(new Color(220,220,220));
flowPanel.add(titlePanel,BorderLayout.NORTH);
titleLabel = new JLabel();
titleLabel.setFont(new Font("Arial",Font.BOLD,25));
titleLabel.setText(tempObject.get("name").toString());
titlePanel.add(titleLabel);
heightPanel = new JPanel();
heightPanel.setBackground(new Color(0,0,220));
flowPanel.add(heightPanel,BorderLayout.EAST);
valueLabel = new JTextArea();
valueLabel.setFont(new Font("Arial",Font.PLAIN,15));
valueLabel.setBackground(new Color(220,220,220));
valueLabel.setLineWrap(true);
valueLabel.setWrapStyleWord(true);
valueLabel.setEditable(false);
valueLabel.setText(tempObject.get("value").toString());
flowPanel.add(valueLabel);
mainFrame.revalidate();
mainFrame.repaint();
System.out.println(heightPanel.getHeight());
mainPanelSize += 55+heightPanel.getHeight();
}
mainPanel.setPreferredSize(new Dimension(1000,mainPanelSize));
}
}
For the part where I'm working on, search for "public static void LoadClippy()".
I went through many forums, and solved the first problem where it would print 0, since you had to add and repaint the JPanel first to get a height. That is solved, and isn't the problem
Just using JPanel.getSize().getHeight(). Didn't include the line wrap, just the height of everything as if there wasn't a line wrap
Thought I was a genious when I came up with the idea of adding a sub-JPanel to the EAST side, so I could get the height of that right? Somehow, even though they are different heights on screen, they output the same getHeight()
Here is what it looks like:
The weird blue lines on the right of each JPanel is my heightPanel. They have different heights to our eyes, but they print the same values if they have line wraps
System.out.println() <- I print the heightPanel.getHeight(). All the same value
Your question appears to be an XY Problem where you ask how to solve a specific code problem when the best solution is to use a completely different approach.
Your question is "why isn't getHeight()
working like I want it to work", when the real issue is that you're using the wrong layout managers. You appear to want to create somewhat list of items held in a JScrollPane, that scrolls correctly and shows correctly, but the main JPanel that is held by the JScrollPane and that holds all the listing sub-components uses FlowLayout, a very limited layout manager, one that is useful mainly for very simple linear based layouts. For this situation, one possible solution is to have the main JPanel that is held by the scrollpane use a BoxLayout oriented to the page-axis. This way, components added will be added below previously added components. This way, using a BoxLayout, the JScrollPane will automatically size its viewport correctly, without you having to use any getHeight()
kludges, a brittle kludge, as you are finding out.
For example, my MRE program:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
@SuppressWarnings("serial")
public class UserInterface2 extends JPanel {
private static final int PREF_W = 1600;
private static final int PREF_H = 900;
JPanel mainPanel = new JPanel();
public UserInterface2() {
setLayout(new BorderLayout());
setBackground(new Color(100, 100, 100));
JPanel sidePanel = new JPanel();
sidePanel.setPreferredSize(new Dimension(500, 100));
sidePanel.setBackground(new Color(220, 228, 232));
add(sidePanel, BorderLayout.WEST);
JPanel topPanel = new JPanel();
topPanel.setPreferredSize(new Dimension(1000, 50));
topPanel.setBackground(new Color(230, 230, 230));
JPanel rightPanel = new JPanel(new BorderLayout(5, 5));
rightPanel.setBackground(new Color(150, 150, 150));
rightPanel.add(topPanel, BorderLayout.NORTH);
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
mainPanel.setBackground(new Color(230, 230, 230));
JScrollPane scrollPane = new JScrollPane(mainPanel);
rightPanel.add(scrollPane);
add(rightPanel);
int maxI = 30;
for (int i = 0; i < maxI; i++) {
mainPanel.add(createFlowPanel(i));
}
}
private JPanel createFlowPanel(int i) {
// panel to hold each cell
JPanel flowPanel = new JPanel();
flowPanel.setLayout(new BorderLayout());
flowPanel.setBackground(new Color(220, 220, 220));
// add a white border around the panel to separate cells
int ebGap = 14;
flowPanel.setBorder(BorderFactory.createLineBorder(Color.WHITE, ebGap));
JLabel titleLabel = new JLabel("", SwingConstants.LEADING);
titleLabel.setFont(new Font("Arial", Font.BOLD, 25));
// titleLabel.setText(tempObject.get("name").toString());
titleLabel.setText("name " + i); // !!
flowPanel.add(titleLabel, BorderLayout.PAGE_START);
JTextArea valueLabel = new JTextArea();
valueLabel.setFont(new Font("Arial", Font.PLAIN, 15));
valueLabel.setBackground(new Color(220, 220, 220));
valueLabel.setLineWrap(true);
valueLabel.setWrapStyleWord(true);
valueLabel.setEditable(false);
// create a bunch of random text of random lengths
StringBuilder sb = new StringBuilder();
for (int j = 0; j < 3 + (int) 3 * Math.random(); j++) {
for (int k = 0; k < 10 + (int) 20 * Math.random(); k++) {
for (int l = 0; l < 4 + (int)8 * Math.random(); l++) {
char myChar = (char)('a' + (int) ('z' - 'a' + 1) * Math.random());
sb.append(myChar);
}
sb.append(" ");
}
sb.append(System.lineSeparator());
}
valueLabel.setText(sb.toString());
flowPanel.add(valueLabel);
return flowPanel;
}
@Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int w = Math.max(superSize.width, PREF_W);
int h = Math.min(superSize.height, PREF_H);
return new Dimension(w, h);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
UserInterface2 ui2 = new UserInterface2();
JFrame frame = new JFrame("ClippyBoards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(ui2);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
Another side point: You should be avoiding over-use of the static modifier, and in fact, the only things in your program that absolutely need to be static are your constants, your main methods, and perhaps a few other things that are shared by all the objects of a class, but really nothing else. Just because this is a Swing GUI doesn't mean that you should throw out the OOPs baby with the bath water, and in fact it is even more important to use good OOP techniques in GUI programs, which tend to be more complex, if only to help keep bugs due to the cyclomatic complexity at bay.