Calling Awt Frame Methods from Subclass

Calling awt Frame methods from subclass

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 :).

Java - Call Method from sub class By pressing a JButton in the base class

As far as I know, you can not use your base class as an instance of your derived class.

However, you can store an instance of the derived class in your base class and then cast it back to the derived class when you need to. See the ActionListener on the button for an example

Base

import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class SimpleClass extends JFrame {
public SimpleClass(String title) {
super(title);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new GridLayout());
setUp();
pack();
setLocationRelativeTo(null);
setVisible(true);
}

public SimpleClass() {

}

public void setUp() {
JPanel panel = new JPanel();

ExtendedClass e = new ExtendedClass();
SimpleClass s = new ExtendedClass();
SimpleClass thisInstance = this;

JButton button = new JButton("Press Me");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(e instanceof ExtendedClass);
e.printLn();

System.out.println(s instanceof ExtendedClass);
((ExtendedClass)s).printLn();

System.out.println(thisInstance instanceof ExtendedClass);
//Returns an exception as it is not an instance of ExtendedClass
((ExtendedClass)thisInstance).printLn();
}
});

panel.add(button);
getContentPane().add(panel);
}

public static void main(String[] args) {
EventQueue.invokeLater(() -> new SimpleClass("Title"));
}
}

Extended

@SuppressWarnings("serial")
public class ExtendedClass extends SimpleClass {
public void printLn() {
System.out.println("Printed A Line To The Console :)");
}
}

Java calling function or using object from Main class in sub class

You say that ConsoleDebug is a subclass. Maybe you need to declare as such:

public class ConsoleDebug extends MainClass{

This way you can call writeTextArea from ConsoleDebug as it is a real subclass of main class.

How to Dispose an opened Jframe from Other

Here is an example of how to dispose a JFrame from another JFrame:

import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Demo
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
FrameA one = new FrameA();
FrameB two = new FrameB(one);

one.setVisible(true);
two.setVisible(true);
}
});
}
}

class FrameA extends JFrame
{
private static final long serialVersionUID = 1812279930292019387L;

public FrameA()
{
super("Frame A");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setLocationRelativeTo(null);

setResizable(false);
}
}

class FrameB extends JFrame
{
private static final long serialVersionUID = 5126089271972476434L;

public FrameB(final JFrame otherFrame)
{
super("Frame B");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400, 400);
setLayout(new GridBagLayout());
setLocationRelativeTo(otherFrame);

JButton button = new JButton("Dispose Other");
button.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
otherFrame.dispose();
}
});

add(button);

setResizable(false);
}
}

How to show different pages from the center element of JFrame (having set to BorderLayout)

Here is a mcve demonstrating how you could use CardLayout as suggested by Andrew Thompson:

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GuiController extends JFrame {

private boolean isRedShowing;

public GuiController(){

setTitle("CardLayout Demo");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
CentreFrameController centreFrameController = new CentreFrameController();
centreFrameController.showRedPane();
isRedShowing = true;
setLayout(new BorderLayout());
add(centreFrameController,BorderLayout.CENTER);
JButton toggle = new JButton("Toggle");
toggle.addActionListener(e ->{
if(! isRedShowing) {
centreFrameController.showRedPane();
} else {
centreFrameController.showYelloPane();
}
isRedShowing = ! isRedShowing;
});
add(toggle,BorderLayout.PAGE_END);
pack();
setVisible(true);
}

public static void main(String[] args) {
new GuiController();
}
}

class CentreFrameController extends JPanel {

public final String YELLOW_PAGE = "yellow page";
public final String RED_PAGE = "red page";
private final CardLayout cLayout;

public CentreFrameController(){

cLayout = new CardLayout();
setLayout(cLayout);
setPreferredSize(new Dimension(200, 150));
add(YELLOW_PAGE, new YellowPane());
add(RED_PAGE, new RedPane());
}

//two convenience methods that encapsulate CardLayout#show(Container, String)
void showRedPane() {
cLayout.show(this, RED_PAGE);
}

void showYelloPane() {
cLayout.show(this, YELLOW_PAGE);
}
}

class RedPane extends JPanel{

RedPane(){
setBackground(Color.RED);
}
}

class YellowPane extends JPanel{

YellowPane(){
setBackground(Color.YELLOW);
}
}

You control which card shows by using CarrdLayout show.


Sample Image

Using a method declared in an interface, but not class

...or do I have to create a subclass of JPanel with that one method in it and then have each subclass be a subclass of that one?

That's the way to go, your own MyJPanel (or similar) class (either abstract or not). Then, you use MyJPanel throughout your code. That gives you a compile-time check that you're dealing with one of your subclasses, and gives you a convenient place to add further methods if you need to.

You could do

((TheInterface)setPanel).getKeyPress();

...but it's clumsy, and you lose compile-time code checks (and all the usual arguments against casting apply).

Clojure (let [frame (java.awt.Frame.)]) within un-invoked function causes AWT to be started

Doing a bit of spelunking through rt.jar, I was able to track it down a bit.

The static initializer[1] for java.awt.Frame looks like:

 0: iconst_0
1: putstatic #20 // Field nameCounter:I
4: invokestatic #114 // Method java/awt/Toolkit.loadLibraries:()V
7: invokestatic #115 // Method java/awt/GraphicsEnvironment.isHeadless:()Z
10: ifne 16
13: invokestatic #116 // Method initIDs:()V
16: new #117 // class java/awt/Frame$1
19: dup
20: invokespecial #118 // Method java/awt/Frame$1."<init>":()V
23: invokestatic #119 // Method sun/awt/AWTAccessor.setFrameAccessor:(Lsun/awt/AWTAccessor$FrameAccessor;)V
26: return

I was able to reproduce the behavior by executing java.awt.Toolkit at the REPL, so I dug into that static initializer too:

 0: ldc_w         #150 // class java/awt/Toolkit
3: invokevirtual #151 // Method java/lang/Class.desiredAssertionStatus:()Z
6: ifne 13
9: iconst_1
10: goto 14
13: iconst_0
14: putstatic #126 // Field $assertionsDisabled:Z
17: iconst_0
18: putstatic #84 // Field loaded:Z
21: new #152 // class java/awt/Toolkit$3
24: dup
25: invokespecial #153 // Method java/awt/Toolkit$3."<init>":()V
28: invokestatic #32 // Method java/security/AccessController.doPrivileged:(Ljava/security/PrivilegedAction;)Ljava/lang/Object;
31: pop
32: invokestatic #154 // Method loadLibraries:()V
35: invokestatic #155 // Method initAssistiveTechnologies:()V
38: invokestatic #156 // Method java/awt/GraphicsEnvironment.isHeadless:()Z
41: ifne 47
44: invokestatic #157 // Method initIDs:()V
47: return

loadLibraries seemed interesting, so that disassembly looks like:

 0: getstatic     #84 // Field loaded:Z
3: ifne 23
6: new #85 // class sun/security/action/LoadLibraryAction
9: dup
10: ldc #86 // String awt
12: invokespecial #87 // Method sun/security/action/LoadLibraryAction."<init>":(Ljava/lang/String;)V
15: invokestatic #32 // Method java/security/AccessController.doPrivileged:(Ljava/security/PrivilegedAction;)Ljava/lang/Object;
18: pop
19: iconst_1
20: putstatic #84 // Field loaded:Z
23: return

Rewriting the core bit of that in Clojure looks like:

(doto (sun.security.action.LoadLibraryAction. "awt")
(java.security.AccessController/doPrivileged))

Running this causes the same application to pop up, so my suspicion is that the native library has initializer code that causes it. Unfortunately, I don't feel like diving into real disassembly, so someone else will have to figure it out from that point!

[1]: I unpacked rt.jar and then used javap -p -c Foo.class to see this.



Related Topics



Leave a reply



Submit