So I have a gui where the layout is set to Null, and I put JLabels ontop of JButtons since the JButtons have icons and adding text to the button makes the button look distorted, so instead I am using JLabels ontop of the JButtons. Every time the mouse goes over the JButton when I test it, the JLabel disappears. How can I fix that so JLabels always appear above JButtons.
Edit: it distorts the button so the icon is taking up most the space and the button label is cut off by the opposite edge of the button.
If you're using a JFrame, as I assume you must be, you could add the labels to a JLayered pane that sits on top of the content pane.
There is almost no cases when you will need to use null layout. You just need to do a little practice with the LayoutManagers
You can do the thing you wish to do with a JLayeredPane. Like this:
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.add(jLabelOnJButton());
frame.setSize(300, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private static JComponent jLabelOnJButton(){
JLayeredPane layers = new JLayeredPane();
JLabel label = new JLabel("label");
JButton button = new JButton("button");
label.setBounds(40, 20, 100, 50);
button.setBounds(20, 20, 150, 75);
layers.add(label, new Integer(2));
layers.add(button, new Integer(1));
return layers;
}
}
This is not a good solution I think. Only do it if you have no better solution.
Related
The below code creates a frame with a JTabbedPane in the frame's contentPane and a "Help" button added directly to the frame's layered pane - at a higher index than the default, so it should always be painted in front of the tabbed pane. But as you can see if you run it, as soon as you click on one of the tabs (or, on Mac, as soon as you hover over a tab), the "Help" button gets painted over - i.e. disappears. You have to resize the frame to make the "Help" button re-appear.
Is this a Java bug or am I doing something wrong? If the latter, what needs to be done to fix the problem? I've consulted both https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html and https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html .
Please pardon the poor positioning of the "Help" button. I was just trying to write a quick test to include here. The idea is the to overlay a "Help" icon button in the unused space of the JTabbedPane.
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class TabTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
JTabbedPane tp = new JTabbedPane();
tp.addTab("hello", new JPanel());
tp.addTab("there", new JPanel());
frame.getContentPane().add(tp, BorderLayout.CENTER);
JLayeredPane layeredPane = frame.getRootPane().getLayeredPane();
JButton helpButton = new JButton("Help");
helpButton.setBounds(800, 5, 50, 20);
layeredPane.add(helpButton, 400);
frame.setSize(new Dimension(900, 800));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
This is a common misunderstanding with JLayeredPane.
If you have a look at the JavaDocs for Container, you will note that there are (at least) two add methods
Container#add(Component, int)
Container#add(Component, Object)
The question you need to answer is, which one are you actually calling?
Both the JavaDocs for JLayeredPane and How to use JLayeredPane demonstrate that you should be calling the second one.
While the first can affect the z-ordering of the components, it's no guarantee that the component positions won't be changed.
Instead of:
layeredPane.add(helpButton, 400);
you should be using:
layeredPane.add(helpButton, new Integer(400));
which will pass the value as a constraint to the container, instead of the desired position within the container hierarchy - yeah, suitable I know
An alternative solution might be to use the glassPane instead, for example...
JFrame frame = new JFrame();
JTabbedPane tp = new JTabbedPane();
tp.addTab("hello", new JPanel());
tp.addTab("there", new JPanel());
frame.getContentPane().add(tp, BorderLayout.CENTER);
// Null layout used here for demonstration purposes only
JPanel glassPane = new JPanel(null);
glassPane.setOpaque(false);
frame.getRootPane().setGlassPane(glassPane);
// This is important, as setGlassPane makes it invisible
glassPane.setVisible(true);
JButton helpButton = new JButton("Help");
helpButton.setBounds(800, 5, 50, 20);
glassPane.add(helpButton);
frame.setSize(new Dimension(900, 800));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Im trying to create a simple welcome screen where the user can choose with how many cards he wants to play a memory game. On the top of the screen I want a text ( I created a JLabel for this). Below that I want a dropdown menu and to the right of this dropdown a button. The code I have so far doenst display anything when I run it (besides a empty JFrame). What am I doing wrong?
The code:
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) {
JFrame frame = new JFrame("Memory game");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setLocation(430, 100);
frame.setLayout(null);
JPanel panel = new JPanel();
frame.add(panel);
JLabel lbl = new JLabel("How many cards u want to play with?");
lbl.setVisible(true);
lbl.setLocation(150,150);
panel.add(lbl);
String[] choices = { "8","12", "16","20","24","28","32"};
final JComboBox<String> cb = new JComboBox<String>(choices);
cb.setVisible(true);
cb.setLocation(200,150);
panel.add(cb);
JButton btn = new JButton("Start game");
btn.setLocation(175,200);
panel.add(btn);
}
}
You would need to set the size of your panel. One way to do it:
JPanel panel = new JPanel();
panel.setSize(frame.getSize());
frame.add(panel);
But using
frame.setLayout(null);
Will give you a lot of headache if you dont know what you are doing (if you had a layout, you wouldnt have had this problem). You should always use a layout. Have a look at the official
Visual Guide to Layout Managers.
Though there are more you can download from the web.
Also another advice: If you are just starting to learn how to build Desktop Applications, maybe you should skip swing and get to JavaFX directly. This will save you even more headache.
I have an java assignment in which I need to have the background color of a GUI change depending on user selected radio buttons listing different colors.
My program has a JFrame to hold everything, then 3 JPanels (1 Instruction area, 1 Radio Button grid, 1 result Textfield) within that frame.
My action listener is currently setting the background color with this statement: getContentPane().setBackground(Color.decode(colorMap.get(btn.getName())));
The background for the JFrame and two of the three panels successfully changes to the correct color, but the panel holding the JRadioButtons will not change at all!
I have tried changing the opaque setting, I have tried setting the panel's background color to (0,0,0,0) but so far none of that is working for me. Does anyone have a suggestion of what I might try or read up on next?
I don't have enough reputation to post a picture but if seeing what I'm talking about helps, let me know and I can email you a screenshot.
Thanks!
You must additionally set all JRadioButtons.setOpaque(false).
Example with one JRadioButton opaque and one non-opaque:
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
public class XFrame
extends JFrame
{
public XFrame(String title)
{
super(title);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
JRadioButton b1 = new JRadioButton("Non opaque button");
// button must not be opaque
b1.setOpaque(false);
// this button is opaque and does not use the background color of the frame
JRadioButton b2 = new JRadioButton("Opaque button");
JPanel p1 = new JPanel();
// panel must be non opaque also
p1.setOpaque(false);
p1.setLayout(new BoxLayout(p1, BoxLayout.Y_AXIS));
p1.add(b1);
p1.add(b2);
add(p1, BorderLayout.CENTER);
getContentPane().setBackground(Color.red);
setSize(200, 200);
}
public static void main(String[] args)
{
XFrame frame = new XFrame("Test");
frame.setVisible(true);
}
}
I have a JTextField being added to an OverlayLayout, but the JTextField automatically scales to be the dimensions of the entire panel, which I don't want. I also don't want to mess with the dimensions of the JTextField because the default height is just right for the font, and the width is supposed to be defined by the number of columns in the constructor. What would be the right way to fix this?
Here's the relevant code that I have now:
frame = new JFrame("frame");
frame.setResizable(false);
panel = new GamePanel();
panel.setPreferredSize(new Dimension(500,300));
panel.setLayout(new OverlayLayout(panel));
JTextField t = new JTextField(50);
panel.add(t);
frame.add(panel);
frame.pack();
frame.setVisible(true);
GamePanel is just a subclass of JPanel; it doesn't do anything that would affect the JTextField.
EDIT: ok, I've heard now that using the default Swing layout managers isn't the best idea. kleopatra linked a page that refers to three third-party layouts that should accomplish pretty much everything you need to do, but I can't find anything that would let me overlay a text field (or other component) onto another custom-rendered panel. What would be the right approach?
Does this work as you want it?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.LayoutManager;
import javax.swing.JTextField;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.OverlayLayout;
public class OverlaySampleAlignment0 {
public static void main(String args[]) {
JFrame frame = new JFrame("Overlay Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(500,300));
LayoutManager overlay = new OverlayLayout(panel);
panel.setLayout(overlay);
JTextField field = new JTextField("", 12);
field.setMaximumSize(field.getPreferredSize());
//button.setMaximumSize(new Dimension(25, 25));
field.setBackground(Color.white);
field.setAlignmentX(0.0f);
field.setAlignmentY(0.0f);
panel.add(field);
frame.add(panel);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
}
The height is exactly the height needed for the font, and the width is (in my example) 12 "columns" (JTextField does not use a monospaced font by default in my Java setup). Additionally I aligned it in the upper left corner.
This might also help trouble-shooting layout issues:
Link
Most of the code is copied from here: Link. I just added the setMaximumSize(...) and used a JTextField instead of buttons etc.
I have this simple Java Swing test application that show an upper label and under this label a button:
package com.techub.exeute;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import org.jdesktop.application.SingleFrameApplication;
public class Main extends SingleFrameApplication{
public static void main(String[] args) {
Main a = new Main();
a.startup();
}
#Override
protected void startup() {
JFrame frame = new JFrame("FrameDemo");
frame.setMinimumSize(new Dimension(800, 400));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel myLabel = new JLabel("Hello World !!!", SwingConstants.CENTER);
myLabel.setFont(new Font("Serif", Font.BOLD, 22));
myLabel.setBackground(Color.RED);
myLabel.setOpaque(true);
myLabel.setPreferredSize(new Dimension(100, 80));
frame.getContentPane().add(myLabel, BorderLayout.NORTH);
Button myButton = new Button("Click Me !!!");
myButton.setMaximumSize(new Dimension(50, 25));
frame.getContentPane().add(myButton, BorderLayout.CENTER);
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
The button is in the BorderLayout.CENTER position. The problem is that this button occupies all available space in the CENTER position also if I have set the Maximum Size property with a Dimension object.
What am I wrong? What can I do to create a button having specific dimension?
You're currently telling Java to place the button in the center of your BorderLayout. Java then thinks that you want the entire area filled with this button. If you want to place a normal sized button in the center of your BorderLayout, add the button to a new JPanel and place the JPanel inside BorderLayout.CENTER.
Doing this, you're telling Java to fill out BorderLayout.CENTER with your JPanel. The elements that you place inside this JPanel will appear normal, because these elements are not getting "stretched" because of your BorderLayout - the JPanel is.
You fail to realize that it's not only the max/min/preferred sizes of the components that determine the outcome. The LayoutManager has a lot to say in this, and as you noticed, BorderLayout will fill the whole area with the component.
What you can do is create a JPanel, make it use for example FlowLayout and put that JPanel to BorderLayout.CENTER and the JButton to the JPanel.
You are using BorderLayout, North region has JLabel. JButton is put on center. JButton will occupy all the space left as per BorderLayout.
Please find more information about Layout on link : http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
U are using BorderLayout, button occupy all the left space of the frame.
use setBounds() function .
myButton.setBounds(10,200,100,30);