Adding multiple JPanels to a JFrame in real time - java

I am writing a tool take performs a task on text file. The task takes some time to perform so I made a panel that displays the file name and the progress in percentage.
The user may run the task on one or on several files, so I need to display a panel for each file. The problem is that the panels are not being added. I am updating my code to be self contained as suggested below:
package sscce.jpanel;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnAbort;
JButton btnClose;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
for(int i = 0; i < 10; i++) {
frame.addTask(i, "Task"+i);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
getContentPane().setLayout(null);
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea();
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
getContentPane().add(newTaskPanel);
validate();
repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
setLayout(null);
lblTaskDescription = new JLabel(id + " " + fileName);
//lblTaskDescription.setBounds(10, 11, 632, 14);
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
//lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " + e.getMessage());
}
}
}
}

Call validate() then repaint().
This is a hacked version of your SSCCE. Not sure what the final requirement is, but I added a button that allows addition of new tasks after the the GUI is visible. Seems the repaint() call is not needed, so I edited it out.
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.logging.Logger;
public class FProgressDisplay extends JFrame {
private final static Logger LOGGER = Logger.getLogger(FProgressDisplay.class.getName());
private List<PanelTaskProgress> tasks;
JTextArea txtLog;
JButton btnNew;
JButton btnAbort;
JButton btnClose;
static int i;
JPanel taskPanel;
public static void main(String[] args) {
try {
FProgressDisplay frame = new FProgressDisplay();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Failed to initialize application.");
}
}
/**
* Create the frame.
*/
public FProgressDisplay() {
setTitle("Mask tool - Progress");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// should be done AFTER components are added
//pack();
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
taskPanel = new JPanel();
taskPanel.setLayout(new BoxLayout(taskPanel, BoxLayout.Y_AXIS));
JPanel panel = new JPanel();
getContentPane().add(panel);
btnNew = new JButton("New");
panel.add(btnNew);
btnNew.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
addTask(++i, "Task " + i);
}
});
btnAbort = new JButton("Abort");
panel.add(btnAbort);
btnClose = new JButton("Close");
panel.add(btnClose);
txtLog = new JTextArea();
txtLog.setLineWrap(true);
getContentPane().add(txtLog);
tasks = new ArrayList<PanelTaskProgress>();
JScrollPane scrollPane = new JScrollPane(taskPanel);
getContentPane().add(scrollPane);
for(i = 0; i < 10; i++) {
addTask(i, "Task"+i);
}
pack();
}
public void addTask(long id, String fileName) {
PanelTaskProgress newTaskPanel = new PanelTaskProgress(id, fileName);
tasks.add(newTaskPanel);
taskPanel.add(newTaskPanel);
validate();
//repaint();
LOGGER.info("Added new panel");
}
public class PanelTaskProgress extends JPanel {
private static final long serialVersionUID = 1L;
JLabel lblTaskDescription;
JLabel lblProgress;
private long id;
/**
* Create the panel.
*/
public PanelTaskProgress(long id, String fileName) {
try {
//setLayout(null);
lblTaskDescription = new JLabel(id + " " + fileName);
//lblTaskDescription.setPreferredSize(new Dimension(632, 14));
add(lblTaskDescription);
lblProgress = new JLabel("0%");
lblProgress.setHorizontalAlignment(SwingConstants.CENTER);
//lblProgress.setBounds(664, 11, 51, 14);
add(lblProgress);
LOGGER.info("Created new panel; Id: " + id + "; File: " + fileName);
} catch (Exception e) {
LOGGER.severe("Error creating new panel; " + e.getMessage());
}
}
}
}

You can try to remove setLayout(null); from PanelTaskProgress.
JPanel has FlowLayout by default and every panel have two component which you align horizontal center.

Two things:
First, your panels are empty because you call setLayout(null); in your PanelTaskProgressconstructor. Call setLayout(new FlowLayout()); instead and you'll see their contents.
Second, and more interestingly: Your main method is running in the main thread, not the event dispatch thread. When you call setVisible() on the frame, the EDT starts doing things. At a random time shortly after, you start changing the layout, again not from the EDT. This is bound to create problems. You have to create and modify the layout on the event dispatch thread.
Wrap your main method in
EventQueue.invokeLater(new Runnable() {
public void run() {
....
}
});
All Swing programs should do this.

Related

how to add a specific number of buttons created in a loop

i have a problem with adding a specific number of buttons from my for-loop to my JPanel, i know how to add all oof them, but i want to add only 1-10 (i havent decided yet, lets go with 10).'
this is my class where i just declare what objects i want to have.
private static int cID;
private static Deck[] card;
static ArrayList<JButton> buttonList = new ArrayList<JButton>();
private JFrame f;
private JPanel p1;
private JButton button;
public boolean isEmpty() {
return cID == 0;
}
public static void main(String[] args) {
CustomDecks c = new CustomDecks();
c.deckCreator();
}```
this is my for-loop where i create 420 buttons and give them names "card" + i where i is 0 - 419, yet when i try to add card0 to my panel, it fails, why?
private void deckCreator() {
card = new Deck[25];
new ArrayList<Cards> (cSet.cards);
for(int i = 0; i < 420; i++) {
button = new JButton();
buttonList.add(button);
button.setName("card" + i);
f.add(button);
p1.add(card0);
}
f.add(p1);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setVisible(true);
f.setExtendedState(Frame.MAXIMIZED_BOTH);
f.setUndecorated(true);
}
}
}
I'm not sure you can create a JPanel large enough to hold 420 JButtons.
Here's an example of a JButton GUI.
[
Generally, you create an application model and view separately. The model is made up of one or more plain Java classes. The view reads from the application model but doesn't update the model.
Your controller classes (ActionListener classes) update the application model and update / repaint the view.
This pattern is called the model / view / controller (MVC) pattern.
You can see in the example code below that the model is created in the view class constructor. Generally, you create the application model first, then you create the application view.
And here's the complete runnable code.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
public class JButtonScrollGUI {
private JFrame frame;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new JButtonScrollGUI();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private String[] greekAlphabet;
public JButtonScrollGUI() {
this.greekAlphabet = new String[] { "alpha", "beta", "gamma", "epsilon", "zeta" };
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setTitle("Application");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createScrollPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createScrollPanel() {
JPanel panel = new JPanel(new BorderLayout());
JPanel innerPanel = createButtonPanel();
Dimension d = innerPanel.getPreferredSize();
d.width += 50;
d.height /= 2;
panel.setPreferredSize(d);
JScrollPane scrollPane = new JScrollPane(innerPanel);
panel.add(scrollPane, BorderLayout.CENTER);
return panel;
}
private JPanel createButtonPanel() {
JPanel panel = new JPanel(new GridLayout(0, 3, 10, 10));
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
for (int i = 0; i < 20; i++) {
JButton button1 = new JButton("Previous " + i);
panel.add(button1);
JComboBox<String> selectorBox = new JComboBox<>(greekAlphabet);
panel.add(selectorBox);
JButton button2 = new JButton("Next " + i);
button2.setPreferredSize(button1.getPreferredSize());
panel.add(button2);
}
return panel;
}
}

Java AWT/Swing Updating JPanel Continously Not Working

I am trying to make a program that populates a JPanel with GridLayout with the contents of a HashMap that contains String keys to JButton values. Because the size of the HashMap may change, I can't just use setText() for each button. So far I've called .removeAll() to remove the JPanel of all buttons, then I loop through the HashMap to repopulate the JPanel. I then call revalidate() on the JPanel and repaint() on the JFrame.
Current Code:
public class GUI implements Runnable, ActionListener
{
private ToDo td;
JFrame frame;
Thread t=null;
int fontsize = 18;
private Container contentPane;
private JPanel topPane;
private JButton main;
private JButton add;
private JButton settings;
private JPanel centerPane;
private JScrollPane centerScroll;
private JPanel scrollable;
private HashMap<String, JButton> items;
public static void main(String[] args) {
new GUI();
}
public GUI(){
td = new ToDo();
frame = new JFrame();
t = new Thread(this);
t.start();
frame.setMinimumSize(new Dimension(480, 640));
frame.setLayout(null);
frame.setVisible(true);
contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
topPane = new JPanel();
topPane.setLayout(new GridLayout(1, 3));
topPane.setPreferredSize(new Dimension(480, 40));
main = new JButton("View Tasks");
main.setFont(new Font("Sans Serif", Font.PLAIN, fontsize));
add = new JButton("Add Task");
add.setFont(new Font("Sans Serif", Font.PLAIN, fontsize));
settings = new JButton("Settings");
settings.setFont(new Font("Sans Serif", Font.PLAIN, fontsize));
topPane.add(main);
topPane.add(add);
topPane.add(settings);
contentPane.add(topPane, BorderLayout.NORTH);
centerPane = new JPanel();
centerPane.setPreferredSize(new Dimension(480, 600));
items = new HashMap<>();
HashMap<String, Assignment> assignments = td.getAssignments();
scrollable = new JPanel();
scrollable.setLayout(new GridLayout(assignments.size(), 1));
centerScroll = new JScrollPane(scrollable);
for(String key: assignments.keySet()){
Assignment a = assignments.get(key);
JButton button = new JButton(a.getTitle() + " | " + a.getDetails() + " | " + a.getClassification().getCls() + " | " + a.getStatus().getStatus());
button.addActionListener(this);
items.put(key, button);
scrollable.add(button);
}
centerPane.add(centerScroll);
contentPane.add(centerPane, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public void update(int i){
HashMap<String, Assignment> assignments = td.getAssignments();
scrollable.removeAll();
scrollable.setLayout(new GridLayout(assignments.size(), 1));
for(String key: assignments.keySet()){
Assignment a = assignments.get(key);
JButton button = new JButton(Integer.toString(i));
button.addActionListener(this);
items.put(key, button);
scrollable.add(button);
}
scrollable.revalidate();
frame.repaint();
}
#Override
public void run(){
int counter = 0;
try {
while (true) {
update(counter);
t.sleep( 1000 ); // interval given in milliseconds
counter++;
}
}
catch (Exception e) {
System.out.println();
}
}
#Override
public void actionPerformed(ActionEvent e){
for(String s: items.keySet()){
if(items.get(s) == e.getSource()){
EventMenu em = new EventMenu(td, s);
}
}
}
}
The problem is that the buttons are not updating. I expect that the JPanel should be constantly repopulating with updated JButtons with different text, but it seems that the program hangs and doesn't update.
I tried making a simpler example which I modified from here, with different results:
public class DigitalWatch implements Runnable{
JFrame f;
JPanel p;
Thread t=null;
int hours=0, minutes=0, seconds=0;
String timeString = "";
JButton b;
DigitalWatch(){
f=new JFrame();
p = new JPanel();
t = new Thread(this);
t.start();
b=new JButton();
b.setBounds(100,100,100,50);
p.add(b);
f.add(p);
f.setSize(300,400);
f.setLayout(null);
f.setVisible(true);
}
public void run() {
try {
while (true) {
Calendar cal = Calendar.getInstance();
hours = cal.get( Calendar.HOUR_OF_DAY );
if ( hours > 12 ) hours -= 12;
minutes = cal.get( Calendar.MINUTE );
seconds = cal.get( Calendar.SECOND );
SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss");
Date date = cal.getTime();
timeString = formatter.format( date );
p.removeAll();
b=new JButton(timeString);
b.setBounds(100,100,100,50);
p.add(b);
f.add(p);
p.revalidate();
f.repaint();
//printTime();
t.sleep( 1000 ); // interval given in milliseconds
}
}
catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) {
new DigitalWatch();
}
}
This snippet fails to draw anything, unlike the first which at least draws the objects created in the constructor.
How can I make a list or grid JPanel update procedurally and in real time and populate buttons? I know I could change the text of each button every time, but the number of buttons may change at any time.
Full code here.
you are violating Swing's single thread rule - you are not supposed to do any UI related stuff outside Swing's event dispatch thread.
Read up on it here and here.
Below is a working example. Not sure why they chose to use a button to show the time though. :-)
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;
public class DigitalWatch extends JFrame {
private DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
public DigitalWatch() {
JButton btn = new JButton(getCurrentTime());
this.getContentPane().setLayout(new FlowLayout());
this.getContentPane().add(btn);
this.setPreferredSize(new Dimension(200, 150));
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null); // center it on the screen
new Timer(500, e -> btn.setText(getCurrentTime())).start();
}
private String getCurrentTime() {
return formatter.format(LocalTime.now());
}
public static void main(String[] args) {
new DigitalWatch().setVisible(true);
}
}

Putting JLabel on JScrollPane from another class in Java

I am making family tree and this is my problem. I have screens NewFamilyTree.java and NewPerson.java.
NewFamilyTree.java:
public class NewFamilyTree {
...
private void initialize() {
frame = new JFrame();
frame.setTitle("New family tree");
frame.setBounds(100, 100, 906, 569);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
...
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
JScrollPane scrollPane = new JScrollPane();
tabbedPane.addTab("Tree", null, scrollPane, null);
panel_1 = new JPanel();
scrollPane.setViewportView(panel_1);
panel_1.setLayout(new MigLayout("", "[][][][][][][][]", "[][][][][][]"));
NewPerson.java:
public class NewPerson{
...
buttonAdd = new JButton("Add");
buttonAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
String names = textFieldNames.getText();
String dateBirth = textFieldDateOfBirth.getText();
String bio = textAreaBio.getText();
Data newData = new Data(names, dateBirth, bio, fileID);
//code that puts new label on scrollpane from NewFamilyTree.java
}
});
buttonAdd.setBackground(new Color(30, 144, 255));
frame.getContentPane().add(buttonAdd, "cell 2 6,grow");
}
I need to put new JLabel from class NewPerson, by pressing on button Add, on the JScrollPane of NewFamilytree.java. Hope someone can help, I searched a lot and couldn't help myself.
EDIT: After the answer from #mjr.
I added public JPanel panel_1; in NewFamilyTree. In Add action performed I added:
JLabel lblHomer = new JLabel("Homer");
lblHomer.setIcon(new ImageIcon("C:\\Users\\Tinmar\\Desktop\\HomerSimpson3.gif"));
panel_1.add(lblHomer, "cell 7 5");
No errors, but - nothing happens after I press the add button. I also added NewPerson EXTENDS NewFamilyTree, ofc.
NewPerson doesn't need extend from NewFamilyTree, it's not adding any functionality to the class
Instead of using a JFrame in NewPerson, consider using a modal JDialog instead. See How to Make Dialogs for more details
Limit the exposure of components between classes. There is no reason why NewFamilyTree should be able to access the "window" been used by NewPerson. There's no reason why NewPerson should be adding anything to NewFamilyTree
Don't mix heavy weight components (like java.awt.Button) with light weight components, this can cause no end of issues...
You need to change the way you think of things. Instead of trying to make the NewPerson update the UI of the NewFamilyTree, have NewPerson gather the details from the user and pass this information back to NewFamilyTree so it can use it...
For example...
JButton newPersonButton = new JButton("New Person");
newPersonButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Data data = NewPerson.createPerson(frame);
if (data != null) {
JLabel lblHomer = new JLabel(data.names);
panel_1.add(lblHomer, "cell 7 5");
panel_1.revalidate();
}
}
});
This basically uses a static method createPerson which passes back a instance of Data (or null if the user cancelled the operation), which NewFamilyTree can then use. It decouples the code, as NewPerson is not relient on anything from NewFamilyTree and NewFamilyTree maintains control. This clearly defines the areas of responsibility between the two classes, it also means that NewPerson could be called from anywhere...
The createPerson method looks, something like, this...
public static Data createPerson(Component comp) {
NewPerson newPerson = new NewPerson();
Window win = SwingUtilities.getWindowAncestor(comp);
JDialog dialog = null;
if (win instanceof Frame) {
dialog = new JDialog((Frame) win, "New person", true);
} else if (win instanceof Dialog) {
dialog = new JDialog((Dialog) win, "New person", true);
} else {
dialog = new JDialog((Frame) null, "New person", true);
}
newPerson.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof Component) {
Window win = SwingUtilities.getWindowAncestor((Component) source);
win.dispose();
}
}
});
dialog.add(newPerson);
dialog.setVisible(true);
return newPerson.getData();
}
It basically creates and instance of JDialog, shows it to the user and waits until the NewPerson class triggers an ActionEvent, which it uses to dispose of the dialog. It then asks the instance of NewPerson for the data...
And because there's a whole bunch of functionality I've not talked about, here's a fully runnable example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
public class NewFamilyTree {
private JFrame frame;
private JPanel panel_1;
private JScrollPane scrollPane;
private JTabbedPane tabbedPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
NewFamilyTree window = new NewFamilyTree();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public NewFamilyTree() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setTitle("New family tree");
frame.getContentPane().setBackground(new Color(135, 206, 250));
frame.setBounds(100, 100, 906, 569);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBackground(new Color(30, 144, 255));
frame.getContentPane().add(panel, BorderLayout.EAST);
panel.setLayout(new MigLayout("", "[]", "[][][][][][][][]"));
JButton newPersonButton = new JButton("New Person");
newPersonButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
Data data = NewPerson.createPerson(frame);
if (data != null) {
JLabel lblHomer = new JLabel(data.names);
// lblHomer.setIcon(new ImageIcon("C:\\Users\\Tinmar\\Desktop\\HomerSimpson3.gif"));
panel_1.add(lblHomer, "cell 7 5");
panel_1.revalidate();
}
}
});
panel.add(newPersonButton, "cell 0 5");
JButton btnNewButton_1 = new JButton("New button");
panel.add(btnNewButton_1, "cell 0 6");
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
scrollPane = new JScrollPane();
tabbedPane.addTab("Tree", null, scrollPane, null);
panel_1 = new JPanel();
scrollPane.setViewportView(panel_1);
panel_1.setLayout(new MigLayout("", "[][][][][][][][]", "[][][][][][]"));
// JLabel lblHomer = new JLabel("Homer");
// lblHomer.setIcon(new ImageIcon("C:\\Users\\Tinmar\\Desktop\\HomerSimpson3.gif"));
// panel_1.add(lblHomer, "cell 7 5");
JScrollPane scrollPane_1 = new JScrollPane();
tabbedPane.addTab("Info", null, scrollPane_1, null);
frame.repaint();
}
//
// /**
// * Launch the application.
// */
// public static void main(String[] args) {
// EventQueue.invokeLater(new Runnable() {
// public void run() {
// try {
// NewPerson window = new NewPerson();
// window.frame.setVisible(true);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// });
// }
public static class NewPerson extends JPanel {
private JTextField textFieldNames;
private JButton selectPictureButton;
private JLabel labelDateOfBirth;
private JTextField textFieldDateOfBirth;
private JLabel labelShortBio;
private JTextArea textAreaBio;
private JLabel labelSelectPicture;
private JButton buttonAdd;
private String fileID;
private Data data;
/**
* Create the application.
*/
private NewPerson() {
initialize();
}
public static Data createPerson(Component comp) {
NewPerson newPerson = new NewPerson();
Window win = SwingUtilities.getWindowAncestor(comp);
JDialog dialog = null;
if (win instanceof Frame) {
dialog = new JDialog((Frame) win, "New person", true);
} else if (win instanceof Dialog) {
dialog = new JDialog((Dialog) win, "New person", true);
} else {
dialog = new JDialog((Frame) null, "New person", true);
}
newPerson.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (source instanceof Component) {
Window win = SwingUtilities.getWindowAncestor((Component) source);
win.dispose();
}
}
});
dialog.add(newPerson);
dialog.pack();
dialog.setLocationRelativeTo(comp);
dialog.setVisible(true);
return newPerson.getData();
}
public void addActionListener(ActionListener listener) {
listenerList.add(ActionListener.class, listener);
}
protected void fireActionPerformed() {
ActionListener[] listeners = listenerList.getListeners(ActionListener.class);
if (listeners != null && listeners.length > 0) {
ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "created");
for (ActionListener listener : listeners) {
listener.actionPerformed(evt);
}
}
}
public Data getData() {
return data;
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
setBackground(new Color(135, 206, 250));
setLayout(new MigLayout("", "[][][grow]", "[][][][grow][][][]"));
JLabel labelNames = new JLabel("Name and Surname:");
add(labelNames, "cell 1 1,alignx trailing");
textFieldNames = new JTextField();
add(textFieldNames, "cell 2 1,growx");
textFieldNames.setColumns(10);
labelDateOfBirth = new JLabel("Date of birth:");
add(labelDateOfBirth, "cell 1 2,alignx center,aligny center");
textFieldDateOfBirth = new JTextField();
add(textFieldDateOfBirth, "cell 2 2,growx");
textFieldDateOfBirth.setColumns(10);
labelShortBio = new JLabel("Bio:");
add(labelShortBio, "cell 1 3,alignx center,aligny center");
textAreaBio = new JTextArea();
add(textAreaBio, "cell 2 3,grow");
labelSelectPicture = new JLabel("Select picture:");
add(labelSelectPicture, "cell 1 4,alignx center,aligny center");
selectPictureButton = new JButton("...");
selectPictureButton.setBackground(new Color(30, 144, 255));
selectPictureButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
JFileChooser chooser = new JFileChooser(new File(System.getProperty("user.home") + "\\Desktop"));
chooser.setDialogTitle("Select Location");
chooser.setFileSelectionMode(JFileChooser.APPROVE_OPTION);
chooser.setAcceptAllFileFilterUsed(false);
if (chooser.showSaveDialog(null) == JFileChooser.APPROVE_OPTION) {
fileID = chooser.getSelectedFile().getPath();
// txtField.setText(fileID);
}
}
});
add(selectPictureButton, "cell 2 4");
buttonAdd = new JButton("Add");
buttonAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
String names = textFieldNames.getText();
String dateBirth = textFieldDateOfBirth.getText();
String bio = textAreaBio.getText();
data = new Data(names, dateBirth, bio, fileID);
fireActionPerformed();
}
});
buttonAdd.setBackground(new Color(30, 144, 255));
add(buttonAdd, "cell 2 6,grow");
}
}
public static class Data {
private final String names;
private final String dateBirth;
private final String bio;
private final String fileID;
private Data(String names, String dateBirth, String bio, String fileID) {
this.names = names;
this.dateBirth = dateBirth;
this.bio = bio;
this.fileID = fileID;
}
}
}
Don't rely on static to provide functionality across classes. If you HAVE to have something from another class, pass it as a reference. static is not your friend and you should be careful and wary of it's use
Don't expose the fields of your class without very good reason, rely on interfaces to allow classes to provide or get information. This limits what other classes can do.
Separate and isolate responsibility
Take a look at How to Use Trees
The same way that NewFamilyTree's frame is accessible in NewPerson when you add the button to it, the scrollPane must also be accessible in NewPerson, if you want to add a label from that class. So just do the same thing with scrollPane as what you did with frame to be able to use it in NewPerson.
I assumed that the JScrollPane and addButton are in different frames... although it will work for sure if they are in the same frame.
Basically you need to provide getters for the JScrollPane and the JPanel, so that they can be accessed from the NewPerson class.
In the action listener of the buttonAdd, you need to increase the preferred size of the panel,, if the labels don't feet in the current size of the panel. The scrollbars will appear automatically when the preferred size of the panel are bigger that the view size of the JScrollPane.
Please see the code below:
NewFamilyTree.jva:
package dva.test001;
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
public class NewFamilyTree {
private JFrame frame;
private JScrollPane scrollPane;
private JPanel panel;
public NewFamilyTree() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setTitle("New family tree");
frame.setBounds(100, 100, 906, 569);
frame.setLayout(new BorderLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
frame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
panel = new JPanel();
panel.setPreferredSize(new Dimension(700, 300));
panel.setLayout(null);
scrollPane = new JScrollPane(panel);
tabbedPane.addTab("Tree", null, scrollPane, null);
frame.setVisible(true);
}
public static void main(String[] args) {
NewFamilyTree ft = new NewFamilyTree();
NewPerson np = new NewPerson(ft);
}
public JFrame getFrame() {
return frame;
}
public JScrollPane getScrollPane() {
return scrollPane;
}
public JPanel getPanel() {
return panel;
}
}
NewPerson.java:
package dva.test001;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class NewPerson {
private NewFamilyTree familyTree;
private static final int labelHeight = 30;
public NewPerson(NewFamilyTree familyTree) {
this.familyTree = familyTree;
init();
}
public void init() {
JFrame frame = new JFrame();
frame.setTitle("New Person");
frame.setBounds(100, 500, 906, 100);
JButton buttonAdd = new JButton("Add");
buttonAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
String names = "names"; //textFieldNames.getText();
String dateBirth = "date"; //textFieldDateOfBirth.getText();
String bio = "bio"; //textAreaBio.getText();
//Data newData = new Data(names, dateBirth, bio, fileID);
//code that puts new label on scrollpane from NewFamilyTree.java
JLabel lbl = new JLabel(names);
int top = familyTree.getPanel().getComponentCount() * labelHeight;
if(top + labelHeight > familyTree.getPanel().getHeight()) {
familyTree.getPanel().setPreferredSize(new Dimension(familyTree.getPanel().getWidth(), top + labelHeight));
familyTree.getScrollPane().revalidate();
}
familyTree.getPanel().add(lbl);
lbl.setBounds(10, top, 100, labelHeight);
}
});
buttonAdd.setBackground(new Color(30, 144, 255));
frame.getContentPane().add(buttonAdd);
frame.setVisible(true);
}
}

JScrollPane displays the content using only the horizontal scroll bar

I want to display a list of strings in a window and i tried to use a JPanel surounded by JScrollPane because the size of the strings list is unknown. The problem is that the window is displaying the text Horizontally and i want to be displayed line after line. How to fix this? This is the code i've written so far.
package interface_classes;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JTextArea;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
public class ErrorMessageW {
private JFrame errorMessageW;
private ArrayList<String> errors;
private JPanel panel;
private JScrollPane scrollPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
final ArrayList<String> err = new ArrayList<>();
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ErrorMessageW window = new ErrorMessageW(err);
window.errorMessageW.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ErrorMessageW(ArrayList<String> err) {
errors = err;
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
errorMessageW = new JFrame();
errorMessageW.setTitle("Unfilled forms");
errorMessageW.setBounds(100, 100, 367, 300);
errorMessageW.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btnOk = new JButton("OK");
btnOk.setBounds(239, 208, 89, 23);
btnOk.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
errorMessageW.dispose();
}
});
errorMessageW.getContentPane().setLayout(null);
errorMessageW.getContentPane().add(btnOk);
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setBounds(10, 10, 330, 175);
errorMessageW.getContentPane().add(scrollPane);
panel = new JPanel();
for(String s : errors){
JTextArea text = new JTextArea(1,20);
text.setText(s);
text.setFont(new Font("Verdana",1,10));
text.setForeground(Color.RED);
panel.add(text);
}
scrollPane.setViewportView(panel);
}
public JFrame getErrorMessageW() {
return errorMessageW;
}
public void setErrorMessageW(JFrame errorMessageW) {
this.errorMessageW = errorMessageW;
}
}
This is what i get
This is what i want, but using the JScrollPane:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.ArrayList;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class ErrorMessageW {
private JFrame errorMessageW;
private ArrayList<String> errors;
private JPanel panel;
private JScrollPane scrollPane;
private JTextArea errorMessage = new JTextArea(3, 30);
/**
* Launch the application.
*/
public static void main(String[] args) {
final ArrayList<String> err = new ArrayList<String>();
err.add("Short String");
err.add("A very very very very very very very very very very very "
+ "very very very very very very very very very very very "
+ "very very very very very very very very long String");
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ErrorMessageW window = new ErrorMessageW(err);
window.errorMessageW.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public ErrorMessageW(ArrayList<String> err) {
errors = err;
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
errorMessageW = new JFrame();
JPanel contentPane = new JPanel(new BorderLayout(5, 15));
contentPane.setBorder(new EmptyBorder(10, 10, 10, 10));
errorMessage.setLineWrap(true);
errorMessage.setWrapStyleWord(true);
JScrollPane jsp = new JScrollPane(
errorMessage,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
);
contentPane.add(jsp, BorderLayout.PAGE_START);
errorMessageW.add(contentPane);
errorMessageW.setTitle("Unfilled forms");
errorMessageW.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JButton btnOk = new JButton("OK");
btnOk.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
errorMessageW.dispose();
}
});
JPanel btnConstrain = new JPanel(new FlowLayout(FlowLayout.TRAILING));
btnConstrain.add(btnOk);
contentPane.add(btnConstrain, BorderLayout.PAGE_END);
scrollPane = new JScrollPane();
scrollPane.setVerticalScrollBarPolicy(
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
scrollPane.setHorizontalScrollBarPolicy(
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollPane, BorderLayout.CENTER);
DefaultListModel<String> listModel = new DefaultListModel<String>();
for (String s : errors) {
listModel.addElement(s);
}
final JList<String> errorList = new JList<String>(listModel);
Dimension preferredSize = new Dimension(errorMessage.getPreferredSize().width,200);
errorList.setPreferredSize(preferredSize);
ListSelectionListener errorSelect = new ListSelectionListener() {
#Override
public void valueChanged(ListSelectionEvent e) {
errorMessage.setText(errorList.getSelectedValue());
}
};
errorList.addListSelectionListener(errorSelect);
scrollPane.setViewportView(errorList);
errorMessageW.pack();
}
public JFrame getErrorMessageW() {
return errorMessageW;
}
public void setErrorMessageW(JFrame errorMessageW) {
this.errorMessageW = errorMessageW;
}
}
First of all, you could try, instead of creating multiple instances of JTextArea, using only one and appending each error to it like this:
JTextArea text = new JTextArea(1, 20);
text.setFont(new Font("Verdana",1,10));
text.setForeground(Color.RED);
for(String s : errors) {
text.append(s + "\n");
}
panel.add(text);
However, if you do need to create more than one JTextArea, you can use a BoxLayout like this:
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
You just need to write a function that adds a new line character as an element of your ArrayList after every other element in your ArrayList of errors. Below i did a test program that shows how that can be done. I also checked the oputput. Just paste the code and understand the working of code. All the best!
import java.util.ArrayList;
public class TestingArraylist {
static ArrayList<String> errors = new ArrayList<String>();
static final String[] warnings = new String[]{"Error 0 occured","Error 1 occured","Error 2 occured","Error 3 occured","Error 4 occured"};;
public static void addNewLineToArrayList(String[] elementofarraylist){
for(int i =0;i<elementofarraylist.length;i++){
errors.add(elementofarraylist[i]);
errors.add("\n"); //this is what you need to do!
}
}
public static void main(String[] args) {
addNewLineToArrayList(warnings);
//checking below if our work has really succeded or not!!
for(int j =0;j<errors.size();j++){
System.out.print(errors.get(j));
}
}
}

Applet not appearing full

I just created an applet
public class HomeApplet extends JApplet {
private static final long serialVersionUID = -7650916407386219367L;
//Called when this applet is loaded into the browser.
public void init() {
//Execute a job on the event-dispatching thread; creating this applet's GUI.
// setSize(400, 400);
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't complete successfully");
}
}
private void createGUI() {
RconSection rconSection = new RconSection();
rconSection.setOpaque(true);
// CommandArea commandArea = new CommandArea();
// commandArea.setOpaque(true);
JTabbedPane tabbedPane = new JTabbedPane();
// tabbedPane.setSize(400, 400);
tabbedPane.addTab("Rcon Details", rconSection);
// tabbedPane.addTab("Commad Area", commandArea);
setContentPane(tabbedPane);
}
}
where the fisrt tab is:
package com.rcon;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import com.Bean.RconBean;
import com.util.Utility;
public class RconSection extends JPanel implements ActionListener{
/**
*
*/
private static final long serialVersionUID = -9021500288377975786L;
private static String TEST_COMMAND = "test";
private static String CLEAR_COMMAND = "clear";
private static JTextField ipText = new JTextField();
private static JTextField portText = new JTextField();
private static JTextField rPassText = new JTextField();
// private DynamicTree treePanel;
public RconSection() {
// super(new BorderLayout());
JLabel ip = new JLabel("IP");
JLabel port = new JLabel("Port");
JLabel rPass = new JLabel("Rcon Password");
JButton testButton = new JButton("Test");
testButton.setActionCommand(TEST_COMMAND);
testButton.addActionListener(this);
JButton clearButton = new JButton("Clear");
clearButton.setActionCommand(CLEAR_COMMAND);
clearButton.addActionListener(this);
JPanel panel = new JPanel(new GridLayout(3,2));
panel.add(ip);
panel.add(ipText);
panel.add(port);
panel.add(portText);
panel.add(rPass);
panel.add(rPassText);
JPanel panel1 = new JPanel(new GridLayout(1,3));
panel1.add(testButton);
panel1.add(clearButton);
add(panel);
add(panel1);
// add(panel, BorderLayout.NORTH);
// add(panel1, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent arg0) {
if(arg0.getActionCommand().equals(TEST_COMMAND)){
String ip = ipText.getText().trim();
if(!Utility.checkIp(ip)){
ipText.requestFocusInWindow();
ipText.selectAll();
JOptionPane.showMessageDialog(this,"Invalid Ip!!!");
return;
}
String port = portText.getText().trim();
if(port.equals("") || !Utility.isIntNumber(port)){
portText.requestFocusInWindow();
portText.selectAll();
JOptionPane.showMessageDialog(this,"Invalid Port!!!");
return;
}
String pass = rPassText.getText().trim();
if(pass.equals("")){
rPassText.requestFocusInWindow();
rPassText.selectAll();
JOptionPane.showMessageDialog(this,"Enter Rcon Password!!!");
return;
}
RconBean rBean = RconBean.getBean();
rBean.setIp(ip);
rBean.setPassword(pass);
rBean.setPort(Integer.parseInt(port));
if(!Utility.testConnection()){
rPassText.requestFocusInWindow();
rPassText.selectAll();
JOptionPane.showMessageDialog(this,"Invalid Rcon!!!");
return;
}else{
JOptionPane.showMessageDialog(this,"Correct Rcon!!!");
return;
}
}
else if(arg0.getActionCommand().equals(CLEAR_COMMAND)){
ipText.setText("");
portText.setText("");
rPassText.setText("");
}
}
}
it appears as
is has cropped some data how to display it full and make the applet non resizable as well. i tried setSize(400, 400); but it didnt helped the inner area remains the same and outer boundaries increases
Here's another variation on your layout. Using #Andrew's tag-in-source method, it's easy to test from the command line:
$ /usr/bin/appletviewer HomeApplet.java
// <applet code='HomeApplet' width='400' height='200'></applet>
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class HomeApplet extends JApplet {
#Override
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
#Override
public void run() {
createGUI();
}
});
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
private void createGUI() {
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.addTab("Rcon1", new RconSection());
tabbedPane.addTab("Rcon2", new RconSection());
this.add(tabbedPane);
}
private static class RconSection extends JPanel implements ActionListener {
private static final String TEST_COMMAND = "test";
private static final String CLEAR_COMMAND = "clear";
private JTextField ipText = new JTextField();
private JTextField portText = new JTextField();
private JTextField rPassText = new JTextField();
public RconSection() {
super(new BorderLayout());
JLabel ip = new JLabel("IP");
JLabel port = new JLabel("Port");
JLabel rPass = new JLabel("Rcon Password");
JButton testButton = new JButton("Test");
testButton.setActionCommand(TEST_COMMAND);
testButton.addActionListener(this);
JButton clearButton = new JButton("Clear");
clearButton.setActionCommand(CLEAR_COMMAND);
clearButton.addActionListener(this);
JPanel panel = new JPanel(new GridLayout(3, 2));
panel.add(ip);
panel.add(ipText);
panel.add(port);
panel.add(portText);
panel.add(rPass);
panel.add(rPassText);
JPanel buttons = new JPanel(); // default FlowLayout
buttons.add(testButton);
buttons.add(clearButton);
add(panel, BorderLayout.NORTH);
add(buttons, BorderLayout.SOUTH);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(e);
}
}
}
As I mentioned in a comment, this question is really about how to layout components in a container. This example presumes you wish to add the extra space to the text fields and labels. The size of the applet is set in the HTML.
200x130 200x150
/*
<applet
code='FixedSizeLayout'
width='200'
height='150'>
</applet>
*/
import java.awt.*;
import javax.swing.*;
public class FixedSizeLayout extends JApplet {
public void init() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
initGui();
}
});
}
private void initGui() {
JTabbedPane tb = new JTabbedPane();
tb.addTab("Rcon Details", new RconSection());
setContentPane(tb);
validate();
}
}
class RconSection extends JPanel {
private static String TEST_COMMAND = "test";
private static String CLEAR_COMMAND = "clear";
private static JTextField ipText = new JTextField();
private static JTextField portText = new JTextField();
private static JTextField rPassText = new JTextField();
public RconSection() {
super(new BorderLayout(3,3));
JLabel ip = new JLabel("IP");
JLabel port = new JLabel("Port");
JLabel rPass = new JLabel("Rcon Password");
JButton testButton = new JButton("Test");
testButton.setActionCommand(TEST_COMMAND);
JButton clearButton = new JButton("Clear");
clearButton.setActionCommand(CLEAR_COMMAND);
JPanel panel = new JPanel(new GridLayout(3,2));
panel.add(ip);
panel.add(ipText);
panel.add(port);
panel.add(portText);
panel.add(rPass);
panel.add(rPassText);
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER,5,5));
panel1.add(testButton);
panel1.add(clearButton);
add(panel, BorderLayout.CENTER);
add(panel1, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Container c = new RconSection();
JOptionPane.showMessageDialog(null, c);
}
});
}
}
Size of applet viewer does not depend on your code.
JApplet is not window, so in java code you can't write japplet dimensions. You have to change run settings. I don't know where exactly are in other ide's, but in Eclipse you can change dimensions in Project Properties -> Run/Debug settings -> click on your launch configurations file (for me there were only 1 - main class) -> edit -> Parameters. There you can choose width and height for your applet. save changes and you are good to go

Categories

Resources