I am doing some basic tests to understand how Java Swing works.
I have a test application which consist of three fully independent windows (JFrames):
Main Menu
Asset Window 1
Asset Window 2
The Main Menu has a JButton which will show/hide Asset Window 1 (a1).
This is the main class to launch all windows:
package test1;
import test1.AssetList.AssetList;
import test1.MainMenu.MainMenu;
import javax.swing.*;
public class Test1 {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
MainMenu m = new MainMenu();
AssetList a1 = new AssetList();
AssetList a2 = new AssetList();
}
});
}
}
This is the class with the Asset Window JFrame:
package test1.AssetList;
import javax.swing.*;
public class AssetList extends JFrame {
public AssetList() {
JLabel label = new JLabel("Asset list");
this.getContentPane().add(label);
this.pack();
this.setVisible(false);
}
}
This is the class for the MainMenu JFrame:
package test1.MainMenu;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
public class MainMenu extends JFrame {
JLabel label = new JLabel("Main Menu");
JButton button = new JButton("Asset");
public MainMenu() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(label);
this.getContentPane().add(button);
button.addActionListener(new ButtonAssetListener());
this.pack();
this.setVisible(true);
}
}
This is the class for the Asset Window Button JButton listener:
package test1.MainMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ButtonAssetListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent evt) {
System.out.println("CLICK!");
/* PSEUDOCODE
if(a1 from Test1.isVisible()==true) {
a1 from Test1.setVisible(false);
} else {
a1 from Test1.setVisible(true);
}
*/
}
}
How can I retrieve the a1 instance from ButtonAssetListener in order to toggle its visibility?
Is there a better alternative to structure this kind of multiple windows application in Java Swing?
You can just pass the instance you want to hide to the button listener.
public class Test1 {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
AssetList a1 = new AssetList();
AssetList a2 = new AssetList();
MainMenu m = new MainMenu(a1);
}
});
}
}
Make your main menu take in a component which it will show and hide.
public class MainMenu extends JFrame {
JLabel label = new JLabel("Main Menu");
JButton button = new JButton("Asset");
public MainMenu(JComponent assetList) {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(label);
this.getContentPane().add(button);
button.addActionListener(new ButtonAssetListener(assetList));
this.pack();
this.setVisible(true);
}
}
Then modify your your button asset listener to take in a component which it will then show or hide.
public class ButtonAssetListener implements ActionListener{
private JComponent component;
public ButtonAssetListener(JComponent component) {
this.component = component;
}
#Override
public void actionPerformed(ActionEvent evt) {
if(component.isVisible()) {
component.setVisible(false);
} else {
component.setVisible(true);
}
}
}
Related
Here I have test application, where I can't understand why ActionListener from Test class doesn't work. Each help will make me happy. Thanks :)
Here's code;
package com.company;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main extends JFrame {
Main(){
GUI m = new GUI();
this.getContentPane().add(m.panel);
this.setDefaultCloseOperation(3);
this.setBounds(0,0,400,200);
this.setLocationRelativeTo(null);
this.requestFocus();
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
new Test();
}
});
}
}
class GUI{
GUI(){
initComp();
btn();
}
JPanel panel = new JPanel();
JButton button1;
JTextField textField;
private void initComp(){
textField = new JTextField(10);
button1 = new JButton("TEST");
panel.add(textField);
panel.add(button1);
}
public String getEnteredText(){
return textField.getText().trim(); //trim dodatkowy
}
public void btn(){
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
System.out.println("Test from GUI-class");
}
});
}
}
class Test{
Test(){
buttonGetter();
}
GUI m = new GUI();
String kol;
public void buttonGetter(){
m.button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
System.out.println("Test from Test-class");
}
});
}
}
Test doesn't add anything to any components/windows, so it's never visible on the screen, only the instance of GUI, which is created in Main is visible.
A possibly better solution would be to use class inheritance to extend the GUI and override the btn method in order to provide your custom implementation, which might look something like...
public class Test extends GUI {
#Override
public void btn() {
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
System.out.println("Test from Test-class");
}
});
}
}
Then instead of creating an instance of GUI in the Main method, you create an instance of Test instead, for example;
GUI m = new Test();
Runnable example
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 Main extends JFrame {
Main() {
GUI m = new Test();
this.getContentPane().add(m.panel);
this.setDefaultCloseOperation(3);
this.setBounds(0, 0, 400, 200);
this.setLocationRelativeTo(null);
this.requestFocus();
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
}
});
}
public class GUI {
GUI() {
initComp();
btn();
}
JPanel panel = new JPanel();
JButton button1;
JTextField textField;
private void initComp() {
textField = new JTextField(10);
button1 = new JButton("TEST");
panel.add(textField);
panel.add(button1);
}
public String getEnteredText() {
return textField.getText().trim(); //trim dodatkowy
}
public void btn() {
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
System.out.println("Test from GUI-class");
}
});
}
}
public class Test extends GUI {
#Override
public void btn() {
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
System.out.println("Test from Test-class");
}
});
}
}
}
Hi, I'm new to Java and I have the following problem:
I created a JFrame and I want the JPanel to change when clicking a JButton. That does almost work.The only problem is that the program creates a new window and then there are two windows. One with the first JPanel and one with the second JPanel.
Here is my current code:
first class:
public class Program {
public static void main (String [] args) {
new window(new panel1());
}
}
second class:
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Window extends JFrame {
private static final long serialVersionUID = 1L;
Window(JPanel panel) {
setLocation((int) Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - 200,
(int) Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2 - 100);
setSize(400, 200);
setTitle("test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setContentPane(panel);
setVisible(true);
}
}
third class:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class Panel1 extends JPanel {
private final long serialVersionUID = 1L;
Panel1() {
JButton nextPanelButton = new JButton("click here");
add(nextPanelButton);
ActionListener changePanel = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
new window(new panel2());
}
};
nextPanelButton.addActionListener(changePanel);
}
}
fourth class:
public class Panel2 extends JPanel {
private static final long serialVersionUID = 1L;
Panel2() {
JLabel text = new JLabel("You pressed the Button!");
add(text);
}
}
But I just want to change the JPanel without opening a new window. Is there a way to do that?
Thanks in advance!
This is a demo
import javax.swing.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new MainFrame("Title").setVisible(true);
});
}
}
MainFrame.java
import javax.swing.*;
import java.awt.*;
public class MainFrame extends JFrame {
private JPanel viewPanel;
public MainFrame(String title) {
super(title);
createGUI();
}
private void createGUI() {
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLayout(new BorderLayout());
setMinimumSize(new Dimension(600, 480));
viewPanel = new JPanel(new BorderLayout());
add(viewPanel, BorderLayout.CENTER);
showView(new View1(this));
pack();
}
public void showView(JPanel panel) {
viewPanel.removeAll();
viewPanel.add(panel, BorderLayout.CENTER);
viewPanel.revalidate();
viewPanel.repaint();
}
}
View1.java
import javax.swing.*;
import java.awt.*;
public class View1 extends JPanel {
final private MainFrame owner;
public View1(MainFrame owner) {
super();
this.owner = owner;
createGUI();
}
private void createGUI() {
setLayout(new FlowLayout());
add(new JLabel("View 1"));
JButton button = new JButton("Show View 2");
button.addActionListener(event -> {
SwingUtilities.invokeLater(() -> owner.showView(new View2(owner)));
});
add(button);
}
}
View2.java
import javax.swing.*;
import java.awt.*;
public class View2 extends JPanel {
final private MainFrame owner;
public View2(MainFrame owner) {
super();
this.owner = owner;
createGUI();
}
private void createGUI() {
setLayout(new FlowLayout());
add(new JLabel("View 2"));
JButton button = new JButton("Show View 1");
button.addActionListener(event -> {
SwingUtilities.invokeLater(() -> owner.showView(new View1(owner)));
});
add(button);
}
}
First of all, take a look at Java naming conventions, in particular your class names should start with a capitalized letter.
If you want to avoid to open a new window every time you click the button, you could pass your frame object to Panel1 constructor, and setting a new Panel2 instance as the frame content pane when you click the button. There is also no need to pass Panel1 to Window constructor (please note that Window class is already defined in java.awt package, it would be better to avoid a possible name clash renaming your class ApplicationWindow, MyWindow or something else).
You could change your code like this (only relevant parts):
public class Program
{
public static void main (String [] args) {
SwingUtilities.invokeLater (new Runnable () {
#Override public void run () {
new Window ().setVisible (true);
}
};
}
}
class Window extends JFrame
{
// ...
Window () {
// ...
setContentPane(new Panel1 (this));
}
}
class Panel1 extends JPanel
{
// ...
Panel1 (JFrame parent) {
// ...
ActionListener changePanel = new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
parent.setContentPane (new Panel2 ());
}
};
// ...
}
Also note the SwingUtilities's invokeLater call, which is the best way to initialise your GUI in the EDT context (for more info look at this question).
Finally, you could avoid to create a new Panel2 instance every time you click the button, simply by using a CardLayout.
Take a look at the official tutorial.
This is an old post, but it may be useful to answer it in a simplified way. Thanks to mr mcwolf for the first answer.
If we want to make 1 child jframe interact with a main jframe in order to modify its content, let's consider the following case.
parent.java and child.java.
So, in parent.java, we have something like this:
Parent.java
public class Parent extends JFrame implements ActionListener{
//attributes
//here is the class we want to modify
private some_class_to_modify = new some_class_to_modify();
//here is a container which contains the class to modify
private JPanel container = new JPanel();
private some_class = new some_class();
private int select;
//....etc..etc
//constructor
public Parent(){
this.setTitle("My title");
//etc etc
//etc....etc
container.add(some_class_to_modify,borderLayout.CENTER);
}
//I use for instance actionlisteners on buttons to trigger the new JFrame
public void actionPerformed(ActionEvent arg0){
if((arg0.getSource() == source_button_here)){
//Here we call the child class and send the parent's attributes with "this"
Child child = new Child(this);
}
//... all other cases
}//Here is the class where we want to be able to modify our JFrame. Here ist a JPanel (Setcolor)
public void child_action_on_parent(int selection){
this.select = selection;
System.out.println("Selection is: "+cir_select);
if(select == 0) {
//Do $omething with our class to modify
some_class_to_modify.setcolor(Color.yellow);
}
}
In child.java we would have something like this:
public class Child extends JFrame implements ActionListener {
//Again some attributes here
private blabla;
//Import Parent JFrame class
private Parent owner;
private int select_obj=0;
//Constructor here and via Parent Object Import
public Child(Parent owner){
/*By calling the super() method in the constructor method, we call the parent's
constructor method and gets access to the parent's properties and methods:*/
super();
this.owner = owner;
this.setTitle("Select Method");
this.setSize(400, 400);
this.setContentPane(container);
this.setVisible(true);
}
class OK_Button implements ActionListener {
public void actionPerformed(ActionEvent e) {
Object Selection = select;
if(Selection == something) {
select_obj=0;
valid = JOptionPane.showConfirmDialog(null,"You have chosen option 1. Do you want to continue?","Minimum diameter",2);
}
System.out.println("Option is:"+valid);
if(valid == 0) {
setVisible(false);
//Here we can use our herited object to call the child_action_on_parent public class of the Parent JFrame. So it can modify directly the Panel
owner.child_action_on_parent(select_obj);
}
}
}
I have two Java classes; mcveF1 and mcveF2. The code below disables when run opens a JFrame with a singular JButton on it. This button opens a second JFrame and disables the first. Similarly this frame has a singular JButton on it. This button should close the second frame and re-enable the first frame. However an exception is thrown, java.lang.NullPointerException. I believe this is because I am creating a new instance of mcveF1 instead of using the current one. I am unaware of how to fix this and would appreciate any help in fixing it.
mcveF1
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import net.miginfocom.swing.MigLayout;
public class mcveF1
{
public JFrame myMainWindow = new JFrame("Frame 1");
JPanel panel2 = new JPanel();
//Variables and Components
JButton openFrame = new JButton("Open new frame");
public void runGUI()
{
myMainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myMainWindow.setLayout(new GridLayout(1,1));
createSortTestPanel();
myMainWindow.getContentPane().add(panel2);
myMainWindow.setVisible(true);
myMainWindow.pack();
myMainWindow.setMinimumSize(new Dimension(myMainWindow.getBounds().getSize()));
myMainWindow.setLocationRelativeTo(null);
}
public void createSortTestPanel()
{
MigLayout layout = new MigLayout("", "[grow]");
panel2.setLayout(layout);
openFrame.addActionListener(new buttonAction());
panel2.add(openFrame);
}
public static void main(String[] args)
{
mcveF1 f1 = new mcveF1();
f1.runGUI();
}
class buttonAction implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
myMainWindow.setEnabled(false);
mcveF2 f2 = new mcveF2();
f2.runGUI();
}
}
}
mcveF2
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import net.miginfocom.swing.MigLayout;
public class mcveF2
{
JFrame myMainWindow = new JFrame("Frame 2");
JPanel panel2 = new JPanel();
//Variables and Components
JButton closeFrame = new JButton("Close");
mcveF1 f1;
public void runGUI()
{
myMainWindow.setLayout(new GridLayout(1,1));
createSortTestPanel();
myMainWindow.getContentPane().add(panel2);
myMainWindow.setVisible(true);
myMainWindow.pack();
myMainWindow.setMinimumSize(new Dimension(myMainWindow.getBounds().getSize()));
myMainWindow.setLocationRelativeTo(null);
}
public void createSortTestPanel()
{
MigLayout layout = new MigLayout("", "[grow]");
panel2.setLayout(layout);
closeFrame.addActionListener(new buttonAction());
panel2.add(closeFrame);
}
public static void main(String[] args)
{
mcveF2 f2 = new mcveF2();
f2.runGUI();
}
class buttonAction implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
myMainWindow.dispose();
f1.myMainWindow.setEnabled(true);
}
}
}
The null pointer exception is shown in this picture as per PM77-1's request.
Create a constructor in your class mcveF2
public class mcveF2() {
public mcveF2(mcveF1 f1) {
this.f1 = f1;
}
Then pass instance of mcveF1 to this constructor in button action listener.
class buttonAction implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
myMainWindow.setEnabled(false);
mcveF2 f2 = new mcveF2(mcveF1.this);
f2.runGUI();
}
}
I have two JFrames (frameA and FrameB). frameB can only be opened from frameA and when I open frameB, frameA must be left open. frameB has got a button (Close_frameA). I would like when the button is clicked to close frameA.
How can i do it?
First of all, is each JFrame made by a different class( I would assume so because I don't know any other way to make two frames).
Possible solution to try:
in frame A, create a "static variable":
//lets call the class that create frameA ClassA
public class ClassA extends JFrame {
static JFrame frameA;
instead of doing
JFrame frameA=new JFrame("Name of the frame");
in the public static void main(String[] args).Then, in the public static void main(String[] args) program, do
//the static JFrame assigned before
frameA= new JFrmae("Nameof the frame");
this lets the program in frameB to read "frameA" with the following code in ClassB(lets call the class that make frameB ClassB):
JFrame frameA= ClassA.frameA;
then, still in ClassB, we can do
frameA.dispose();
I hope you understand(please comment for what you don't understand if you don't), and i hope it works.
Code:
import javax.swing.JFrame;
public class ClassA {
static JFrame frameA;
public ClassA(){
//a useless constructor because I am not adding any Listeners(don't worry about it)
}
public static void main(String[] args){
frameA=new JFrame("Name");
//your ordinary things(some peiople put these in the constructor)
frameA.setSize(300,300);
frameA.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frameA.setVisible(true);
//runs ClassB
new ClassB();
}
}
and
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class ClassB extends JFrame implements ActionListener{
static JButton close=new JButton("close");
public ClassB(){
//your ordinary thigns
add(close);
setSize(300,300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
close.addActionListener(this);
System.out.println("what?");
}
public static void main(String[] args){
JFrame frameB=new JFrame("Clae Frame A");
}
#Override
public void actionPerformed(ActionEvent arg0) {
if(arg0.equals("close")){
JFrame frameA=ClassA.frameA;
frameA.dispose();
}
}
}
You can use below two class: TJFrame and OpenFrame to close a JFrame class with a button in another JFrame
public class TJFrame {
public static OpenFrame openWindow;
public static void main(String[] args) {
JFrame frame = new JFrame("Swing Frame");
JButton button = new JButton("Open");
frame.add(button);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
openWindow = new OpenFrame();
openWindow.setVisible(true);
}
});
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setSize(350, 200);
frame.setVisible(true);
}}
public class OpenFrame extends JFrame{
JPanel back_panel;
public JButton button = new JButton("Cross");
public OpenFrame() {
back_panel = new JPanel();
setContentPane(back_panel);
this.setSize(350, 200);
button.setBounds(380, 10, 20, 20);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
dispose();
}
});
back_panel.add(button);
}}
So I am trying to make a menu in swing of 8 functions. This code i have right now.
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Menu extends JFrame {
public Menu(){
init();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
#Override
public void run(){
Menu menu = new Menu();
menu.setVisible(true);
}
});
}
private void init() {
setTitle("Group 2");
setSize(300, 400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JButton quitButton = new JButton("E(X)it");
quitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
});
createLayout(quitButton);
JButton nameAsk = new JButton("What is your name?");
nameAsk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
}
});
createLayout(nameAsk);
}
private void createLayout(JComponent... arg){
Container pane = getContentPane();
GroupLayout gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup().addComponent(arg[0]));
gl.setVerticalGroup(gl.createSequentialGroup().addComponent(arg[0]));
}
}
The problem is when i add one more button the other one goes away. I think its on top of other button but i am confused now.