Add Object to JPanel after button click - java

I have created a JScrollPane with a JPanel inside it and I want to add JPanel/JLabel/Other objects after pressing the button. For example after three button presses I want to get something like this:
I tried myJPane.add(testLabel) with testlabel.setBounds()but no result, I don't want to use GridLayout because of the unchangeable sizes. I would like it if the added objects had different sizes - adjusted to the text content.
What should I use for it and how?
Thanks in advance.
Best regards,
Tom.

Here is a JPanel inside a JScrollPane that adds JLabels to it when pressing the button:
public class Example extends JFrame {
public Example() {
JPanel boxPanel = new JPanel();
boxPanel.setLayout(new BoxLayout(boxPanel, BoxLayout.PAGE_AXIS));
JTextField textField = new JTextField(20);
JButton sendButton = new JButton("Send");
sendButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JLabel label = new JLabel(textField.getText());
label.setOpaque(true);
label.setBackground(Color.RED);
boxPanel.add(label);
boxPanel.add(Box.createRigidArea(new Dimension(0,5)));
textField.setText("");
boxPanel.revalidate();
// pack();
}
});
JPanel southPanel = new JPanel();
southPanel.add(textField);
southPanel.add(sendButton);
add(new JScrollPane(boxPanel));
add(southPanel, BorderLayout.PAGE_END);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
new Example();
}
}
The BoxLayout will stack the labels on top of each other.
Notes:
setOpaque(true) must be called on label for it to honor the background color.
Box.createRigidArea is used for creating gaps. Use it as you wish.
The call to revalidate() is imperative in order to display the new components immediately.
Calling pack() (on the JFrame) will resize it each time to fit all the new components. I just put it there for demonstration since the initial frame size is too small to display the initial components added.

I will use a BoxLayout, creating a vertical box, and after each button action, it will add a new JPanel to this box.
Example:
public class YourChat extends JPanel{
private JScrollPane sc;
private Box bv;
public YourChat(){
bv = Box.createVerticalBox();
sc = new JScrollPane(bv);
//your functions (panel creation, addition of listeners, etc)
add(sc);
}
//panel customized to have red backgroud
private class MyPanel extends JPanel(){
private JLabel label=new JLabel();
public MyPanel(String text){
setBackgroundColor(Color.red);
add(label);
}
}
//inside the action listener
public void actionPerformed(ActionEvent e) {
sc.add(new MyPanel(textField.getText()));
textField.setText("");
}
}
For extra information check on:
[https://docs.oracle.com/javase/tutorial/uiswing/layout/box.html]
See also the example
[http://www.java2s.com/Code/Java/Swing-JFC/VerticalandhorizontalBoxLayouts.htm]

Use BoxLayout if you want only add vertically, otherwise you can use FlowLayout for both directions.

Related

Java JPanel not appearing

I have a two JPanels, one that is displayed as a home/welcome page, the other displayed when a user clicks a button. The first panel does not disappear when the button is clicked, the second panel sort of displays its components at the same time so there is two panels worth of buttons/text fields etc both visible at the same time.
How do I fix this so panel1 disappears/panel2 appears?
(If I set the container visibility to false after button click, neither panel's components are displayed.)
public class mainApplication {
private static JFrame mainApp;
private static JPanel panel1;
private static JPanel panel2;
public mainApplication() {
JFrame.setDefaultLookAndFeelDecorated(true);
mainApp = new JFrame("Keystroke Authenticator Application");
mainApp.setSize(640, 480);
mainApp.setLocationRelativeTo(null);
mainApp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainApp.add(panel1());
mainApp.setVisible(true);
}
private JPanel panel1() {
panel1 = new JPanel();
panel1.setSize(640,480);
Container contain1 = mainApp.getContentPane();
//Buttons, text fields and labels are configured with groupLayout here
panel1.setVisible(true);
buttonNew.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent clickNew) {
panel2 = panel2();
panel1.setVisible(false);
//contain1.setVisible(false); - neither panel are displayed
}
}
);
return panel1;
}
private JPanel panel2() {
panel2 = new JPanel();
panel2.setSize(640,480);
Container contain2 = mainApp.getContentPane();
//Buttons, text fields and labels are configured with groupLayout here
panel2.setVisible(true);
mainApp.add(panel2);
}
}
I solved my own problem, it seemed to be the fact I was creating a container within each JPanel and using it with the GroupLayout. I removed the created container and replaced the container with the name of the JPanel:
//working code
GroupLayout layout = new GroupLayout(panel1);
panel1.setLayout(layout);
//instead of the original below
GroupLayout layout = new GroupLayout(container1);
container1.setLayout(layout);
I would recommend using a layout manager; this should solve most of your problems.
public mainApplication() {
//normal formatting stuff
mainApp.setLayout(new FlowLayout()); //This will make things appear/disappear
mainApp.setResizable(false) //This will stop your frame from changing sizes on you
}
private JPanel panel1(JFrame frame) {
//normal formatting stuff
frame.add(panel1); //this will make your panel appear in the frame
//more formatting stuff and button creation
buttonNew.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
panel2 = panel2();
frame.remove(panel1);
frame.add(panel2);
frame.pack(); //this swaps out your components so that the frame displays panel2 instead. Pack makes it repaint itself.
}
return panel1;
}
Basically, what you were doing was telling the frame to paint the first panel, but then you told it to paint over it with panel 2, and never said to stop painting panel 1. Using a layout manager handles all of this behind the scenes and helps for other stuff in the long run.

Java Swing JTabbedPane layout

I am new to Swing and cannot find a page that helps me understand JTabbedPane. I cannot find a way to control the layout of components of the tabbed panels. I can layout each of my panels correctly as separate GUIs but not in a tabbed pane like I need to do. I would like to use the BorderLayout not FlowLayout.
Also, you can see I'm trying to use colors to keep track of my panels and their components. I cannot set the background of the JTabbedPane. It is still the default grey. Can someone tell me why this is?
Thank you for any advice you can give.
What I have so far appears to follow a 'flow layout' despite any changes I've tried
(Methods have been removed or nearly removed to keep code shorter)
public class GUIFrame extends JFrame {
public GUIFrame(String title) {
JFrame frame = new JFrame(title);
Container c = frame.getContentPane();
buildGUI(c);
setFrameAttributes(frame);
}
private void buildGUI(Container c) {
c.setLayout(new BorderLayout());
c.setBackground(Color.BLACK);
JTabbedPane tabs = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);
tabs.setBackground(Color.YELLOW);
c.add("Center", tabs);
tabs.addTab("Specialty", new SpecialtyPanel());
tabs.addTab("Treatment", new TreatmentPanel());
tabs.addTab("Doctor", new DoctorPanel());
tabs.addTab("Patient", new PatientPanel());
}
private void setFrameAttributes(JFrame f) {
f.setSize(500, 500);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String args[]) {
MedicalSystemIO test = new MedicalSystemIO();
new GUIFrame("Tabbed Title");
}
public class SpecialtyPanel extends JPanel implements ActionListener {
JTextField jteInput = null;
DefaultListModel<String> model = new DefaultListModel<String>();
JList<String> list = new JList(model);
JScrollPane pane = new JScrollPane(list);
public SpecialtyPanel() {
JPanel panel = new JPanel();
panel.setBorder(BorderFactory.createLineBorder(Color.black));
buildGUI(panel);
}
private void buildGUI(JPanel panel) {
JPanel jpaInput = createInputPanel();
JPanel jpaProcess = createProcessPanel();
JPanel jpaOutput = createOutputPanel();
//panel.setLayout(new BorderLayout());
add("North", jpaInput);
add("Center", jpaProcess);
add("South", jpaOutput);
}
private JPanel createInputPanel() {
JPanel jpaInput = new JPanel();
jpaInput.setBackground(Color.RED);
return jpaInput;
}
private JPanel createProcessPanel() {
JPanel jpaProcess = new JPanel();
jpaProcess.setBackground(Color.BLUE);
return jpaProcess;
}
private JPanel createOutputPanel() {
JPanel jpaOutput = new JPanel();
jpaOutput.add(pane);
return jpaOutput;
}
The SpecialtyPanel is shown that way (flow layout) as you are putting the components on it in the wrong way:
No need for passing a new panel into the buildGUI method as you want to put them directly on the SpecialtyPanel which already is a JPanel,
you commented out the setting of the BorderLayout and
you used the wrong notation of passing the layout constraints in the add methods.
Your constructor and build method should look like this:
public SpecialtyPanel() {
buildGUI();
}
private void buildGUI() {
setBorder(BorderFactory.createLineBorder(Color.black));
JPanel jpaInput = createInputPanel();
JPanel jpaProcess = createProcessPanel();
JPanel jpaOutput = createOutputPanel();
setLayout(new BorderLayout());
add(jpaInput, BorderLayout.NORTH);
add(jpaProcess, BorderLayout.CENTER);
add(jpaOutput, BorderLayout.SOUTH);
}
To have the panel another color than gray you have to color the component that is put on the tabbed pane as it covers the whole space. Add the desired color to the buildGUI method, e.g.:
private void buildGUI(JPanel panel) {
// ...
setBackground(Color.YELLOW);
}
As a JPanel is opaque by default (that means not transparent), you need to set panels on top (except those which you colored explicitly) to be transparent. In case of SpecialtyPanel:
private JPanel createOutputPanel() {
JPanel jpaOutput = new JPanel();
jpaOutput.add(pane);
jpaOutput.setOpaque(false); // panel transparent
return jpaOutput;
}

Change text visibility of buttons according to the frame size

I have both texts and icons for my buttons. I want to hide texts, if user resize the frame and make one the buttons invisible. I found a workaround with scroll pane, but I want to know if there is a better solution. Thanks in advance.
My solution:
public class IconButtonTest extends JFrame {
private JScrollPane buttonScrollPane;
private JButton button1;
private JButton button2;
private JButton button3;
public IconButtonTest() {
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
ImageIcon icon = new ImageIcon();
button1 = new JButton("Button1", icon);
button2 = new JButton("Button2", icon);
button3 = new JButton("Button2", icon);
buttonPanel.add(button1);
buttonPanel.add(button2);
buttonPanel.add(button3);
buttonScrollPane = new JScrollPane(buttonPanel);
buttonScrollPane.setBorder(null);
add(buttonScrollPane, BorderLayout.NORTH);
addComponentListener(new ResizeListener());
setSize(300, 300);
setVisible(true);
}
public static void main(String[] args) {
new IconButtonTest();
}
private class ResizeListener extends ComponentAdapter {
#Override
public void componentResized(ComponentEvent e) {
button1.setText("Button1");
button2.setText("Button2");
button3.setText("Button2");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (buttonScrollPane.getHorizontalScrollBar().isVisible()) {
button1.setText("");
button2.setText("");
button3.setText("");
}
}
});
}
}
}
I added buttons to JPanel and add that panel to the frame with a scroll pane. In ResizeListener I am checking if horizontal scroll visible or not. If it is visible it means buttonPanel is overflowed the visible area.
I found a workaround with scroll pane, but I want to know if there is a better solution.
Don't know if it is better but there is no need for the scroll pane. Just add the listener to the panel, then you can check the preferred width against the actual width:
button1.setText("Button1");
button2.setText("Button2");
button3.setText("Button2");
JPanel panel = (JPanel)e.getComponent();
if (panel.getSize().width < panel.getPreferredSize().width)
{
button1.setText("");
button2.setText("");
button3.setText("");
}
I want to hide texts, if user resize the frame and make one the buttons invisible.
If you are just trying to make sure all the buttons are accessible then you might be able to:
Use the Wrap Layout. The button will wrap to a new line and the height of the panel will be increased.
Use the concept of the ScrollContainer. Buttons will be added to the start/end of the container as required to allow you to scroll through buttons that are not currently visible. See: Moving left right in a JPanel

Changing layout of a JPanel sent to JOptionPane with the pane still running

Trying to change the look of a JOptionPane while its open, depending on which radiobutton the user clicks. What am I doing wrong? It works perfect if I for example add a button and move a JLabel from side to side of the window.
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import static javax.swing.JOptionPane.*;
public class ChangePanel extends JFrame{
private JButton click = new JButton("CLICK ME!");
ChangePanel(){
add(click, BorderLayout.SOUTH);
click.addActionListener(new ButtonListen());
setVisible(true);
setSize(300,100);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
public class ButtonListen implements ActionListener{
public void actionPerformed(ActionEvent e){
PopUpPanel pop = new PopUpPanel();
showConfirmDialog(ChangePanel.this, pop, "Changeable", OK_CANCEL_OPTION);
}
}
//Send this as Parameter to the ConfirmDialog
public class PopUpPanel extends JPanel implements ActionListener{
JRadioButton jewelry = new JRadioButton("Jewelry");
JRadioButton shares = new JRadioButton("Shares");
JRadioButton machine = new JRadioButton("Machine");
PopUpPanel(){
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
ButtonGroup bg = new ButtonGroup();
JPanel north = new JPanel();
bg.add(jewelry);
jewelry.addActionListener(this);
bg.add(shares);
shares.addActionListener(this);
bg.add(machine);
machine.addActionListener(this);
north.add(jewelry);
north.add(shares);
north.add(machine);
add(north);
}
//Listener for RadioButtons
public void actionPerformed(ActionEvent e){
JTextField info1Txt = new JTextField(12);
JTextField info2Txt = new JTextField(12);
JTextField info3Txt = new JTextField(3);;
JRadioButton b = (JRadioButton)e.getSource();
if(b.getText().equals("Jewelry")){
//Dummy test text
System.out.println("Jewelry");
JPanel info1 = new JPanel();
info1.add(new JLabel("info1:"));
info1.add(info1Txt);
add(info1);
JPanel info2 = new JPanel();
info2.add(new JLabel("info2:"));
info2.add(info2Txt);
add(info2);
JPanel info3 = new JPanel();
info3.add(new JLabel("info3:"));
info3.add(info3Txt);
add(info3);
validate();
repaint();
}else if(b.getText().equals("Shares")){
//Dummy test text
System.out.println("Shares");
}else
//Dummy test text
System.out.println("Machine");
}
}
public static void main(String[] args){
new ChangePanel();
}
}
As you are working with BoxLayout, you should provide size hints to the PopUpPanel panel, which you haven't given.
When a BoxLayout lays out components from top to bottom, it tries to size each component at the component's preferred height. If the vertical space of the layout does not match the sum of the preferred heights, then BoxLayout tries to resize the components to fill the space. The components either grow or shrink to fill the space, with BoxLayout honoring the minimum and maximum sizes of each of the components.
check out the official tutorial page discussion: BoxLayout Feature
Call revalidate() and repaint() on the container after removing or adding components to it. So if you change the following lines:
validate();
repaint();
to:
revalidate();
repaint();
The content should appear. Though, it will not fit the original size of the JOptionPane. You can override PopUpPanel.getPreferredSize() to return desired size so that JOptionPane is packed properly, ie:
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
You can also use JDialog instead of JOptionPane.
Also, consider using CardLayout instead of swapping components manually. Check How to Use CardLayout for examples.
Why not just use setPreferredSize(new Dimension(300, 300)) in PopUpPanel constructor? Works fine for me. Good eye on revalidate and repaint.

Java Swing: How can I implement a login screen before showing a JFrame?

I'm trying to make a little game that will first show the player a simple login screen where they can enter their name (I will need it later to store their game state info), let them pick a difficulty level etc, and will only show the main game screen once the player has clicked the play button. I'd also like to allow the player to navigate to a (hopefully for them rather large) trophy collection, likewise in what will appear to them to be a new screen.
So far I have a main game window with a grid layout and a game in it that works (Yay for me!). Now I want to add the above functionality.
How do I go about doing this? I don't think I want to go the multiple JFrame route as I only want one icon visible in the taskbar at a time (or would setting their visibility to false effect the icon too?) Do I instead make and destroy layouts or panels or something like that?
What are my options? How can I control what content is being displayed? Especially given my newbie skills?
A simple modal dialog such as a JDialog should work well here. The main GUI which will likely be a JFrame can be invisible when the dialog is called, and then set to visible (assuming that the log-on was successful) once the dialog completes. If the dialog is modal, you'll know exactly when the user has closed the dialog as the code will continue right after the line where you call setVisible(true) on the dialog. Note that the GUI held by a JDialog can be every bit as complex and rich as that held by a JFrame.
Another option is to use one GUI/JFrame but swap views (JPanels) in the main GUI via a CardLayout. This could work quite well and is easy to implement. Check out the CardLayout tutorial for more.
Oh, and welcome to stackoverflow.com!
Here is an example of a Login Dialog as #HovercraftFullOfEels suggested.
Username: stackoverflow Password: stackoverflow
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
public class TestFrame extends JFrame {
private PassWordDialog passDialog;
public TestFrame() {
passDialog = new PassWordDialog(this, true);
passDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new TestFrame();
frame.getContentPane().setBackground(Color.BLACK);
frame.setTitle("Logged In");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
class PassWordDialog extends JDialog {
private final JLabel jlblUsername = new JLabel("Username");
private final JLabel jlblPassword = new JLabel("Password");
private final JTextField jtfUsername = new JTextField(15);
private final JPasswordField jpfPassword = new JPasswordField();
private final JButton jbtOk = new JButton("Login");
private final JButton jbtCancel = new JButton("Cancel");
private final JLabel jlblStatus = new JLabel(" ");
public PassWordDialog() {
this(null, true);
}
public PassWordDialog(final JFrame parent, boolean modal) {
super(parent, modal);
JPanel p3 = new JPanel(new GridLayout(2, 1));
p3.add(jlblUsername);
p3.add(jlblPassword);
JPanel p4 = new JPanel(new GridLayout(2, 1));
p4.add(jtfUsername);
p4.add(jpfPassword);
JPanel p1 = new JPanel();
p1.add(p3);
p1.add(p4);
JPanel p2 = new JPanel();
p2.add(jbtOk);
p2.add(jbtCancel);
JPanel p5 = new JPanel(new BorderLayout());
p5.add(p2, BorderLayout.CENTER);
p5.add(jlblStatus, BorderLayout.NORTH);
jlblStatus.setForeground(Color.RED);
jlblStatus.setHorizontalAlignment(SwingConstants.CENTER);
setLayout(new BorderLayout());
add(p1, BorderLayout.CENTER);
add(p5, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jbtOk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Arrays.equals("stackoverflow".toCharArray(), jpfPassword.getPassword())
&& "stackoverflow".equals(jtfUsername.getText())) {
parent.setVisible(true);
setVisible(false);
} else {
jlblStatus.setText("Invalid username or password");
}
}
});
jbtCancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
parent.dispose();
System.exit(0);
}
});
}
}
I suggest you insert the following code:
JFrame f = new JFrame();
JTextField text = new JTextField(15); //the 15 sets the size of the text field
JPanel p = new JPanel();
JButton b = new JButton("Login");
f.add(p); //so you can add more stuff to the JFrame
f.setSize(250,150);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Insert that when you want to add the stuff in. Next we will add all the stuff to the JPanel:
p.add(text);
p.add(b);
Now we add the ActionListeners to make the JButtons to work:
b.addActionListener(this);
public void actionPerforemed(ActionEvent e)
{
//Get the text of the JTextField
String TEXT = text.getText();
}
Don't forget to import the following if you haven't already:
import java.awt.event*;
import java.awt.*; //Just in case we need it
import java.x.swing.*;
I hope everything i said makes sense, because sometimes i don't (especially when I'm talking coding/Java) All the importing (if you didn't know) goes at the top of your code.
Instead of adding the game directly to JFrame, you can add your content to JPanel (let's call it GamePanel) and add this panel to the frame. Do the same thing for login screen: add all content to JPanel (LoginPanel) and add it to frame. When your game will start, you should do the following:
Add LoginPanel to frame
Get user input and load it's details
Add GamePanel and destroy LoginPanel (since it will be quite fast to re-create new one, so you don't need to keep it memory).

Categories

Resources