Using a JPanel with a null layout - java

So I have a class called CalendarPanel that extends JPanel. It uses a null layout. How would I use CalendarPanel as a regular component? When I put it in another JPanel and then add it to a window, it disappears. It is only visible when I add it directly to a window.
EDIT:
And yes, I realize using a JPanel with a null layout is bad practice. CalendarPanel is actually someone else's code, and I'm trying to use it for my purposes without having to refactor it.

It is only visible when I add it directly to a window.
That is because a window uses a BorderLayout by default and will automatically resize the panel to fit in the window.
When I put it in another JPanel and then add it to a window, it disappears.
The is because a JPanel uses a FlowLayout by default and a flow layout respects the preferred size of the components added to it. Since you are using a null layout your panel doesn't have a preferred size so nothing gets painted.
That is why you should NOT use null layout. Instead use layout managers because they do all this extra work for you.

NOTE: it is a very bad idea in general to use a null layout. Use a LayoutManager instead.
If you insist on using a null layout, you're going to have to position the JPanel manually as mentioned in the documentation. Here's an example.
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Test extends JFrame {
static int defaultX = 10;
static int defaultY = 10;
static int defaultW = 150;
static int defaultH = 50;
public Test() {
super("Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// here is the outer JPanel
final JPanel outer = new JPanel(new BorderLayout());
JPanel inner = new JPanel(new BorderLayout());
// here is the main component we want to see
// when the outer panel is added to the null layout
JButton mainComponent = new JButton("Test");
inner.add("Center", mainComponent);
outer.add("Center", inner);
JPanel c = (JPanel)getContentPane();
// This panel has a null layout!
final JPanel nullLayoutPanel = new JPanel();
nullLayoutPanel.setLayout(null);
c.add("Center", nullLayoutPanel);
// set the bounds of the outer panel manually
// when using the null layout!
nullLayoutPanel.add(outer);
outer.setBounds(defaultX, defaultY, defaultW, defaultH);
JPanel controlPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
final JTextField x = new JTextField(""+defaultX, 3);
final JTextField y = new JTextField(""+defaultY, 3);
final JTextField w = new JTextField(""+defaultW, 3);
final JTextField h = new JTextField(""+defaultH, 3);
JButton b = new JButton("Resize");
b.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
outer.setBounds(
Integer.parseInt(x.getText()),
Integer.parseInt(y.getText()),
Integer.parseInt(w.getText()),
Integer.parseInt(h.getText())
);
outer.revalidate();
} catch(Exception ex) {}
}
}
);
controlPanel.add(x);
controlPanel.add(y);
controlPanel.add(w);
controlPanel.add(h);
controlPanel.add(b);
c.add("South", controlPanel);
}
public static void main(String[] argv) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test p = new Test();
p.setSize(300, 200);
p.setVisible(true);
}
});
}
}

Related

Setting JPanel background while using BoxLayout

I am developing a simple application, and am currently working on the gui design using Swing. In my program I have a JPanel which I would like to have a background color black like so:
JPanel playerPanel = new JPanel();
playerPanel.setOpaque(true);
playerPanel.setBackground(Color.BLACK);
This code works fine. However, the problem is when I assign a Layout Manager to the panel:
JPanel playerPanel = new JPanel();
playerPanel.setOpaque(true);
playerPanel.setBackground(Color.BLACK);
playerPanel.setLayout(new BoxLayout(playerPanel, BoxLayout.PAGE_AXIS));
For some reason, this makes the black color of the panel go away. This happens no matter where I place the .setLayout(...) command, before or after the .setBackground(...) and .setOpaque(true).
Why is this, and how do I work around this? How do I keep a black JPanel that uses a BoxLayout manager?
Verify that your panel's content is not obscuring the altered background. Resize the example below, which I've artificially enlarged, to see the effect.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Random;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* #see https://stackoverflow.com/a/57785802/230513
*/
public class BoxTest {
public static final Random random = new Random();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new BoxTest().create();
}
});
}
void create() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setBackground(Color.BLACK);
panel.add(Box.createVerticalGlue());
for (int i = 0; i < 4; i++) {
panel.add(new VariablePanel());
panel.add(Box.createVerticalGlue());
}
JFrame f = new JFrame("BoxTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setSize(f.getWidth(), f.getHeight() + 64);
}
}
/**
* A VariablePanel has a label showing its current size,
* as well as a variable number of text items.
*/
class VariablePanel extends JPanel {
private static final String text =
"Sed ut perspiciatis unde omnis iste natus error sit.";
private final JLabel sizeLabel = new JLabel("Size:");
public VariablePanel() {
this.setLayout(new GridLayout(0, 1));
this.add(sizeLabel);
int count = BoxTest.random.nextInt(5) + 1;
for (int i = 0; i < count; i++) {
this.add(new JLabel(text));
}
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
int w = e.getComponent().getWidth();
int h = e.getComponent().getHeight();
sizeLabel.setText("Size: " + w + "\u00d7" + h);
}
});
}
}
Swing components (except JLabel) are opaque by default. This means:
you don't need playerPanel.setOpaque(true)
most components you add to the panel will be opaque and cover the background of your playerPanel.
Also, the BoxLayout respects the maximum size of any component you add to the panel. So if you add a component:
like a JButton which has a defined maximum size, you will see the button on top of the playerPanel and the background will surround the button.
like a JPanel, which does not have a defined maximum size, the panel will be resized to fill the entire area of the playerPanel and you won't see the background of the playerPanel.
If you want to see the background of the playerPanel show through a component added to the playerPanel, then you need to use setOpaque(false) on the component. For example:
JPanel child = new JPanel();
child.setOpaque( false );
playerPanel.add( child );

I'm attempting to create a small GUI application, but the contents of the JFrame are not showing on screen. How can I fix my code?

As of late I've been developing a (very) small GUI application in Java. I'm extremely new to Swing and Java in general, but up until now I have been able to get everything to work the way I want it to. However, after cleaning up my code, when I run the program nothing but the border of the window appears. What am I doing wrong and how can I fix my code? Thanks ahead of time!
For the sake of saving space I've made Pastebin links to all of my classes (besides Main).
Main Class
package me.n3rdfall.ezserver.main;
public class Main {
public static GUI g = new GUI();
public static void main(String[] args) {
g.showWindow(800, 500);
}
}
GUI Class
http://pastebin.com/gDMipdp1
ButtonListener Class
http://pastebin.com/4XXm70AD
EDIT: It appears that calling removeAll() directly on 'frame' actually removed essential things other than what I had added. By calling removeAll() on getContentPane(), the issue was resolved.
Quick hack: Remove the removeAll() functions.
public void homePage() {
// frame.removeAll();
// mainpanel.removeAll();
// topbar.removeAll();
I'm not sure what you're trying to achieve, but that will at least show some items. If I were you I would rebuild this GUI by extending JFrame. It will make your code a little easier to read.
I also think what you are trying to achieve with the buttons is to switch layouts, you can do this in an easier way by using CardLayout
Example (has nothing to do with your code, but to demonstrate):
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JFrame implements ActionListener {
private JButton leftButton;
private JButton rightButton;
private CardLayout cardLayout = new CardLayout();
JPanel cards = new JPanel(cardLayout);
final static String LEFTPANEL = "LEFTPANEL";
final static String RIGHTPANEL = "RIGHTPANEL";
JPanel card1;
JPanel card2;
public Example() {
JPanel topPanel = new JPanel();
addButtons(topPanel);
add(topPanel, BorderLayout.NORTH);
add(cards, BorderLayout.CENTER);
//Initiates the card panels
initCards();
setTitle("My Window");
setSize(300, 300);
setLocationRelativeTo(null);
setVisible(true);
}
private void initCards() {
card1 = new JPanel();
card2 = new JPanel();
card1.setBackground(Color.black);
card2.setBackground(Color.red);
cards.add(card1, LEFTPANEL);
cards.add(card2, RIGHTPANEL);
}
private void addButtons(Container con) {
leftButton = new JButton("Left Button");
leftButton.addActionListener(this);
rightButton = new JButton("Right Button");
rightButton.addActionListener(this);
con.add(leftButton, BorderLayout.WEST);
con.add(rightButton, BorderLayout.EAST);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(leftButton)) {
//Change cardlayout
cardLayout.show(cards, LEFTPANEL);
} else if(e.getSource().equals(rightButton)) {
//Change cardlayout
cardLayout.show(cards, RIGHTPANEL);
}
}
public static void main(String[] args) {
new Example();
}
}

JCheckBox not showing (text appears, but without check box)

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class SideNotes {
public static JPanel panel = new JPanel();
private List<String> notes = new ArrayList<String>();
private static JButton add = new JButton("Add note");
public SideNotes() {
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(add);
loadNotes();
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addNote();
}
});
}
public void addNote() {
String note = JOptionPane.showInputDialog("Enter note: ", null);
notes.add(note);
JLabel label = new JLabel(note);
panel.add(label);
panel.revalidate();
panel.repaint();
}
private void loadNotes() {
for (int i = 0; i < notes.size(); i++) {
JCheckBox jcb = new JCheckBox(notes.get(i), false);
panel.add(jcb);
panel.revalidate();
panel.repaint();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(200, 400);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(add);
frame.add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
new SideNotes();
}
}
Why isn't my JCheckBox showing up? The text shows up but not the actual box. What's the deal?
I have edited my post to contain all of my code in case that helps solve the issue.
needmoretextneedmoretextneedmoretextneedmoretextneedmoretextneedmoretextneedmoretext
Possible reasons:
panel has not been added to GUI
panel has been added but for some reason is not visible.
panel is too small to show the child component. This can happen for instance if you set a component's size or preferredSize or if you place it in a FlowLayout-using container without thought.
panel uses null layout.
panel's layout manager is not one that easily accepts a new component -- think GroupLayout for this one.
There are other unspecified layout manager problems going on. Do you call pack() on your GUI? Do you use null layout or absolute positioning anywhere? Do you need to put panel in a JScrollPane?
Consider creating and posting an sscce for better help.
Edit
Your posted code doesn't ever add any JCheckBoxes to the JPanel, just JLabels. To prove this is so, click on the labels and you'll see that they don't respond to clicks.
Your code grossly over-uses static fields. Get rid of all static modifiers on all variables. They should all be instance variables. The only static anything in your code above should be the main method, and that's it. If this causes errors, then fix the errors, but not by making fields static.
Give your SideNotes class a method, getPanel() that returns the panel field.
Create a SideNotes instance in the beginning of your main method. Then call the above method on the instance to get the JPanel for the JFrame. i.e., frame.add(sideNotes.getPanel());.
Don't add JLabels to your GUI (I've no idea why you're doing this). Add JCheckBoxes in the actionPerformed method.
Every time you press the button, a new Note (JLabel) is added to the panel. But you never call loadNotes() after adding a new Note. So the JLabel is added but not its respective JCheckBox as intended.
Besides of this I'd suggest you make this change:
public void addNote() {
String note = JOptionPane.showInputDialog("Enter note: ", null);
if(notes != null) {
notes.add(note);
JLabel label = new JLabel(note);
panel.add(label);
panel.add(new JCheckBox(note, false));
panel.revalidate();
panel.repaint();
}
}
So you don't need to call loadNotes() and update the GUI just once.

MigLayout row-height and changing font-size

I have a problem using MigLayout in combination with dynamically changing the font-size of the components which are shown in the MigLayout cells.
In detail: I added a JCheckBox via MigLayout to a JPanel. The font-size of the JCheckBox is default (12pt?) and the row which contains the JCheckBox has a preferred height of 17lp. That all works fine.
(View here: http://www.bilderload.com/bild/227327/migproblemcellheight1UQXP2.png)
Now I change the font-size to e.g. 20pt and start the program again. Now the text of the JCheckBox is cut because the row has also the height of 17lp.
(View here: http://www.bilderload.com/bild/227328/migproblemcellheight2DDPGJ.png)
If I for example let the row definition empty ("[]") the text shows correctly with both font sizes - the normal and the large one. But in this case the row will sadly never reach a minimum of 17lp. (It will always have a minimum of 23lp or so)
How can I change the MigLayout definition to get a minimum row-height of 17lp and to let the cell grow correctly with the components font-size/text etc.?
Or maybe this is a L&F problem?
Thanks & best regards,
Philipp
Here is my sample code (working example):
import java.awt.Font;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class TestMigLayoutFontSize extends JFrame {
public TestMigLayoutFontSize() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 400);
setContentPane(getTestPanel());
setVisible(true);
}
private JPanel getTestPanel() {
JCheckBox testBox = new JCheckBox("Program argument");
Font normalFont = testBox.getFont();
Font largeFont = new Font(testBox.getFont().getName(), testBox.getFont().getStyle(), 20);
// testBox.setFont(normalFont);
testBox.setFont(largeFont);
JPanel tempPanel = new JPanel(new MigLayout("debug", "0lp![grow,fill]0lp!", "[17lp:17lp:n]"));
tempPanel.add(testBox);
JPanel testPanel = new JPanel(new MigLayout("", "[grow,fill]", "[grow,fill]"));
testPanel.add(tempPanel);
return testPanel;
}
public static void main(String[] args) {
new TestMigLayoutFontSize();
}
}
You may reduce the space around your checkbox by reducing the border size, e.g. put
testBox.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
directly after the assignment of testBox. You may then leave the row definition empty and still get a reasonable height for your panel.
The following works for me. I think the problem is , that you specify the preferred size.
Regards
Roger
package de.test;
import java.awt.Font;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
public class MigTest extends JFrame {
public MigTest() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(600, 400);
setContentPane(getTestPanel());
setVisible(true);
}
private JPanel getTestPanel() {
JCheckBox testBox = new JCheckBox("Program argument");
Font normalFont = testBox.getFont();
Font largeFont = new Font(testBox.getFont().getName(), testBox.getFont().getStyle(), 90);
// testBox.setFont(normalFont);
testBox.setFont(largeFont);
JPanel tempPanel = new JPanel(new MigLayout("debug", "0lp![grow,fill]0lp!", "[80:n:]"));
tempPanel.add(testBox);
JPanel testPanel = new JPanel(new MigLayout("", "[grow,fill]", "[grow,fill]"));
testPanel.add(tempPanel);
return testPanel;
}
public static void main(String[] args) {
new MigTest();
}
}

Change Content Pane in JFrame

I've seen a few examples of this, and I've tried with the following code. I'm trying to change the content pane when portraitB is selected and then run the other class file.
//imported java libraries
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.UIManager;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.Dimension;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class birthdayCardGUI implements ActionListener
{
//Welcome Screen
JPanel welcomeP, welcomeImageP, portraitP, landscapeP, backP;
JLabel welcomeImageL;
JButton portraitB, landscapeB, backB;
//Portrait Screen
JTabbedPane tabbedPane;
JPanel portraitOne;
JLabel test;
public JFrame frame;
//Colours
int colourOne = Integer.parseInt( "c1c7f9", 16);
Color Blue = new Color( colourOne );
public birthdayCardGUI() throws Exception
{
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
JFrame frame = new JFrame("birthday Card Maker!");
frame.setExtendedState(frame.NORMAL);
frame.getContentPane().add(create_Content_Pane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 700); //Size of main window
frame.setVisible(true);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
//sets frame location
int fw = frame.getSize().width;
int fh = frame.getSize().height;
int fx = (dim.width-fw)/2;
int fy = (dim.height-fh)/2;
//moves the frame
frame.setLocation(fx, fy);
}
public JPanel create_Content_Pane() throws Exception
{
JPanel TotalGUI = new JPanel();
//TotalGUI.setBackground(Blue);
TotalGUI.setLayout(null);
//Welcome Panel
welcomeP = new JPanel();
Border etched = BorderFactory.createBevelBorder(10);
Border titled = BorderFactory.createTitledBorder(etched, "Welcome");
welcomeP.setBorder(titled);
welcomeP.setLayout(null);
welcomeP.setLocation(0,0);
welcomeP.setSize(485, 680);
welcomeP.setBackground(Blue);
TotalGUI.add(welcomeP);
welcomeImageP = new JPanel();
welcomeImageP.setLayout(null);
welcomeImageP.setLocation(88,20);
welcomeImageP.setSize(324, 225);
welcomeP.add(welcomeImageP);
String welcomeG = "Welcome Image.png";
ImageIcon WelcomeG = new ImageIcon(welcomeG);
welcomeImageL = new JLabel( WelcomeG, JLabel.CENTER);
welcomeImageL.setSize(324, 225);
welcomeImageL.setLocation(0,0);
welcomeImageP.add(welcomeImageL);
portraitB = new JButton("Portrait");
portraitB.setSize(100, 30);
portraitB.setLocation(200, 295);
portraitB.addActionListener(this);
welcomeP.add(portraitB);
landscapeB = new JButton("Landscape");
landscapeB.setSize(100, 30);
landscapeB.setLocation(200, 335);
landscapeB.addActionListener(this);
welcomeP.add(landscapeB);
TotalGUI.setOpaque(true);
return TotalGUI;
}
public void create_Portrait_Pane()
{
PortraitGUI portrait = new PortraitGUI();
getContentPane().removeAll();
getContentPane().add(portrait.PortraitGUI);
getContentPane().doLayout();
update(getGraphics());
}
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == portraitB)
{
create_Portrait_Pane();
}
}
//MAIN METHOD
public static void main(String[] args) throws Exception
{
birthdayCardGUI CGUI = new birthdayCardGUI();
}
}
And this is the PortraitGUI file that creates the new content pane.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class PortraitGUI extends JPanel implements ActionListener
{
JPanel frontPageP;
JLabel frontPageL;
//Color White;
int intValue = Integer.parseInt( "FFFFFF", 16);
Color White = new Color(intValue);
public JPanel PortraitGUI() throws Exception
{
JPanel PortraitGUI = new JPanel();
PortraitGUI.setLayout(null);
frontPageP = new JPanel();
frontPageP.setBackground(White);
frontPageP.setSize(350, 400);
frontPageP.setLocation(20, 70);
PortraitGUI.add(frontPageP);
frontPageL = new JLabel("Front Page");
frontPageL.setLocation(10, 5);
frontPageL.setSize(70, 30);
frontPageL.setHorizontalAlignment(JTextField.CENTER);
PortraitGUI.add(frontPageL);
PortraitGUI.setOpaque(true);
return PortraitGUI;
}
public void actionPerformed(ActionEvent e)
{
}
}
There are several problems in your code, but one of your main problems comes from your shadowing of the JFrame class field in your constructor leaving the class field null and non-usable. To fix this, don't redeclare this variable. Thus change this:
JFrame frame = new JFrame("birthday Card Maker!");
to this:
// this uses the JFrame variable declared in the class.
frame = new JFrame("birthday Card Maker!");
Then you can use this variable later on in a method where you swap contents of the contentPane:
public void create_Portrait_Pane() throws Exception {
PortraitGUI portrait = new PortraitGUI();
frame.getContentPane().removeAll(); // now you can use the frame variable
frame.getContentPane().add(portrait);
//!! getContentPane().doLayout();
//!! update(getGraphics()); // WTF?
((JPanel)frame.getContentPane()).revalidate();
frame.repaint();
}
Having said this, myself, I'd probably use a JPanel that uses CardLayout as my Container for swapping views (other JPanels).
Also, you appear to have a "pseudo" constructor here:
public JPanel PortraitGUI() throws Exception {
Why not just use a real constructor?:
public PortraitGUI() throws Exception {
setLayout(null);
frontPageP = new JPanel();
frontPageP.setBackground(White);
frontPageP.setSize(350, 400);
frontPageP.setLocation(20, 70);
add(frontPageP);
frontPageL = new JLabel("Front Page");
frontPageL.setLocation(10, 5);
frontPageL.setSize(70, 30);
frontPageL.setHorizontalAlignment(JTextField.CENTER);
add(frontPageL);
setOpaque(true);
}
Also for good programming practice you'll want to avoid using a plain-vanilla Exception class and instead throw or catch specific exceptions.
Next, you're going to want to get out of the habit of using absolute size and position and instead using the layout managers for doing what they do best.
Edit:
replies to your recent comments
The reason I used public "JPanel" PortraitGUI is because it was throwing the error or return type required,
This was fixing the wrong thing though as the better solution was to make it a true constructor, not to give it a return type.
and I coded the class the same as create_Content_Pane(); with returning a Panel. Also the return type required error came up a few times.
Again, it's important to know why the error is occurring rather than fixing the wrong thing.
The update(getGraphics()); was also a method I tried from code examples I found with the same problem.
Surely that didn't come from a Swing example but more likely an older AWT example. You don't do that sort of coding with Swing.

Categories