Java JPanel not appearing - java

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.

Related

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

Add Object to JPanel after button click

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.

JPanel doesn't update when adding Component in another class

I'm fairly new to Java Swing and I'm running into a few problems.
As a side question, when making a fairly large Java Swing Application, what is the best way to split up code?
In my case I want to have an application that has a layout just as Microsoft Word where there is a JToolBar filled with buttons and a main JPanel where changes are made based on the buttons pressed in the Tool Bar.
So as shown in the code below, I have a JFrame and I call the MainPanel class in order to create a panel and add a ToolBar with a button. When the button is pressed it adds a button to the panel. The problem comes when you click the button nothing shows up until you resize the window(in my case I simply manually drag the screen to make it larger).
public class Main {
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("MathMaker");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create the menu bar. Make it have a green background.
//MainToolBar mainTB = new MainToolBar();
MainPanel mainPanel = new MainPanel();
frame.getContentPane().add(mainPanel.getGUI(), BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
public class MainPanel implements ActionListener{
JPanel mPanel;
JToolBar mToolBar;
JButton addQuestion;
public MainPanel() {
mPanel = new JPanel(new BorderLayout());
mToolBar = new JToolBar();
addQuestion = new JButton("test");
addQuestion.addActionListener(this);
mPanel.setLayout(new BorderLayout());
mPanel.setBackground(new Color(248, 213, 131));
mPanel.setPreferredSize(new Dimension(200, 180));
mToolBar.add(addQuestion);
mPanel.add(mToolBar, BorderLayout.PAGE_START);
}
public JComponent getGUI()
{
return mPanel;
}
#Override
public void actionPerformed(ActionEvent e) {
JButton temp = new JButton("temp");
mPanel.add(temp);
}
}
You should revalidate your panel
#Override
public void actionPerformed(ActionEvent e) {
JButton temp = new JButton("temp");
mPanel.add(temp);
mPanel.revalidate();
mPanel.repaint();
}
I believe you need to call revalidate() and repaint() to see the changes, here is a similar question here
The problem here is the panel is not repainted automatically.. When you resize the panel Java repaints the panel on the screen. Try repainting the panel everytime any button to modify the panel is clicked..
Just call the validate() and repaint() method with the panel

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.

Categories

Resources