Why do my images not display in my panels? - java

I want to set a background for my game.
Scenario:
First of all, I have to read from a text file, and then draw my tile map and images on it base on that texts. Second, my map is 3600*2400 pixels and it's larger than my screen so I have to scroll it. Third, there must be a mini map on the corner of my screen showing me where i am. (I guess I should use panels and awt.container.)
Here is my code:
public class bkg extends Panel implements ImageObserver {
//i Initialize my variables here
// then read my images with image buffer in constructor
public static void main(String[] args) {
//my three panels and frame settings
Frame frame = new Frame();
frame.setLayout(null);
frame.setSize(1350, 700);
frame.setTitle("age of empires");
frame.setVisible(true);
frame.setLayout(null);
Panel p1 = new Panel();
Panel p2 = new Panel();
p2.setLayout(null);
JPanel p3 = new JPanel();
p3.setLayout(null);
p1.setSize(1350, 700); // i divide my screen in to 3 parts , one biggest panel, and two small. the biggest one is for main map
p1.setLayout(null);
p2.setBackground(Color.cyan);//just wanna test showing my panel.
p2.setSize(675, 350);
p3.setSize(675, 350);
p1.setLocation(0, 0);
p2.setLocation(0, 350);// this small panel must be under the main pannel.
p3.setLocation(675, 350);// this is with p2.
frame.add(p1);
p1.add(p2);
p2.add(p3);
tilemap = new int[60][75];// it creat my tilemap in console.
filereader();// it reads the text file.
}
#Override
public void paint(Graphics g) {
super.paint(g);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
int mod_i = 100 * i;// based on images sizes
int mod_j = 50 * j;// based on images sizes
//now i start to draw images base on the text file numbers
switch (tilemap[i][j]) {
case 1:
g.drawImage(tree, mod_i, mod_j, null);
break;
.........
}
}
}
}
Question: Seems that my code can't even see the paint method. It doesn't draw any images on my panels. What's the problem?

Your code is so full of errors that I started from the beginning to create a GUI divided into 3 areas.
You must start a Swing application with a call to the SwingUtilities invokeLater method. This ensures that the Swing application starts on the Event Dispatch thread (EDT).
A Java class name starts with a capital letter. Java method names and variable names start with a lowercase letter.
Don't put everything in your main method. Break your code up into methods that do one thing well. My run method creates the JFrame. My createMainPanel method creates the main panel.
I used Swing layout managers to position the JPanels. Yes, using absolute positioning seems like it's easier, but you can't move your application to any other computer with a different screen resolution.
I decided to stop at this point. You would create further methods and / or classes to further define the 3 JPanels. In those JPanel methods / classes, you would override the paintComponent method, not the paint method.
Here's the code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class AgeOfEmpires implements Runnable {
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new AgeOfEmpires());
}
#Override
public void run() {
frame = new JFrame();
frame.setTitle("Age of Empires");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel());
frame.pack();
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
JPanel upperPanel = new JPanel();
upperPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
JPanel tilePanel = new JPanel();
tilePanel.setBackground(Color.CYAN);
tilePanel.setPreferredSize(new Dimension(800, 300));
upperPanel.add(tilePanel);
JPanel lowerPanel = new JPanel();
lowerPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
JPanel miniMapPanel = new JPanel();
miniMapPanel.setBackground(Color.BLUE);
miniMapPanel.setPreferredSize(new Dimension(400, 300));
JPanel unknownPanel = new JPanel();
unknownPanel.setBackground(Color.GREEN);
unknownPanel.setPreferredSize(new Dimension(400, 300));
lowerPanel.add(miniMapPanel);
lowerPanel.add(unknownPanel);
mainPanel.add(upperPanel, BorderLayout.CENTER);
mainPanel.add(lowerPanel, BorderLayout.SOUTH);
return mainPanel;
}
}

Related

Is there a way to put JPanel on a JPanel?

I'm trying to put a JPanel inside OR on a JPanel, whichever may be the case, ultimately I just want this to work like this
As you can see on the picture, the red line is a JFrame and it has 2 JPanels inside it, on the green JPanel there are some different JPanels.
I need help with the green JPanel and the little JPanels inside it. Is there any way to make it work like this?
Any help would be greatly appreciated!
==============EDIT 1==============
So here is some code, to show you what I've done so far with the help of #hfontanez.
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
public class Main
{
public static void main(String[] args)
{
//JFrame
JFrame jframe = new JFrame();
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setSize(1920, 1080);
jframe.setResizable(false);
jframe.setLocationRelativeTo(null);
jframe.setVisible(true);
//parentJpanel - This is the main panel
JPanel parentJpanel = new JPanel();
parentJpanel.setBackground(Color.YELLOW);
parentJpanel.setSize(1920, 1080);
parentJpanel.setLayout(new BorderLayout());
//smallPanel - This is the little panel on the bottom
JPanel smallPanel = new JPanel();
smallPanel.setBackground(Color.GREEN);
smallPanel.setSize(1920, 300);
smallPanel.setLocation(0, 780);
smallPanel.setLayout(new BoxLayout(smallPanel, BoxLayout.PAGE_AXIS));
parentJpanel.add(smallPanel);
jframe.add(parentJpanel);
}
}
I expected the top part to be yellow, and the small part on the bottom to be green, yet the whoel thing turned green. What did I do wrong?
The pictured GUI is created using three panels.
The YELLOW panel is the game play area. It has no layout, no components (which define their own preferred sizes) and is custom painted, so it defines a sensible preferred size to report to the layout manager.
The GREEN panel contains controls. It uses a FlowLayout.
The RED panel uses a BorderLayout, and puts the YELLOW panel in the CENTER and the GREEN panel in the PAGE_END.
Code
This is the code that made the screenshot seen above.
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
public class GameLayout {
GameLayout() {
// The main GUI. Everything else is added to this panel
JPanel gui = new JPanel(new BorderLayout(5, 5));
gui.setBorder(new EmptyBorder(4, 4, 4, 4));
gui.setBackground(Color.RED);
// The custom painted area - it is a panel that defines its preferred size.
gui.add(new GamePanel());
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
buttonPanel.setBackground(Color.GREEN);
for (int ii = 1; ii<5; ii++) {
buttonPanel.add(new JButton("B " + ii));
}
gui.add(buttonPanel,BorderLayout.PAGE_END);
JFrame f = new JFrame("Game Layout");
f.setContentPane(gui);
f.setLocationByPlatform(true);
f.pack();
f.setVisible(true);
}
public static void main(String[] args) {
Runnable r = () -> new GameLayout();
SwingUtilities.invokeLater(r);
}
}
class GamePanel extends JPanel {
GamePanel() {
setBackground(Color.YELLOW);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 100);
}
}
You need to use a LayoutManager so when you put the JPanel inside the other JPanel it will have the correct look. If you simply put panels inside the others, the parent JPanel will use its default layout manager, which is FlowLayout.
For the look of it, it seems you need to use Border Layout for the parent (yellow) panel. For the green, you have options, but I think your best bet is to use Box Layout with a PAGE_AXIS Component Orientation.
In general, you need to be familiarized with two things: 1) Layout Managers and how they behave, and 2) the default layout behavior of JComponents.

jsplitpane and paintcomponent conflicting with each other

I'm having issues with my code regarding the fact that when I instantiate my City class as an object and add it to the right side of my JSplitPane (or even the left), the circle that is supposed to be drawn is not showing up. My cities class uses paintComponent and should draw a circle just by calling the constructor. I have also tried putting the repaint in its own drawIt() method but the result is still the same. The buttons and spinner show up on the left side of the divider, but the circle I am trying to draw does not show up at all.
Here is my City class.
import javax.swing.*;
import java.awt.*;
public class City extends JPanel{
int xPos, yPos;
City(int x, int y){
xPos = x;
yPos = y;
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(xPos, yPos, 10, 10);
}
}
And here is my main.
Here I try to instantiate my city and add it to the right side of the JSplitPane (under Add Components) and that is where I am having issues with, as the black circle will not be drawn on the JSplitPane.
import java.awt.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
public class TSP{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TSP();
}
});
}
TSP(){
JLabel instructions = new JLabel("Enter the number of cities: ");
instructions.setBounds(30, 150, 300, 40);
SpinnerNumberModel numMod = new SpinnerNumberModel(2, 2, 10, 1);
JSpinner numOfCities = new JSpinner(numMod);
numOfCities.setBounds(185, 150, 80, 40);
JButton start = new JButton("Start Simulation");
start.setBounds(50, 400, 200, 40);
JFrame frame = new JFrame("Travelling Salesperson");
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
JPanel lp = new JPanel(null);
JPanel rp = new JPanel(null);
sp.setDividerLocation(300);
sp.setLeftComponent(lp);
sp.setRightComponent(rp);
sp.setEnabled(false);
frame.setDefaultCloseOperation(3);
frame.setSize(1100,600);
frame.setResizable(false);
////////////////Add Components//////////////////////////
lp.add(instructions);
lp.add(numOfCities);
lp.add(start);
City test = new City(301, 301);
rp.add(test);
frame.add(sp);
////////////////////////////////////////////////////////
frame.setVisible(true);
}
}
I feel like the circle is being drawn under the JSplitPane as if I add my cities object (test) to my frame instead of the JSplitPane(frame.add(test) instead of rp.add(test) under the Add Components section) the black circle will appear in the desired spot but the JSplitPane along with the buttons and spinners will disappear so I feel as if they are conflicting. Is there any fix to this or is there another way altogether to make the circle appear on the right side while the other components are on the left side.
I do not know why it is not drawing the circle on the JSplitPane, but any sort of help would be appreciated. Thanks!
Sorry if anything is unclear or there is any ambiguity in my code, or if I need to post more information as I am quite new to posting here. Let me know if there is anything else I need to add or if there are any questions regarding what I am asking!
EDIT:
It seems there is something blocking where I draw the circle, like another JPanel. Here is an image below. As you can see part of the circle looks as if it is being covered. The small box I drew is the only area that the dot is visible from (everywhere else the circle is covered up by white). Also, the coordinates for the circle in the image below is at (3, 0), i.e City test = new City(3, 0);
I am not quite sure why this is happening though.
the invisible JPanel?
Now that I've seen what you're trying to do, I can provide a more proper answer.
You have a control panel on the left and a drawing panel on the right. Usually, you don't use a JSplitPane to separate the panels. To create your layout, you would add the control panel to the LINE_START of the JFrame BorderLayout and the drawing panel to the CENTER.
The reason for this is that you don't want to constantly recalculate the size of the drawing panel.
So let me show you one way to get a solid start. Here's the GUI I created.
Here are the things I did.
All Swing GUI applications must start with a call to the SwingUtilities invokeLater method. This method ensures that Swing components are created and executed on the Event Dispatch Thread.
I separated the creation of the JFrame, the control panel, and the drawing panel. That way, I could focus on one part of the GUI at a time.
The JFrame methods must be called in a certain order. This is the order that I use for most of my Swing applications.
The JFrame is not sized. It is packed. The Swing layout managers will calculate the size of the components and the JPanels.
I used a FlowLayout and a GridBagLayout to create the control panel. Yes, this looks more complicated than absolute positioning, but in the long run, layout managers allow the GUI to be more flexible.
I used the setPreferredSize method in the drawing panel to set the preferred size of the drawing panel. Because I know the drawing panel size, I can put the first city in the center of the drawing panel.
And here's the code. You don't have to code exactly like this, but this code should give you a good basis to start your project. Take a look at the model / view / controller pattern and see how to further separate your code into smaller pieces that allow you to focus on one part of your application at a time.
I put all the classes in one file to make it easier to paste. You should separate these classes into separate files.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
public class CitySimulation implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new CitySimulation());
}
private ControlPanel controlPanel;
private DrawingPanel drawingPanel;
private JFrame frame;
#Override
public void run() {
frame = new JFrame("Traveling Salesperson");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
controlPanel = new ControlPanel();
frame.add(controlPanel.getPanel(), BorderLayout.LINE_START);
drawingPanel = new DrawingPanel();
frame.add(drawingPanel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class ControlPanel {
private JPanel panel;
public ControlPanel() {
panel = new JPanel(new FlowLayout());
JPanel mainPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.insets = new Insets(10, 10, 10, 10);
JLabel instructions = new JLabel("Enter the number " +
"of cities:");
mainPanel.add(instructions, gbc);
gbc.gridx++;
gbc.insets = new Insets(10, 0, 10, 10);
SpinnerNumberModel numMod =
new SpinnerNumberModel(2, 2, 10, 1);
JSpinner numOfCities = new JSpinner(numMod);
mainPanel.add(numOfCities, gbc);
gbc.anchor = GridBagConstraints.CENTER;
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 2;
gbc.insets = new Insets(10, 10, 10, 10);
JButton start = new JButton("Start Simulation");
mainPanel.add(start, gbc);
panel.add(mainPanel);
}
public JPanel getPanel() {
return panel;
}
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 1L;
public DrawingPanel() {
this.setBackground(Color.WHITE);
this.setPreferredSize(new Dimension(400, 400));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillOval(195, 195, 10, 10);
}
}
}

Java swing JScrollPane not scrollable

This is the add(main) version
This is the add(scroll) version
Im trying to get a window full of lables and make it scrollable, this is my code for that purpose:
public class JobHistoryListScreen extends JFrame implements View
{
#Override
public void showScreen()
{
setSize(800, 800);
setLayout(new BorderLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel main = new JPanel();
main.setSize(500,500);
JScrollPane scroll = new JScrollPane(main,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scroll.setSize(500,500);
//Font
//Font david50 = new Font("David", Font.BOLD, 50);
for(int i=0; i<1000; i++)
{
JLabel empty = new JLabel("No jobs to display!");
empty.setBounds(0,i+250,400,100);
empty.setFont(david50);
main.add(empty);
}
add(main);
setVisible(true);
}
public static void main(String[] args) {
JobHistoryListScreen v = new JobHistoryListScreen();
v.showScreen();
}
}
For some reason the window gets filled with the labels but is not scrollable at all.
Learn about layout managers. Refer to Laying Out Components Within a Container. Default for JPanel is FlowLayout and because the JPanel is inside a JScrollPanel, the labels will not wrap. And since you set the horizontal scroll bar policy to NEVER, there is no horizontal scroll bar and hence you cannot scroll horizontally. Try using BoxLayout to display all the labels one under the other. Alternatively you could use a GridLayout with 0 (zero) rows and 1 (one) column. Refer to the tutorial for more details.
EDIT
Here is my modified version of your code. Explanatory notes appear after the code.
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.WindowConstants;
public class JobHistoryListScreen implements Runnable {
private JFrame frame;
#Override // java.lang.Runnable
public void run() {
showScreen();
}
public void showScreen() {
frame = new JFrame("Jobs");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel main = new JPanel(new GridLayout(0, 1));
JScrollPane scroll = new JScrollPane(main,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scroll.setPreferredSize(new Dimension(500, 500));
Font david50 = new Font("David", Font.BOLD, 50);
for(int i=0; i<1000; i++) {
JLabel empty = new JLabel("No jobs to display!");
empty.setFont(david50);
main.add(empty);
}
frame.add(scroll);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
JobHistoryListScreen v = new JobHistoryListScreen();
// Launch Event Dispatch Thread (EDT)
EventQueue.invokeLater(v);
}
}
I don't know what interface View is so I removed that part.
No need to extend class JFrame.
No need to explicitly call setSize() on JFrame. Better to call pack().
Default content pane for JFrame is JPanel and default layout manager for that JPanel is BorderLayout so no need to explicitly set.
No need to call setSize() on JPanel.
Call setPreferredSize() rather than setSize() on JScrollPane.
Add the JScrollPane to the JFrame and not the JPanel.
No need to call setBounds() because GridLayout handles this.
Explicitly launch EDT (Event Dispatch Thread) by calling invokeLater().
Here is a screen capture of the running app. Note the vertical scroll bar.

Newbie JLayeredPane issue

I just can't get past square one on JLayeredPanes. (See my original question of yesterday. I have been studying the JLayeredPane tutorial and API. These tutorials are geared somewhat differently to what I am ultimately trying to produce.
Going back to square one, I took Oracle's JFrame Example and modified it to include Layered panes.
Here is the code:
package components;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/* FrameDemo.java requires no other files. */
public class FrameDemo {
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainLayer = new JPanel(new BorderLayout());
mainLayer.setPreferredSize(new Dimension(640, 480));
frame.setContentPane(mainLayer);
frame.getLayeredPane().add(mainLayer, JLayeredPane.DEFAULT_LAYER, 0);
JLabel emptyLabel = new JLabel("LABEL");
emptyLabel.setPreferredSize(new Dimension(320, 240));
mainLayer.add(emptyLabel, BorderLayout.NORTH);
JPanel subLayer = new JPanel(new BorderLayout());
JLabel subLabel = new JLabel("SUBLABEL");
subLabel.setPreferredSize(new Dimension( 200, 100));
subLabel.setBackground(Color.YELLOW);
subLayer.add(subLabel, BorderLayout.SOUTH);
subLayer.setVisible(true);
subLabel.setVisible(true);
frame.getLayeredPane().add(subLayer, JLayeredPane.PALETTE_LAYER, 0);
//Display the window.
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();
}
});
}
}
Why doesn't it work? IOW, why doesn't the sublabel show up? It's at a higher level than the main layer.
One thought is why am I adding mainLayer to both the Content Pane and the Layered Pane? If I don't do that, nothing shows up. I.e, by commenting out this line, I just get a blank frame.
// frame.setContentPane(mainLayer);
Obviously, I'm not understanding something. But what is it?
I should add that obviously, this simple demo can be done without Layered Panes. But my ultimate goal is to have a layer that can be turned on and off programatically. But I can't even get this simple case to work. If I can get over this hump, I think the rest will be easier.
ADDENDUM:
What I want to acheive is illustrated by the following Code, which is very similar to what TrashGod set up below and it works. There is a JLayeredPane with a constant layer (layered at Integer(0)) and a floating layer layered initially at Integer(-1) but togglable by the F7 and F8 keystrokes between the Integer(-1) layer and the Integer(1) layer, thereby allowing it to float above or below the constant layer.
package components;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/* MyLayeredPaneDemo.java requires no other files. */
public class MyLayeredPaneDemo {
private JFrame frame;
private JLayeredPane mainPanel;
private JPanel constantLayer;
private JPanel floatingLayer;
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private MyLayeredPaneDemo() {}
private void createAndShowGUI() {
//Create and set up the window.
this.frame = new JFrame("MyLayeredPaneDemo");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.frame.setPreferredSize(new Dimension(640, 480));
mainPanel = new JLayeredPane();
constantLayer = new JPanel(new BorderLayout(0,0));
floatingLayer = new JPanel(new BorderLayout(0,0));
// constantLayer.setPreferredSize();
constantLayer.setOpaque(true);
constantLayer.setBackground(Color.BLUE);
JLabel constantLabel = new JLabel("MAIN LAYER");
constantLayer.setPreferredSize(new Dimension(640, 480));
constantLayer.add(constantLabel, BorderLayout.CENTER);
JLabel subLabel = new JLabel("SUB LAYER");
floatingLayer.setBackground(Color.YELLOW);
floatingLayer.add(subLabel, BorderLayout.SOUTH);
floatingLayer.setOpaque(true);
floatingLayer.setVisible(true);
floatingLayer.setVisible(true);
subLabel.setBackground(Color.YELLOW);
mainPanel.add(constantLayer, new Integer(0), 0);
constantLayer.setBounds(0,0,640,480);
mainPanel.add(floatingLayer, new Integer(-1), 0);
floatingLayer.setBounds(100, 360, 300, 90 );
frame.add(mainPanel, BorderLayout.CENTER);
//Display the window.
mapKeyToAction(frame.getRootPane(),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0),
"Hide Layer",
new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("F7 pressed");
mainPanel.setLayer(floatingLayer, new Integer(-1));
}
});
mapKeyToAction(frame.getRootPane(),
JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0),
"Show Layer",
new AbstractAction() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("F8 pressed");
mainPanel.setLayer(floatingLayer, new Integer(1));
}
});
frame.pack();
frame.setVisible(true);
frame.getRootPane().setFocusable(true);
boolean ok = frame.getRootPane().requestFocusInWindow();
System.out.println("focus ok: " + ok);
}
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() {
new MyLayeredPaneDemo().createAndShowGUI();
}
});
}
private static void mapKeyToAction(JComponent component,
int whichMap, KeyStroke keystroke,String key, Action action) {
component.getInputMap(whichMap).put(keystroke, key);
component.getActionMap().put(key, action);
}
}
However, I am having trouble getting this to work in my real case. The difference between the two is that here, my JLayeredPane is owned by the Frame, whereas in my real application, I want the JLayeredPane to be owned by a JPanel is that some levels down in the containment hierarchy from the Frame, and whose size is set by a GridBagLoyout in its parent, and the size is therefore unknowable at the time its constructor is called, making it difficult to call setBounds() which I need to do on a child of a JLayeredPane.
FURTHER ADDENDUM. I know that the Oracle Tutorials mention a case where Layouts rather than absolute positioning is used with a JLayeredPane. The difference between this case and mine is that in my case the layers occupy the same horizontal space on different layers, whereas in this case, the components on different layrers occupy different horizontal spaces. It's almost as if we need a 3D Layout Manager!
"By default, a layered pane has no layout manager."—How to Use Layered Panes
Addendum: I need to avoid using the Frame's layered pane and instead add a layered pane to the window.
Yes, The Root Pane is an instance of JRootPane, which contains a JLayeredPane. In particular, "The layered pane contains the menu bar and content pane, and enables Z-ordering of other components."
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FrameDemo {
private static void createAndShowGUI() {
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane mainLayer = new JLayeredPane();
frame.add(mainLayer, BorderLayout.CENTER);
JLabel label = new JLabel("LABEL", JLabel.CENTER);
label.setBounds(100, 100, 200, 100);
label.setOpaque(true);
label.setBackground(Color.cyan);
mainLayer.add(label, 1);
JPanel subLayer = new JPanel(new BorderLayout());
JLabel subLabel = new JLabel("SUBLABEL", JLabel.CENTER);
subLabel.setBounds(20, 20, 200, 100);
subLabel.setOpaque(true);
subLabel.setBackground(Color.yellow);
subLayer.add(subLabel, BorderLayout.SOUTH);
mainLayer.add(subLabel, 2);
frame.pack();
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
The solution I came up and thanks to trashgod which I expect is good advice too is to implement ComponentListener and capture the component resize event. At that point you can get the actual bounds of the container and use it to set the actual bounds of the layer JPanels which are always in some fixed relation to the bounds of the component that contains them. It works.
Trashgod's solution would also work I believe but I have not tried it.

JPanel layout Issue

So I have a slight issue with adding two JPanels to a main main panel. I've put it as a quick example of what I want to do since you don't want to be looking through loads of lines of unnecessary code :). I want panel one to be added first (north) and then panel two (south). I've tried using Border layout and positioning them invoking north and south on BorderLayout when adding the panels but still no luck.
Thanks in advance.
private JPanel one,two;
public Example(){
one = new JPanel();
one.setSize(new Dimension(400,400));
two = new JPanel(new GridLayout(7,8));
two.setSize(new Dimension(400,400));
one.setBackground(Color.BLACK);
two.setBackground(Color.BLUE);
JPanel mainpanel = new JPanel();
mainpanel.setBackground(Color.orange);
mainpanel.add(one);
mainpanel.add(two);
add(mainpanel);
setSize(500,500);
setVisible(true);
}
If you want to use BorderLayout, then BorderLayout.CENTER takes up as much space as it can, and the other directions take only what they need. If you add extra stuff to the JPanels, they will get bigger, based on the needs of the objects they contain.
If you want to just divide the space evenly within the main JPanel, try this:
JPanel mainpanel = new JPanel(new GridLayout(2, 1));
That creates a GridLayout with 2 rows and 1 column...
Try this code. There was issue that apparently if you install grid layout on a panel and you add no components it will not take space.
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JFrame
{
private JPanel one, two;
public Example()
{
one = new JPanel();
two = new JPanel();///new GridLayout(7, 8));
one.setBackground(Color.BLACK);
two.setBackground(Color.BLUE);
JPanel mainpanel = new JPanel(new BorderLayout());
mainpanel.setBackground(Color.orange);
mainpanel.add(one, BorderLayout.NORTH);
mainpanel.add(two, BorderLayout.SOUTH);
setContentPane(mainpanel);
setSize(500, 500);
setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
Example f = new Example();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
}
GridLayout ignores the values set in setSize method of contained components. If you want to control the size of each component, consider using GridBagLayout.

Categories

Resources