I want to attached the progress bar to the Frame and not the test start button that I have currently. The progress bar works but I want it run when the window is opened for the time being and then I can attach it to whatever I want later on.
Code:
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.JProgressBar;
import javax.swing.JButton;
public class ProgressBarWindow extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel contentPane;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
ProgressBarWindow frame = new ProgressBarWindow();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public ProgressBarWindow() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch(Exception e) { }
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 183);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JProgressBar progressBar = new JProgressBar();
progressBar.setBounds(22, 77, 386, 27);
contentPane.add(progressBar);
JButton btnNewButton = new JButton("Cancel");
btnNewButton.setBounds(319, 111, 89, 23);
btnNewButton.addMouseListener(new myMouseListener2());
contentPane.add(btnNewButton);
JButton btnStart = new JButton("Start");
btnStart.addActionListener(new btnDoAction(progressBar));
btnStart.setBounds(220, 111, 89, 23);
contentPane.add(btnStart);
}
}
class myClose implements MouseListener {
myClose() { }
#Override
public void mouseClicked(MouseEvent e) {
final Component source = e.getComponent();
final JFrame frame = (JFrame) SwingUtilities.getRoot(source);
frame.dispose();
}
#Override
public void mousePressed(MouseEvent e) {
final Component source = e.getComponent();
final JFrame frame = (JFrame) SwingUtilities.getRoot(source);
frame.dispose();
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
class btnDoAction implements ActionListener{
JProgressBar temp = new JProgressBar();
btnDoAction(JProgressBar p) {
this.temp = p;
}
public void actionPerformed (ActionEvent e){
new Thread(new thread1(temp)).start(); //Start the thread
}
}
class thread1 implements Runnable{
JProgressBar pBar = new JProgressBar();
thread1(JProgressBar u) {
this.pBar = u;
}
public void run(){
for (int i=0; i<=100; i++){ //Progressively increment variable i
pBar.setValue(i); //Set value
pBar.repaint(); //Refresh graphics
try{Thread.sleep(50);} //Sleep 50 milliseconds
catch (InterruptedException err){}
}
}
}
If I understand correctly, instead of using a JFrame as you base component, extend your class from a JPanel, this way you can add it to anything you want.
You could then provide setter and getter methods to adjust the progress bar, but I'd do this via some kind of interface contract .
Don't use null layouts. You don't control aspects like fonts, font metrics, rendering pipelines and other properties which effect the amount of space components need in order to be rendered properly across multiple systems (even those running the same OS)
Don't use MouseListeners on buttons, use ActionListeners instead. To takes into account when the use clicks on the button and presses space/Zener
Don't update the UI from any thread other then the a Event Dispatching Thread. See Concurrency in Swing for more details. Consider using a SwingWorker instead, it has functionality to sync the background thread with the EDT and in built progress support
Updated
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class LayoutExample {
public static void main(String[] args) {
new LayoutExample();
}
public LayoutExample() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new ProgressPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ProgressPane extends JPanel {
private JProgressBar pb;
private JButton start;
private JButton cancel;
public ProgressPane() {
pb = new JProgressBar();
start = new JButton("Start");
cancel = new JButton("Cacnel");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(50, 10, 5, 10);
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.gridwidth = 2;
add(pb, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.insets = new Insets(0, 0, 0, 5);
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 1;
gbc.gridwidth = 1;
gbc.anchor = GridBagConstraints.EAST;
add(start, gbc);
gbc.weightx = 0;
gbc.gridx = 1;
gbc.insets = new Insets(0, 0, 0, 10);
gbc.anchor = GridBagConstraints.WEST;
add(cancel, gbc);
}
}
}
Related
i'm new to Java and I'm trying to add a time delay when I press a Jbutton start. I used TimeUnit.SECONDS.sleep() but it didn't work, then i researched and found out about java swing timer, but it didn't work either and I can't figure out why
btnStart.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("start DONE");
Object step;
for (int i = 1; i < n; i++) {
//code that shows on interface
// then i want a delay here then to carry on with the iteration of for
timer.start();
};
}
});
}
});
You're almost there. But you seem to be misunderstanding what the Timer is actually doing for you.
The Timer is acting as a kind of pseudo loop, with a built in delay. That is, after each time period, it will execute. This means, that each time your ActionListener is triggered, you want to execute the next step in your logic.
For example...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel contentPane = new JPanel(new GridBagLayout());
public TestPane() {
setLayout(new BorderLayout());
add(new JScrollPane(contentPane));
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
private int row = 0;
private int count = 1000;
private DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
#Override
public void actionPerformed(ActionEvent e) {
row = 0;
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.weightx = 1;
contentPane.removeAll();
contentPane.revalidate();
contentPane.repaint();
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
row++;
if (row >= count) {
((Timer)(e.getSource())).stop();
return;
}
JLabel label = new JLabel(LocalDateTime.now().format(formatter));
contentPane.add(label, gbc);
contentPane.revalidate();
contentPane.repaint();
// This is only required because the layout pass seems
// to be execute in different run cycle, so the label's
// bounds are not been updated yet. We force the layout
// pass so we can scroll to the label, but otherwise
// isn't needed
contentPane.doLayout();
Rectangle bounds = label.getBounds();
bounds.y += bounds.height;
contentPane.scrollRectToVisible(bounds);
}
});
timer.start();
}
});
add(startButton, BorderLayout.NORTH);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
I'm learning java swing, I have many buttons, but I need to put some new buttons in the red zone when I select something on my combobox, the problem is that I don't know how to use the buttons if those are not created at the beginning.
Here some buttons loaded when I select in the combobox, I need to make some actions with them:
thanks
Your question leaves a lot open to interpretation.
So, for example, if the values are fixed, I would start by separating them into individual panels, isolating their functionality and workflow, and simple swap them based on what is selected.
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JComboBox<String> comboBox = new JComboBox<>();
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>();
model.addElement("Option A");
model.addElement("Option B");
comboBox.setModel(model);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(8, 8, 8, 8);
add(comboBox, gbc);
CardLayout cardLayout = new CardLayout();
JPanel buttonOptions = new JPanel(cardLayout);
buttonOptions.add(new OptionAPane(), "optionA");
buttonOptions.add(new OptionBPane(), "optionB");
gbc.gridy = 1;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
add(buttonOptions, gbc);
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
switch (comboBox.getSelectedIndex()) {
case 0:
cardLayout.show(buttonOptions, "optionA");
break;
case 1:
cardLayout.show(buttonOptions, "optionB");
break;
}
}
});
}
}
public class OptionAPane extends JPanel {
public OptionAPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
JButton btnThis = new JButton("This");
btnThis.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Do this");
}
});
JButton btnThat = new JButton("That");
btnThis.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Do that");
}
});
add(new JLabel("A Options"), gbc);
add(btnThis, gbc);
add(btnThat, gbc);
}
}
public class OptionBPane extends JPanel {
public OptionBPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
JButton btnOther = new JButton("Other");
btnOther.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Do other");
}
});
JButton btnSomethingElse = new JButton("Something else");
btnOther.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Do something else");
}
});
add(new JLabel("B Options"), gbc);
add(btnOther, gbc);
add(btnSomethingElse, gbc);
}
}
}
But how do I know when a button is clicked.
This is where an observer pattern would be used. You'd define one or more listeners, based on the needs of each panel and when a button on a panel is clicked, this listener would trigger an event and you could make use of it
If, on the other hand, you need something a little more dynamic (ie each option can have different actions based on some other configuration), you might be able to make use of the Action API
For example...
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ActionGroup {
private String description;
private List<Action> actions;
public ActionGroup(String description) {
this.description = description;
this.actions = new ArrayList<>(25);
}
public ActionGroup(String description, List<Action> actions) {
this.description = description;
this.actions = actions;
}
public String getDescription() {
return description;
}
public void add(Action action) {
actions.add(action);
}
public void remove(Action action) {
actions.remove(action);
}
public List<Action> getActions() {
return Collections.unmodifiableList(actions);
}
}
public class SimpleAction extends AbstractAction {
// You have a number of choices when using something like Action,
// You can create a custom Action based on your needs and pass
// in the information it needs to do it's job OR, you can use
// a observer pattern to get notified when the ActionListener
// is triggered
public SimpleAction(String name) {
putValue(NAME, name);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(getValue(NAME) + " was triggered");
}
}
public class ActionGroupCellRenderer extends DefaultListCellRenderer {
#Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value instanceof ActionGroup) {
value = ((ActionGroup)value).getDescription();
}
return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
}
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
ActionGroup optionA = new ActionGroup("Option A");
optionA.add(new SimpleAction("Cat"));
optionA.add(new SimpleAction("Doggy"));
optionA.add(new SimpleAction("Bunny"));
optionA.add(new SimpleAction("Rat"));
optionA.add(new SimpleAction("Cow"));
ActionGroup optionB = new ActionGroup("Option B");
optionB.add(new SimpleAction("Banana"));
optionB.add(new SimpleAction("Apple"));
optionB.add(new SimpleAction("Pear"));
optionB.add(new SimpleAction("Orange"));
optionB.add(new SimpleAction("Lemon"));
JComboBox<ActionGroup> comboBox = new JComboBox<>();
comboBox.setRenderer(new ActionGroupCellRenderer());
DefaultComboBoxModel<ActionGroup> model = new DefaultComboBoxModel<>();
model.addElement(optionA);
model.addElement(optionB);
comboBox.setModel(model);
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(8, 8, 8, 8);
add(comboBox, gbc);
gbc.gridy = 1;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
ActionGroupPane buttonOptions = new ActionGroupPane();
buttonOptions.setActionGroup(optionA);
add(buttonOptions, gbc);
comboBox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Object item = comboBox.getSelectedItem();
if (item instanceof ActionGroup) {
System.out.println(item);
buttonOptions.setActionGroup((ActionGroup)item);
}
}
});
}
}
public class ActionGroupPane extends JPanel {
public ActionGroupPane() {
setLayout(new GridBagLayout());
}
public void setActionGroup(ActionGroup actionGroup) {
removeAll();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = gbc.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
add(new JLabel(actionGroup.getDescription()), gbc);
for (Action action : actionGroup.getActions()) {
add(new JButton(action), gbc);
}
revalidate();
repaint();
}
}
}
Action is very powerful and I would recommend taking some time to have look at How to Use Actions
i'm new to Java and experience a little bit with the WindowBuilder. I want to change the visibility of a different components like labels or textfields. So I wrote an example code: the function is, when I click on the button btnAnzahl the boolean bNoteVis is set to true in the method uebernehmen and bNoteVis is used as the variable to change the visibility of the label lblNote.
When I click on the button the message True is shown on the textfield tfNote but the label lblNote is still not visible.
Can somebody tell me how I can change the visibility like this because I want to change it with many components in multiple events.
package gui;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Notenbilanz_2 extends JFrame {
private JPanel contentPane;
private JTextField tfAnzahl;
private JTextField tfNote;
/**
* Launch the application.
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
} catch (Throwable e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Notenbilanz_2 frame = new Notenbilanz_2();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Notenbilanz_2() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblAnzahl = new JLabel("Noten Anzahl");
lblAnzahl.setBounds(10, 11, 87, 14);
contentPane.add(lblAnzahl);
tfAnzahl = new JTextField();
tfAnzahl.setBounds(10, 31, 104, 20);
contentPane.add(tfAnzahl);
tfAnzahl.setColumns(10);
JLabel lblNote = new JLabel("1.Note");
lblNote.setVisible(bNoteVis);
lblNote.setBounds(10, 68, 87, 16);
contentPane.add(lblNote);
tfNote = new JTextField();
tfNote.setBounds(10, 95, 104, 20);
contentPane.add(tfNote);
tfNote.setColumns(10);
JButton btnAnzahl = new JButton("Umrechnen");
btnAnzahl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
uebernehmen();
if (bNoteVis) {
tfNote.setText("True");
}
}
});
btnAnzahl.setBounds(159, 28, 100, 26);
contentPane.add(btnAnzahl);
JButton btnNote = new JButton("Umrechnen");
btnNote.setBounds(159, 92, 100, 26);
contentPane.add(btnNote);
}
boolean bNoteVis = false;
private void uebernehmen() {
bNoteVis = true;
}
}
You've got some "magic thinking" going on. To wit:
You've set the visibility of the component based on a boolean variable
You expect the visibility of the component to magically change when the boolean variable changes -- but the component has no idea, no notification that this change has occurred, and so this is guaranteed to fail.
To get success, you will need to change the visibility of the component itself from within a listener. In other words, within the ActionListener, you will need to call .setVisible(true/false) on the component of interest.
btnAnzahl.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
uebernehmen();
lblNote.setVisible(bNoteVis);
}
});
Other unrelated issues:
doing this, contentPane.setLayout(null);, and this, lblNote.setBounds(10, 68, 87, 16); will lead to siginficant frustration over time as it leads to inflexible GUI's that might look sort-of OK on one platform, but not OK on others, and that are hard to extend and modify. Much better to learn and use layout managers
If your goal is to change multiple components, then best to swap components using a CardLayout. Have a look at the CardLayout Tutorial for the details on how to use this tool.
Also, rather than toggle a JLabel's visibility, I'd change its text so that it still takes up space on the GUI.
For example:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ItemEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Notenbilanz3 extends JPanel {
private static final String LABEL_TEXT = "Noten Anzahl";
private JLabel lblNote = new JLabel(LABEL_TEXT);
private JTextField txtField1 = new JTextField(10);
private JCheckBox checkBox = new JCheckBox("Check Box", true);
public Notenbilanz3() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.LINE_START;
gbc.gridwidth = 2;
gbc.insets = new Insets(3, 3, 3, 3);
add(lblNote, gbc);
gbc.gridx = 0;
gbc.gridy = 1;
gbc.gridwidth = 1;
add(txtField1, gbc);
gbc.gridx = 1;
add(checkBox, gbc);
checkBox.addItemListener(l -> {
String text = l.getStateChange() == ItemEvent.SELECTED ? LABEL_TEXT : " ";
lblNote.setText(text);
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(()-> {
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Notenbilanz3());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
I am trying to find a way to create a list of JPanels which have no Layout manager.
I found several examples on SO providing solutions to the 'scrollable JPanel list' problem. More specifically, I started from this thread and worked on it.
My current problem is that I am having issues when I remove the layout from the JPanels in the list.
They get added correctly but the scrollbar does not appear when needed, and the panels start overlapping.
Note: I know that layouts are heavily preferred but I find it more straightforward to work with pure X, Y coordinates and a mockup program. Please do not bash me for this...
Here is a small working example (taken and modified from this comment):
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.MatteBorder;
public class JScrollPanels {
private int i;
private JPanel listContainer;
private void initUI() {
final JFrame frame = new JFrame(JScrollPanels.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
listContainer = new JPanel();
listContainer.setLayout(new BoxLayout(listContainer, BoxLayout.Y_AXIS));
frame.add(new JScrollPane(listContainer), BorderLayout.CENTER);
JButton button = new JButton("Add");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final JPanel newPanel = new JPanel();
newPanel.setLayout(null);
newPanel.setSize(272, 110);
JLabel name = new JLabel("Name " + i++);
name.setBounds(18, 13, 84, 21);
newPanel.setBorder(new MatteBorder(0, 0, 1, 0, Color.GRAY));
JLabel date = new JLabel("12/11/2014");
date.setBounds(10, 44, 123, 21);
JButton btn= new JButton(">");
btn.addActionListener( new NameListener(name, date) );
btn.setBounds(205, 44, 48, 30);
newPanel.add(name);
newPanel.add(date);
newPanel.add(btn);
listContainer.add(newPanel);
listContainer.revalidate();
// Scroll down to last added panel
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
newPanel.scrollRectToVisible(newPanel.getBounds());
}
});
}
});
frame.add(button, BorderLayout.PAGE_END);
frame.setSize(272, 300);
frame.setVisible(true);
}
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new JScrollPanels().initUI();
}
});
}
public class NameListener implements ActionListener {
private JLabel name;
private JLabel date;
public NameListener(JLabel name, JLabel date) {
this.name = name;
this.date = date;
}
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked " + name.getText() + " on " + date.getText());
}
}
}
EDIT:
Fixed by using this:
final JPanel newPanel = new JPanel(){
#Override
public Dimension getPreferredSize() {
return new Dimension(272, 110);
}
};
Thanks, mKorbel!
Again, I still persist in my claim that in the long run, a layout manager will work best. For instance, your GUI could use something perhaps like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.*;
import javax.swing.border.Border;
#SuppressWarnings("serial")
public class JScrollPanels2 extends JPanel {
private static final int PREF_W = 300;
private static final int PREF_H = 300;
private int i;
private JPanel listContainer;
public JScrollPanels2() {
JPanel outerWrapperPanel = new JPanel(new BorderLayout());
listContainer = new JPanel();
listContainer.setLayout(new BoxLayout(listContainer, BoxLayout.Y_AXIS));
outerWrapperPanel.add(listContainer, BorderLayout.PAGE_START);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 5, 0));
buttonPanel.add(new JButton(new AddAction("Add")));
setLayout(new BorderLayout());
add(new JScrollPane(outerWrapperPanel), BorderLayout.CENTER);
add(buttonPanel, BorderLayout.PAGE_END);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class AddAction extends AbstractAction {
public AddAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
listContainer.add(new CellPanel(i));
listContainer.revalidate();
listContainer.repaint();
i++;
}
}
private class CellPanel extends JPanel {
private final int gap = 4;
private int index;
private String name;
private Date date;
private final String format = "MM/dd/yyyy";
private SimpleDateFormat sdf = new SimpleDateFormat(format);
public CellPanel(int i) {
this.index = i;
this.name = "Name " + index;
setLayout(new GridBagLayout());
date = new Date();
Border emptyBorder = BorderFactory.createEmptyBorder(gap, gap, gap, gap);
Border lineBorder = BorderFactory.createLineBorder(Color.black);
setBorder(BorderFactory.createCompoundBorder(lineBorder, emptyBorder));
add(new JLabel(name), createGbc(0, 0));
add(new JLabel(""), createGbc(1, 0));
add(new JLabel(sdf.format(date)), createGbc(0, 1));
add(new JButton(new MyBtnAction(">")), createGbc(1, 1));
}
private GridBagConstraints createGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = 1;
gbc.gridheight = 1;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
if (x % 2 == 0) {
gbc.anchor = GridBagConstraints.WEST;
} else {
gbc.anchor = GridBagConstraints.EAST;
}
return gbc;
}
private class MyBtnAction extends AbstractAction {
public MyBtnAction(String name) {
super(name);
// int mnemonic = (int) name.charAt(0);
// putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("Button pressed for " + name);
}
}
}
private static void createAndShowGui() {
JScrollPanels2 mainPanel = new JScrollPanels2();
JFrame frame = new JFrame("JScrollPanels2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
One of the beauties of use of layout managers is their flexibility. If you wanted to add new components to the inner JPanel, you can easily do so without having to manually recalculate every dang other component's position, if they need to be shifted. Instead, let the layout managers do the heavy lifting for you. Also, while your null-layout using GUI might look good on one platform it will usually look terrible on most other platforms or screen resolutions.
I currently have two frames, when you run the application the first JFrame that shows is a login, it has two input fields and a button. When the user logs in and is verified, I would like to close the frame and start up the second one.
So, the only thing I can think of doing is doing setVisible(false) for the login frame and setVisible(true) for the Main frame.
Is there a better way to do this, or is that the only way?
Personnally, I would start up your second JFrame immediately and replace your first frame with a modal JDialog which would be owned by the JFrame.
See also this answer to The Use of Multiple JFrames, Good/Bad Practice?
Here is a basic demo of what I suggest:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestLogin {
private JFrame frame;
private boolean authenticated;
private JTextField login;
private JPasswordField password;
protected void initUI() {
frame = new JFrame(TestLogin.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setVisible(true);
}
protected void showLoginDialog() {
authenticated = false;
final JDialog dialog = new JDialog(frame, "Please provide your credentials");
dialog.setModal(true);
JPanel panel = new JPanel(new GridBagLayout());
JPanel buttonPanel = new JPanel();
login = new JTextField(40);
password = new JPasswordField(20);
JLabel loginLabel = new JLabel("Login:");
JLabel passwordLabel = new JLabel("Password:");
JButton ok = new JButton("OK");
ok.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Here perform authentication and set authentication flag to appropriate value
authenticated = true;
if (authenticated) {
setUpFrame();
dialog.dispose();
}
}
});
JButton cancel = new JButton("Cancel");
cancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
dialog.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
if (!authenticated) {
System.exit(0);
}
}
});
dialog.getRootPane().setDefaultButton(ok);
buttonPanel.add(ok);
buttonPanel.add(cancel);
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.fill = GridBagConstraints.HORIZONTAL;
panel.add(loginLabel, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1.0;
panel.add(login, gbc);
gbc.gridwidth = 1;
gbc.weightx = 0;
panel.add(passwordLabel, gbc);
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.weightx = 1.0;
panel.add(password, gbc);
panel.add(buttonPanel, gbc);
dialog.add(panel);
dialog.pack();
dialog.setLocationRelativeTo(frame);
while (!authenticated) {
dialog.setVisible(true);
}
}
protected void setUpFrame() {
frame.add(new JLabel("Successfully authenticated"));
frame.revalidate();
frame.repaint();
}
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
TestLogin testLogin = new TestLogin();
testLogin.initUI();
testLogin.showLoginDialog();
}
});
}
}
There are several ways to do that.
E.g. you could reuse your 1st JFrame. Therefore remove the components you got on your 1st frame, add the ones for the 2nd and then repaint() the frame.
But I wouldn't consider that as good practice.
As Andrew Thompson suggested, you could also use a CardLayout to just initialize one JFrame, show your login-card and then switch to the fully initialized 2nd full-application card. This way you will get rid of those repaints.
You could also show your 2nd frame (your application first) and then use a modal JDialog to the let user log in.