JPanel is not draw on JFrame - java

Linked to a previous question : I want to draw on panel. I have the following classes:
GMain.java
public class GMain{
static frmDashboard fDB;
public static void main(String[] args) {
fDB = new frmDashboard();
fDB.setTitle("Graphics Mate");
fDB.setVisible(true);
fDB.pack();
}
}
frmDashboard.java
public class frmDashboard extends javax.swing.JFrame {
public frmDashboard() {
initComponents();
Clear();
}
private void btnPlotActionPerformed(java.awt.event.ActionEvent evt) {
frmCPlot fCP = new frmCPlot();
fCP.setVisible(true);
fCP.pack();
}
}
frmCPlot.java
public class frmCPlot extends javax.swing.JFrame {
int W, H;
int N;
public frmCPlot() {
initComponents();
CPanel cp = new CPanel();
this.getContentPane().add(cp);
System.out.println("WW = " + cp.getWidth() +
" HH = " + cp.getHeight());
}
class CPanel extends JPanel{
int i, j;
public CPanel(){
setPreferredSize(new Dimension(400, 400));
setBackground(Color.WHITE);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawLine(0, 0, this.getWidth(), this.getHeight());
}
}
}
The frmCPlot is displayed, but CPanel is not displayed. Not talking about the line. More, the output from the frmCPlot.java is:
*WW = 0 HH = 0*
I followed the instructions by the book. I tried to add a repaint in frmCPlot class, in CPanel class, but no use. Have any idea ?

It's never a good idea to extend a JFrame as it's a Top Level Component. This will just lead to more problems. You should, instead, create a class that extends a JPanel and add that to the a JFrame. A JPanel is good for when you want to group things together. Since you still have to have a JFrame somewhere in your program (or else it will display nothing) you'll have to make a variable instead and add the JPanel to it.
Try something like this
JFrame frame = new JFrame("My Frame");
frame.setSize(500, 500);
frame.getContentPane().add(new JPanel MyPanel);
frame.setVisible(true);

Related

In Java can we create an object of a subclass in the subclass itself and outside the methods of the subclass?

I need to create an object of a subclass in the subclass itself but outside of all the methods of the subclass.
In the code below, I want to create an object of ODrawPanel at the specified location (commented part in the code) but when I do this, I get a StackOverflowError. However, I can create the object ODrawPanel inside the display() method with no problem but in that case I cannot use it in the other methods. I need to do some drawing on the panel and the panel must be available anywhere in the code.
How can I make the panel object available anywhere in the code?
Thanks for helping.
package odrawpanel;
import java.awt.*;
import javax.swing.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentAdapter;
public class ODrawPanel extends JPanel
{
private Point p1 = new Point(100, 300);
private Point p2 = new Point(380, 300);
// Either
// JPanel panel = new ODrawPanel(); I want to create the object of the subclass here.
// or
// ODrawPanel panel = new ODrawPanel();
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
}
public void display()
{
JPanel panel = new ODrawPanel();
JFrame f = new JFrame();
panel.setBounds(40, 40, 400, 400);
panel.setBackground(Color.white);
f.add(panel);
f.setSize(800,600);
f.setLayout(null);
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.addComponentListener(new ComponentAdapter()
{
#Override
public void componentResized(ComponentEvent e)
{
panel.setSize(f.getWidth()-100,f.getHeight()-100);
}
});
}
public static void main(String args[])
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
new ODrawPanel().display();
}
});
}
}
You may declare a JPanel supplier with lazy initialization as a field of the class:
private Point p1 = new Point(100, 300);
private Point p2 = new Point(380, 300);
private final Supplier<JPanel> panelSupplier = new Supplier<>() {
private JPanel panel;
#Override
public JPanel get() {
if (panel == null) {
panel = new ODrawPanel();
}
return panel;
}
};
... and then use it all over the class by .get()ting the value from the supplier (the first time you use it, the ODrawPanel will be created but it won't cause an overflow since you're not recursively initializing it:
public void display() {
JPanel panel = panelSupplier.get(); //the first time you call get() it will create the panel, the next times it will reuse it
JFrame f = new JFrame();
panel.setBounds(40, 40, 400, 400);
//...rest of the code
I would create different classes for the main(), the JFrame, the JPanel.
In Main:
new JFrame();
In JFrame:
add(new JPanel());
...
In JPanel:
Do not create JPanels here.
...
Matteo, thank you for the code. When I tried it, I got the following compiler error for the line:
private final Supplier<JPanel> panelSupplier = new Supplier<>()
{
// some code here.
};
"cannot infer type arguments for Supplier<T>
reason: '<>' with anonymous inner classes is not supported in -source 8
(use -source 9 or higher to enable '<>' with anonymous inner classes)
where T is a type-variable:
T extends Object declared in interface Supplier"
After changing the code to:
private final Supplier<JPanel> panelSupplier = new Supplier<JPanel>()
{
// some code here.
}
I did not receive an error. It works, for example, in a method like:
public void Test()
{
JPanel panel = panelSupplier.get();
panel.setBackground(Color.RED);
}
But it has no effect in the method:
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.BLUE);
g.drawLine(p1.x, p1.y, p2.x, p2.y);
JPanel panel = panelSupplier.get();
panel.setBackground(Color.CYAN);
}

Switching between panels LayeredPane [duplicate]

This question is about Frames, Java and Processing.
This questions sounds pretty convoluted but its really not. I'll try keep this to a simple minimum. I'm creating a small ball in a maze game to get my head around physics and rendering. It's been a good experience so far but I've hit a bit of a brick wall.
The general layout I decided on was to contain PApplets within a AWT Frame and have the Frame close. The reason for this is because I was told that you should only have on instance of a Papplet at a time.
PApplet is the Applet class in Processing, a rendering library.
I have 3 classes here including the main
public class Menu extends PApplet
{
//images and buttons
PImage background, playbtn1, playbtn2, hsbtn1, hsbtn2, abbtn1, abbtn2, exbtn1, exbtn2;
FBox pBtn, hBtn, eBtn;
FWorld menu;
//simple constructor
public Menu()
{
}
public void setup()
{
size(600, 400);
smooth();
Fisica.init(this);
menu = new FWorld();
//loading and placing images
background = loadImage("MenuAlt.jpg");
System.out.println(background);
playbtn1 = loadImage("play1.gif");
playbtn2 = loadImage("play2.gif");
hsbtn1 = loadImage("high1.gif");
hsbtn2 = loadImage("high2.gif");
exbtn1 = loadImage("exit1.gif");
exbtn2 = loadImage("exit2.gif");
//loading and placing buttons
pBtn = new FBox(120, 150);
pBtn.setPosition(135, 215);
pBtn.setDrawable(false);
hBtn = new FBox(120, 150);
hBtn.setPosition(295, 215);
hBtn.setDrawable(false);
eBtn = new FBox(120, 150);
eBtn.setPosition(455, 215);
eBtn.setDrawable(false);
//add item to world
menu.add(pBtn);
menu.add(hBtn);
menu.add(eBtn);
}
public void draw()
{
image(background, 0, 0);
image(playbtn1, 80, 140);
image(hsbtn1, 237, 135);
image(exbtn1, 400, 140);
mouseOver();
menu.draw();
}
//close this frame an open a new level, high score or exit
//depending on what the use clicks
public void mousePressed()
{
FBody pressed = menu.getBody(mouseX, mouseY);
if (pressed == pBtn)
{
System.out.println("play game");
this.getParent().getParent().getParent().getParent().setVisible(false);
ExampleFrame x = new ExampleFrame(new Level("level1.txt"));
x.setLocation(this.getParent().getParent().getParent().getParent().getLocation());
}
if (pressed == hBtn)
{
System.out.println("high scores");
this.getParent().getParent().getParent().getParent().setVisible(false);
/* these are just for finding the parent
System.out.println(this.getName());
System.out.println(this.getParent().getName());
System.out.println(this.getParent().getParent().getName());
System.out.println(this.getParent().getParent().getParent().getName());
System.out.println(this.getParent().getParent().getParent().getParent().getName());
*/
ExampleFrame x = new ExampleFrame(new HighScores()); //for testing, you can change this to new menu()
x.setLocation(this.getParent().getParent().getParent().getParent().getLocation());
}
if (pressed == eBtn)
{
System.out.println("exit");
System.exit(0);
}
}
the exampleFrame class
public class ExampleFrame extends JFrame
{
PApplet app;
public ExampleFrame(PApplet emApp)
{
super("Ball Maze Game");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(200, 200);
app = emApp;
setSize(615,438);
setVisible(true);
setLayout(new BorderLayout());
add(app, BorderLayout.CENTER);
app.init();
}
}
the main
public class Main
{
public static void main(String[] args)
{
ExampleFrame x = new ExampleFrame(new Menu());
}
}
What needs to happen when mousePressed == ebtn is all the stuff in the Frame will be removed and a Highscores Screen will be loaded. highscores is almost the same as menu. There is no need to post code as there is enough here.
The second class is the one which acts as a frame and holds the PApplet
Bottom line, has anyone have any idea how to call the Frame methods from the PApplet or another way to remove all PApplets contents and load another PApplet in?
What needs to happen when mousePressed == ebtn is all the stuff in the Frame will be removed and a Highscores Screen will be loaded
The demo. below of a nested CardLayout adds an ActionListener instead of a MouseListener. It reacts to both mouse and keyboard input.
There are a multitude of other ways to include more than one GUI element in the same screen space. Off the top of my head, JTabbedPane, JSplitPane, JDesktopPane/JInternalFrame, popping the high scores in a JDialog or JOptionPane..
Screenshots
CardLayoutDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class CardLayoutDemo {
public static void main(String[] args) {
Runnable r = new Runnable () {
public void run() {
final JRadioButton game = new JRadioButton("Game", true);
JRadioButton highScores = new JRadioButton("High Scores");
ButtonGroup bg = new ButtonGroup();
bg.add( game );
bg.add( highScores );
JPanel buttons = new JPanel(new
FlowLayout(FlowLayout.CENTER, 5, 5));
buttons.add( game );
buttons.add( highScores );
JPanel gui = new JPanel(new BorderLayout(5,5));
gui.add(buttons, BorderLayout.SOUTH);
final CardLayout cl = new CardLayout();
final JPanel cards = new JPanel(cl);
gui.add(cards);
cards.add(new JLabel("Level 1"), "game");
cards.add(new JLabel("High Scores"), "scores");
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent ae) {
if (game.isSelected()) {
cl.show(cards, "game");
} else {
cl.show(cards, "scores");
}
}
};
game.addActionListener(al);
highScores.addActionListener(al);
JOptionPane.showMessageDialog(null, gui);
}
};
SwingUtilities.invokeLater(r);
}
}
In order to answer How to call the Frame methods from the PApplet?, I have modified your code snippet to bare minimum. In this modified version when the user click mouse button a System.out is fired.
Now there are two ways in which you can access your Frame object. But before that let me state these two points:
When you create a PApplet like new ExampleFrame(new Menu()); and add it in your JFrame like this add(app, BorderLayout.CENTER); then a complex hierarchy of windows/panels are created.
Like this:
javax.swing.JPanel
javax.swing.JLayeredPane
javax.swing.JRootPane
test.ExampleFrame
PApplet provides a public field for setting and accessing your frame object. And amazingly it is called frame :). You can set it before calling app.init();
>>Code
** Checkout the comments in the code**
Modified ExampleFrame.java
import java.awt.BorderLayout;
import javax.swing.JFrame;
import processing.core.PApplet;
public class ExampleFrame extends JFrame
{
private static final long serialVersionUID = 4792534036194728580L;
PApplet app;
public ExampleFrame(PApplet emApp)
{
super("Ball Maze Game");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(200, 200);
app = emApp;
setSize(615,438);
setVisible(true);
setLayout(new BorderLayout());
add(app, BorderLayout.CENTER);
// Setting my frame object
app.frame = this;
app.init();
}
// Sample Method
public void sampleMethod(String msg)
{
System.out.println("I think '"+ msg +"' called me !!");
}
}
Modified Menu.java
import java.awt.Container;
import processing.core.PApplet;
import processing.core.PImage;
public class Menu extends PApplet
{
private static final long serialVersionUID = -6557167654705489372L;
PImage background;
static String tab = "";
//simple constructor
public Menu()
{
}
public void setup()
{
size(600, 400);
smooth();
background = loadImage("C:/temp/background.jpg");
}
public void draw()
{
image(background, 0, 0);
}
public void mousePressed()
{
Container p = getParent();
tab = "";
// FIRST WAY OF ACCESSING PARENT FRAME
while(p != null)
{
//printParentTree(p);
if(p instanceof ExampleFrame)
{
ExampleFrame myframe = (ExampleFrame)p;
myframe.sampleMethod("First Way");
break;
}
p = p.getParent();
}
// SECOND WAY OF ACCESSING PARENT FRAME
if(frame != null && (frame instanceof ExampleFrame))
{
ExampleFrame myframe = (ExampleFrame)p;
myframe.sampleMethod("Second Way");
}
}
void printParentTree(Container p)
{
System.out.println(tab+p.getClass().getName());
tab +='\t';
}
}
Checkout the public void mousePressed() method.
For completeness, I am also including Main.java.
public class Main {
public static void main(String[] args){
new ExampleFrame(new Menu());
}
}
Now to answer Remove all PApplets contents and load another PApplet in
Well I have not tested it. But you can add a JPanel to your JApplet and do all your drawing on that i.e creating child controls etc. When feel like redrawing then call JPanel.removeAll(). Which as per javadoc:
Removes all the components from this
container. This method also notifies
the layout manager to remove the
components from this container's
layout via the removeLayoutComponent
method.
After this call repaint on the JPanel. Try it out, it might work :).

load contents of panel in java applet

I am trying to load a panel into a java applet, but the contents of the panel do not populate. As you can see from the code below, I set up a test to see where the code in the panel is failing to run, and the results of my test indicate that getRootPane().add(MyLabel) is the line of code that triggers the exception.
All of the code required to recreate this problem is included below. Can anyone show me how to alter the code below so that the contents of the panel get loaded into the applet?
Here is the code for TestApplet.java:
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
public class TestApplet extends JApplet {
public void init(){//Called when this applet is loaded into the browser.
//Execute a job on the event-dispatching thread; creating this applet's GUI.
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't complete successfully");
}
}
private void createGUI(){
TestPanel myPanel = new TestPanel();
myPanel.setOpaque(true);
setContentPane(myPanel);
}
}
And here is the code for TestPanel.java:
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestPanel extends JPanel{
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
getRootPane().add(myLabel);
System.out.println("Still running in constructor. ");
}
}
EDIT:
I edited my code as follows, based on the suggestions given so far. Using this.add does cause the JLabel to load, however, an inner class is still not loading, which I have added to the code below. Also, the changed code below is no longer triggering an exception; it just only loads the JLabel but does not load the inner class. Any suggestions as to how to load the inner class?
Here is the new TestApplet.java:
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
public class TestApplet extends JApplet {
public void init(){//Called when this applet is loaded into the browser.
//Execute a job on the event-dispatching thread; creating this applet's GUI.
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't complete successfully");
System.err.println(e);
e.printStackTrace();
}
}
private void createGUI(){
TestPanel myPanel = new TestPanel();
myPanel.setOpaque(true);
setContentPane(myPanel);
}
}
And here is the new TestPanel.java:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class TestPanel extends JPanel{
DrawingLines myDrawingLines = new DrawingLines();
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
this.add(myLabel);
this.add(myDrawingLines);
myDrawingLines.repaint();
System.out.println("Still running in constructor. ");
}
//inner class to override paint method
class DrawingLines extends Canvas{
int width, height;
public void paint( Graphics g ) {
width = getSize().width;
height = getSize().height;
g.setColor( Color.green );
for ( int i = 0; i < 10; ++i ) {
g.drawLine( width, height, i * width / 10, 0 );
}
System.out.println("Running in paint method.");
}
}//end of inner class
}
Set the method as:
private void createGUI(){
TestPanel myPanel = new TestPanel();
getContentPane().add(myPanel);
}
and the class TestPanel as
public class TestPanel extends JPanel{
TestPanel(){
super();
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
add(myLabel);
System.out.println("Still running in constructor. ");
}
}
The rootpane is null because the Jpanel has not been added to any component yet. And adding stuff to panel rootpane like that is.. pretty dirty.
Let start at the beginning...
public class TestPanel extends JPanel{
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
getRootPane().add(myLabel);
System.out.println("Still running in constructor. ");
}
}
Using getRootPane to add a component to it is the wrong thing to do. You should never need to add anything to a root pane. Instead you should be using the content pane, but that's not what you are trying to do (or should be doing from this context).
Instead, you simply be calling add
public class TestPanel extends JPanel{
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
add(myLabel);
System.out.println("Still running in constructor. ");
}
}
This will then add the label to the TestPane
Lets take a look at the extension...
public class TestPanel extends JPanel{
DrawingLines myDrawingLines = new DrawingLines();
TestPanel(){
System.out.println("Running in constructor. ");
JLabel myLabel = new JLabel("Hello World");
this.add(myLabel);
this.add(myDrawingLines);
myDrawingLines.repaint();
System.out.println("Still running in constructor. ");
}
//inner class to override paint method
class DrawingLines extends Canvas{
int width, height;
public void paint( Graphics g ) {
width = getSize().width;
height = getSize().height;
g.setColor( Color.green );
for ( int i = 0; i < 10; ++i ) {
g.drawLine( width, height, i * width / 10, 0 );
}
System.out.println("Running in paint method.");
}
}//end of inner class
}
First of, you should avoid mixing heavy and lightweight components (putting a Canvas on a JPanel), this is just not worth the frustration it will cause.
There is no need to call repaint in the constructor. At the time the constructor is called, the component can't be painted anyway.
Instead, simply override the panel's paintComponent method
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int width = getWidth;
int height = getHeight();
g.setColor( Color.green );
for ( int i = 0; i < 10; ++i ) {
g.drawLine( width, height, i * width / 10, 0 );
}
}
I strongly suggest you take a look at
Custom Painting
2D Graphics
Painting in AWT and Swing

Problems extending JPanels

Hi I'm working on a problem and I'm having some issues working in Swing. I have no issues working with classes that extend either JFrame or JComponent, but when I try to use a class that I write that extends JPanel, it won't ever show up and nothing that I call on that panel shows up, including adding custom JComponents to it. What is the general procedure for creating a JPanel extendting class and then setting it as the content pane to use in a JFrame?
I (my personal view) can't see nothing wrong with extends JComponent as JComponent, JPanel, JLabel, more Inheritance versus composition, for example
import java.awt.*;
import javax.swing.*;
public class CustomComponent extends JFrame {
private static final long serialVersionUID = 1L;
public CustomComponent() {
setTitle("Custom Component Test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(new CustomComponents());
pack();
setMinimumSize(getSize());// enforces the minimum size of both frame and component
setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CustomComponent main = new CustomComponent();
//main.display();
}
});
}
}
class CustomComponents extends JComponent {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
#Override
public void paintComponent(Graphics g) {
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
}
You should be added your class that extend the Jpanel to a container like JFrame.A class that extends the JPanel it not show any things because it a component not container.

Calling awt Frame methods from subclass

This question is about Frames, Java and Processing.
This questions sounds pretty convoluted but its really not. I'll try keep this to a simple minimum. I'm creating a small ball in a maze game to get my head around physics and rendering. It's been a good experience so far but I've hit a bit of a brick wall.
The general layout I decided on was to contain PApplets within a AWT Frame and have the Frame close. The reason for this is because I was told that you should only have on instance of a Papplet at a time.
PApplet is the Applet class in Processing, a rendering library.
I have 3 classes here including the main
public class Menu extends PApplet
{
//images and buttons
PImage background, playbtn1, playbtn2, hsbtn1, hsbtn2, abbtn1, abbtn2, exbtn1, exbtn2;
FBox pBtn, hBtn, eBtn;
FWorld menu;
//simple constructor
public Menu()
{
}
public void setup()
{
size(600, 400);
smooth();
Fisica.init(this);
menu = new FWorld();
//loading and placing images
background = loadImage("MenuAlt.jpg");
System.out.println(background);
playbtn1 = loadImage("play1.gif");
playbtn2 = loadImage("play2.gif");
hsbtn1 = loadImage("high1.gif");
hsbtn2 = loadImage("high2.gif");
exbtn1 = loadImage("exit1.gif");
exbtn2 = loadImage("exit2.gif");
//loading and placing buttons
pBtn = new FBox(120, 150);
pBtn.setPosition(135, 215);
pBtn.setDrawable(false);
hBtn = new FBox(120, 150);
hBtn.setPosition(295, 215);
hBtn.setDrawable(false);
eBtn = new FBox(120, 150);
eBtn.setPosition(455, 215);
eBtn.setDrawable(false);
//add item to world
menu.add(pBtn);
menu.add(hBtn);
menu.add(eBtn);
}
public void draw()
{
image(background, 0, 0);
image(playbtn1, 80, 140);
image(hsbtn1, 237, 135);
image(exbtn1, 400, 140);
mouseOver();
menu.draw();
}
//close this frame an open a new level, high score or exit
//depending on what the use clicks
public void mousePressed()
{
FBody pressed = menu.getBody(mouseX, mouseY);
if (pressed == pBtn)
{
System.out.println("play game");
this.getParent().getParent().getParent().getParent().setVisible(false);
ExampleFrame x = new ExampleFrame(new Level("level1.txt"));
x.setLocation(this.getParent().getParent().getParent().getParent().getLocation());
}
if (pressed == hBtn)
{
System.out.println("high scores");
this.getParent().getParent().getParent().getParent().setVisible(false);
/* these are just for finding the parent
System.out.println(this.getName());
System.out.println(this.getParent().getName());
System.out.println(this.getParent().getParent().getName());
System.out.println(this.getParent().getParent().getParent().getName());
System.out.println(this.getParent().getParent().getParent().getParent().getName());
*/
ExampleFrame x = new ExampleFrame(new HighScores()); //for testing, you can change this to new menu()
x.setLocation(this.getParent().getParent().getParent().getParent().getLocation());
}
if (pressed == eBtn)
{
System.out.println("exit");
System.exit(0);
}
}
the exampleFrame class
public class ExampleFrame extends JFrame
{
PApplet app;
public ExampleFrame(PApplet emApp)
{
super("Ball Maze Game");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(200, 200);
app = emApp;
setSize(615,438);
setVisible(true);
setLayout(new BorderLayout());
add(app, BorderLayout.CENTER);
app.init();
}
}
the main
public class Main
{
public static void main(String[] args)
{
ExampleFrame x = new ExampleFrame(new Menu());
}
}
What needs to happen when mousePressed == ebtn is all the stuff in the Frame will be removed and a Highscores Screen will be loaded. highscores is almost the same as menu. There is no need to post code as there is enough here.
The second class is the one which acts as a frame and holds the PApplet
Bottom line, has anyone have any idea how to call the Frame methods from the PApplet or another way to remove all PApplets contents and load another PApplet in?
What needs to happen when mousePressed == ebtn is all the stuff in the Frame will be removed and a Highscores Screen will be loaded
The demo. below of a nested CardLayout adds an ActionListener instead of a MouseListener. It reacts to both mouse and keyboard input.
There are a multitude of other ways to include more than one GUI element in the same screen space. Off the top of my head, JTabbedPane, JSplitPane, JDesktopPane/JInternalFrame, popping the high scores in a JDialog or JOptionPane..
Screenshots
CardLayoutDemo.java
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class CardLayoutDemo {
public static void main(String[] args) {
Runnable r = new Runnable () {
public void run() {
final JRadioButton game = new JRadioButton("Game", true);
JRadioButton highScores = new JRadioButton("High Scores");
ButtonGroup bg = new ButtonGroup();
bg.add( game );
bg.add( highScores );
JPanel buttons = new JPanel(new
FlowLayout(FlowLayout.CENTER, 5, 5));
buttons.add( game );
buttons.add( highScores );
JPanel gui = new JPanel(new BorderLayout(5,5));
gui.add(buttons, BorderLayout.SOUTH);
final CardLayout cl = new CardLayout();
final JPanel cards = new JPanel(cl);
gui.add(cards);
cards.add(new JLabel("Level 1"), "game");
cards.add(new JLabel("High Scores"), "scores");
ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent ae) {
if (game.isSelected()) {
cl.show(cards, "game");
} else {
cl.show(cards, "scores");
}
}
};
game.addActionListener(al);
highScores.addActionListener(al);
JOptionPane.showMessageDialog(null, gui);
}
};
SwingUtilities.invokeLater(r);
}
}
In order to answer How to call the Frame methods from the PApplet?, I have modified your code snippet to bare minimum. In this modified version when the user click mouse button a System.out is fired.
Now there are two ways in which you can access your Frame object. But before that let me state these two points:
When you create a PApplet like new ExampleFrame(new Menu()); and add it in your JFrame like this add(app, BorderLayout.CENTER); then a complex hierarchy of windows/panels are created.
Like this:
javax.swing.JPanel
javax.swing.JLayeredPane
javax.swing.JRootPane
test.ExampleFrame
PApplet provides a public field for setting and accessing your frame object. And amazingly it is called frame :). You can set it before calling app.init();
>>Code
** Checkout the comments in the code**
Modified ExampleFrame.java
import java.awt.BorderLayout;
import javax.swing.JFrame;
import processing.core.PApplet;
public class ExampleFrame extends JFrame
{
private static final long serialVersionUID = 4792534036194728580L;
PApplet app;
public ExampleFrame(PApplet emApp)
{
super("Ball Maze Game");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(200, 200);
app = emApp;
setSize(615,438);
setVisible(true);
setLayout(new BorderLayout());
add(app, BorderLayout.CENTER);
// Setting my frame object
app.frame = this;
app.init();
}
// Sample Method
public void sampleMethod(String msg)
{
System.out.println("I think '"+ msg +"' called me !!");
}
}
Modified Menu.java
import java.awt.Container;
import processing.core.PApplet;
import processing.core.PImage;
public class Menu extends PApplet
{
private static final long serialVersionUID = -6557167654705489372L;
PImage background;
static String tab = "";
//simple constructor
public Menu()
{
}
public void setup()
{
size(600, 400);
smooth();
background = loadImage("C:/temp/background.jpg");
}
public void draw()
{
image(background, 0, 0);
}
public void mousePressed()
{
Container p = getParent();
tab = "";
// FIRST WAY OF ACCESSING PARENT FRAME
while(p != null)
{
//printParentTree(p);
if(p instanceof ExampleFrame)
{
ExampleFrame myframe = (ExampleFrame)p;
myframe.sampleMethod("First Way");
break;
}
p = p.getParent();
}
// SECOND WAY OF ACCESSING PARENT FRAME
if(frame != null && (frame instanceof ExampleFrame))
{
ExampleFrame myframe = (ExampleFrame)p;
myframe.sampleMethod("Second Way");
}
}
void printParentTree(Container p)
{
System.out.println(tab+p.getClass().getName());
tab +='\t';
}
}
Checkout the public void mousePressed() method.
For completeness, I am also including Main.java.
public class Main {
public static void main(String[] args){
new ExampleFrame(new Menu());
}
}
Now to answer Remove all PApplets contents and load another PApplet in
Well I have not tested it. But you can add a JPanel to your JApplet and do all your drawing on that i.e creating child controls etc. When feel like redrawing then call JPanel.removeAll(). Which as per javadoc:
Removes all the components from this
container. This method also notifies
the layout manager to remove the
components from this container's
layout via the removeLayoutComponent
method.
After this call repaint on the JPanel. Try it out, it might work :).

Categories

Resources