Stack overflow error GUI programming - java

I have a big problem i tried to solve it for days. I programmed a little program but it doesn't work.The error is Stackoverflow I already searched this website on and on again .I broke it down to the part wich doesn't works so here is the code.
This is the frame:
package snippet;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class MyFrame extends JFrame {
JButton button;
JLabel label;
TextEdit textEdit = new TextEdit();
public void LetsGo() {
setBounds(0, 0, 800, 510);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Game");
setResizable(false);
setLocationRelativeTo(null);
//Labels
label = new JLabel();
label.setText("Change Me");
label.setBounds(30, 25, 200, 50);
label.setVisible(true);
add(label);
button = new JButton();
button.setText("I Will Change A Text");
button.setBounds(30, 130, 200, 400);
button.addActionListener(new Listener());;
add(button);
}
public class Listener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
textEdit.editTheText();
}
}
And this object should edit the Text :
package snippet;
public class TextEdit {
MyFrame frame = new MyFrame();
public void editTheText(){
frame.label.setText("Text was edited");
}
}
So the real code is much more complex so i won't put all in one Object
Would be great if i receive some help would be very very thankful for that

You are creating a new MyFrame in TextEdit, which I don't think is what you want to do because frame.label will be null.
What you really should be doing is assigning the JFrame inside of Listener.
public class Listener implements ActionListener {
private JFrame frame;
public Listener(JFrame frame) {
this.frame = frame;
}
#Override
public void actionPerformed(ActionEvent e) {
if (this.frame.label != null) {
this.frame.label.setText("Text was edited");
}
}
}
Then for the the other code, you don't have a constructor or your actual class is called LetsGo?
Assuming it is not called LetsGo and it actually is MyFrame, you need an actual constructor.
public MyFrame() {
LetsGo();
}
Then in the LetsGo method, add the frame to the Listener
button.addActionListener(new Listener(this));

Related

Utilize a ActionListener object from a separate JFrame class to main class

I am building a GUI program in which specific code takes place when a certain condition is meant (JButton is pressed). I have a seperate class that constructs my Jframe called "MyFrame" .
Essentially I want to know the proper way to use my use a ActionListener/ ActionEvent from my "MyFrame" class in conjunction when a JButton is pressed in which it would correlate properly in the main class.
For example i am able to initiate specific code when a JButton is pressed in my MyFrame class through the actionPerformed provided method by java in my Myframe class, I am just puzzled on how I can make the same thing work through my main class as well.
Any assistance would be appreciated
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
public static void main(String[] args) {
MyFrame mf;
mf= new MyFrame();
Expenses exp ;
BudgetSystem system ;
ActionEvent e ;
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class MyFrame extends JFrame implements ActionListener {
JFrame myFrame;
JPanel myPanel;
JLabel greetText ;
JButton addReportButton;
JButton exitButton;
ActionListener event ;
BorderLayout layout ;
MyFrame() {
myFrame = new JFrame();
myPanel = new JPanel();
greetText = new JLabel();
addReportButton = new JButton();
exitButton = new JButton();
myPanel.setBorder(null);
myFrame.setPreferredSize(new Dimension(400,300));
greetText.setText("Please choose one of the following options to begin:" );
myPanel.add(greetText);
myFrame.add(myPanel);
addReportButton.setText("Add a budget report");
addReportButton.addActionListener(this);
myPanel.add(addReportButton);
exitButton.setText("Close Program");
exitButton.addActionListener(this);
myPanel.add(exitButton);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setLocationRelativeTo(null);
myFrame.pack();
}
#Override
public void actionPerformed(ActionEvent e) {
/*
if (e.getSource()==addReportButton)
{
JOptionPane.showMessageDialog(myFrame,"This button Works!");
}
else if (e.getSource()== dummyButton)
{
JOptionPane.showMessageDialog(myFrame,"This is the dummy button ! , you are targeting specific buttons now ! ... YOU ROCK :) ");
}else
JOptionPane.showMessageDialog(myFrame,"This is does not work :( ");
*/
}
}
I tried to make a specific ActionEvent object in main but that did not work properly.
I also tried to use a MyFrame object to access the actionPerformed method in java but that doesnt seem to work either.
If your goal is to add listeners to a JButton from another class, one option is to give the class that holds the JButton a public method that allows this to happen, for instance:
public void addMyButtonListener(ActionListener listener) {
myButton.addActionListener(listener);
}
This would allow any object that holds an instance of the class that holds the JButton to call this method and pass in a listener.
For instance:
import java.awt.Dimension;
import java.awt.event.ActionListener;
import javax.swing.*;
public class AddOutsideActionListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
SomeGUI mainPanel = new SomeGUI();
mainPanel.addMyButtonListener(e -> {
String message = "Message from the main method";
String title = "Message";
int type = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(mainPanel, message, title, type);
});
JFrame frame = new JFrame("Some GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
class SomeGUI extends JPanel {
public static final int PREF_W = 600;
public static final int PREF_H = 400;
private JButton myButton = new JButton("My Button");
public SomeGUI() {
add(myButton);
setPreferredSize(new Dimension(PREF_W, PREF_H));
}
public void addMyButtonListener(ActionListener listener) {
myButton.addActionListener(listener);
}
}

How to properly call a shape drawing method in an ActionListener

I'm trying to make it so that after clicking on the button, a figure is added to the canvas.
But I can't correctly implement the listener method in the OvalDrawTool class.
package com.company;
import javax.swing.*;
import java.awt.*;
public class TestFrame extends JFrame{
public final OvalDrawTool odt = new OvalDrawTool();
public static void main(String[] args){
new TestFrame().start();
}
public void start(){
setLayout(new BorderLayout());
JPanel buttonsPanel = new JPanel();
JButton buttonOval = odt.getButtonOval();
buttonsPanel.add(buttonOval);
add(buttonsPanel, BorderLayout.NORTH);
setSize(500,500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
}
I do not understand how should I create a Graphics object and pass it in actionPerformed method
package com.company;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class OvalDrawTool implements ActionListener{
public JButton getButtonOval() {
JButton buttonOval = new JButton();
buttonOval.setPreferredSize(new Dimension(100, 50));
buttonOval.setText("Oval");
buttonOval.addActionListener(this);
return buttonOval;
}
public void paintOval(Graphics g) {
g.setColor(Color.green);
g.fillOval(100, 100, 50, 50);
}
#Override
public void actionPerformed(ActionEvent e) {
paintOval();
}
}
I moved the figure drawing method into a separate class since I want to add more other shapes.

Java Button not appearing on (GUI)

I've been figuring out a nice way to lay nice foundations when working on a somewhat bigger project than I have before. If i write everything in main it works fine. When doing classes like this the Frame works but the Button i've added doesn't wanna appear:
//main
package taxsystem;
import java.awt.*;
import javax.swing.*;
public class Taxmain
{
public mainFrame mf;
public Interface gui;
public void startApplication()
{
mf = new mainFrame();
mf.startApp();
gui = new Interface();
gui.makeLayout();
}
public static void main(String[] args)
{
Taxmain tm = new Taxmain();
tm.startApplication();
}
}
//The actual Frame
package taxsystem;
import java.awt.*;
import javax.swing.*;
public class mainFrame extends JFrame
{
public void startApp()
{
setResizable(false);
setVisible(true);
setSize(720,340);
setLocation(0,0);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBackground(Color.WHITE);
setTitle("Tax Handler");
}
}
//the layout (where i create the button that doesn't appear)
package taxsystem;
import java.awt.*;
import javax.swing.*;
public class Interface extends JPanel
{
Taxmain mc;
public JButton testButton;
public void makeLayout()
{
testButton = new JButton();
testButton.setText("Printer");
testButton.setFont(new Font("verdana", Font.ITALIC, 16));
testButton.setForeground(Color.BLACK);
testButton.setFocusable(false);
testButton.setSize(new Dimension(150, 40));
testButton.setLocation(10, 10);
this.setLayout(null);
this.add(testButton);
}
}
Currently it looks like this: https://gyazo.com/fad5dbca6c59905faea0a8ac1fbd424a
Thanks in advance, also are there anyway i can improve the code i have so far?
You need to add the JPanel to your JFrame
public void startApplication()
{
mf = new mainFrame();
mf.startApp();
gui = new Interface();
gui.makeLayout();
mf.add(gui); // here is get's added
}

How can I switch focus to a canvas?

I have this class and I want to switch focus to the Game class right after it was invoked. I might've not understand the purpose of focus but when I press start I have to click on the game canvas itself so I can use the keyboard . In other words: How can I make it so I don't have to click on it to use the keyboard?
package com.runner.panels;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import com.runner.main.Game;
import com.runner.main.Main;
public class PlayPanel extends JPanel{
private static final long serialVersionUID = 1L;
public PlayPanel(){
//setting the layout of the playpanel to null
setLayout(null);
//setting up the info panel : high score, meters ran, pause button etc...
JPanel info = new JPanel();
info.setBounds(0,0,1200,50);
add(info);
//back button
JButton back = new JButton("Back");
info.add(back);
Game game = new Game();
game.setBounds(0,50,1200,521);
game.setBackground(Color.black);
add(game);
back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
CardLayout cl = (CardLayout) Main.mainp.getLayout();
cl.show(Main.mainp, "Menu");
}
});
}
}
Off topic: (kinda)
The fact that you are doing Main.mainp.getLayout();, calling the panel statically tells me you have poor design and should be looking into other options like an Model-view-controller pattern, an Observer pattern, or at the very least passing a reference of of the Main to the panel, instead of using static objects/calls.
Back on topic
Sounds like a common KeyListener problem. Generally to gain focus you call requestFocusInWindow(). But you still have to worry about other components stealing the focus way after the fact.
I would instead recommend using Key Bindings instead of KeyListener. You have more control over the focus. For instance, by using
InputMap im = panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke("SPACE"), "hitSpace");
panel.getActionMap().put("hitSpace", new AbstractAction(){
public void actionPerformed(ActionEvent e) {
// do something.
}
});
The panel will have immediate access to the action once you show it from the CardLayout. If you happen to use any other components that would steal the focus away from the panel, the action is still accessible because of the WHEN_IN_FOCUSED_WINDOW input map
Here's a simple example. Type A if it is on panel A, you will see it print. If you type B, it won't print because panel A is in the window. Also if you try and press the button in the panel to steal the focus, you can still type and it will still print. Same goes for panel B
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class Main {
CardLayout layout = new CardLayout();
JPanel panel = new JPanel(layout);
JPanel p1 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JPanel p2 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
};
JButton b1 = new JButton("panelA");
JButton b2 = new JButton("panelB");
public Main() {
addKeyBind(p1, "pressA", "A");
addKeyBind(p2, "pressB", "B");
p1.add(new JButton("Button for Panel A"));
p2.add(new JButton("Button for Panel B"));
panel.add(p1, "panelA");
panel.add(p2, "panelB");
b1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelA");
}
});
b2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
show("panelB");
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(b1);
buttonPanel.add(b2);
JFrame frame = new JFrame();
frame.add(panel);
frame.add(buttonPanel, BorderLayout.PAGE_END);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void show(String panelName) {
layout.show(panel, panelName);
}
private void addKeyBind(JComponent comp, String name, final String stroke) {
InputMap im = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
im.put(KeyStroke.getKeyStroke(stroke), name);
comp.getActionMap().put(name, new AbstractAction(){
public void actionPerformed(ActionEvent e) {
System.out.println(stroke + " pressed");
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new Main();
}
});
}
}
Take some time to go over the link I gave you for Key Bindings to learn more.
Back off-topic
Take a look at #AndrewThompson's comment about the null layouts. Learn how to use the LayoutManagers
I believe your problem would be fixed if you add
setFocusable(true);
to your PlayPanel constructor (works for me).
Also, if you want a specific Panel in your GUI to have focus when you start your application, follow the link in the comment of "user3218114", as this will explain how to implement this functionality with Listeners.
Good luck!
You don't need to do anything. The container should be focusable for that.
Here is a code to demonstrate.
package one;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
public class PlayPanel extends Canvas {
public static void main(String... args) {
PlayPanel p = new PlayPanel();
p.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
p.msg = "Focus gained";
p.repaint();
}
#Override
public void focusLost(FocusEvent e) {
p.msg = "Focus Lost";
p.repaint();
}
});
p.setBackground(Color.GRAY);
JFrame f = new JFrame();
f.add(p);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 200);
f.setLocation(300, 300);
f.setVisible(true);
}
String msg = "NO FOCUS";
public void paint(Graphics g) {
g.drawString(msg, 50, 50);
}
}

JPanel transition, what is wrong with my code?

I am new to java, and learning new things everyday.
Today i stumbled upon an error i just can not get fixed.
So i've got a JFrame with a JPanel inside, now I want to remove the Jpanel when i click on my Start game JLabel, and make it transition into my game JPanel ( for now i use a test JPanel)
JFrame class:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MainMenu extends JFrame {
JPanel panel;
JFrame frame;
JButton playlabel;
public void mainmenu() {
frame = new JFrame();
panel = new JPanel();
playlabel = new JButton ("Nieuw Spel");
//frame
frame.setSize(new Dimension(800, 600));
frame.getContentPane().setBackground(new Color(14,36,69));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setMinimumSize(frame.getMinimumSize());
frame.setVisible(true);
//panel
Dimension expectedDimension = new Dimension(690, 540);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.setPreferredSize(expectedDimension);
panel.setMaximumSize(expectedDimension);
panel.setMinimumSize(expectedDimension);
panel.setBackground(new Color(14, 36, 69));
panel.add(playlabel);
playlabel.setAlignmentX(JComponent.CENTER_ALIGNMENT);
//playlabel
playlabel.setFont(new Font("Old English Text MT", Font.BOLD, 40));
playlabel.setBounds(250, 350, 50, 20);
playlabel.setForeground(new Color(217,144,39));
playlabel.setBackground(new Color(14,36,69));
playlabel.setBorderPainted(false);
playlabel.setFocusPainted(false);
playlabel.addActionListener(new PlayListener());
}
private class PlayListener extends JFrame implements ActionListener {
public void actionPerformed(ActionEvent e) {
JPanel panelgame = Game.Game();
this.remove(panel);
this.add(panelgame);
this.revalidate();
}
}
}
Game class:
package labyrinthproject.View;
import java.awt.Color;
import javax.swing.JPanel;
public class Game {
public static JPanel Game(){
JPanel panel = new JPanel();
panel.setSize(690, 540);
panel.setBackground(new Color(255,36,69));
return panel;
}
}
if anyone could explain this to me why this doesn't work, it would be greatly appreciated!
Thank you very much!
Sincerely,
A beginner java student.
There are quite some issues in your code
Create the GUI on the event dispatch thread
Don't extend JFrame (you have three (three!) JFrames floating around there!)
Follow the naming conventions
Don't overuse static methods
Only store the instance variables that you really need to represent your class state
Don't use manual setSize or setBounds calls. Use a LayoutManager instead
The call to frame.setVisible(true) should be the last call, after the frame has been completely assembled
Consider a CardLayout for switching between panels ( http://docs.oracle.com/javase/tutorial/uiswing/layout/card.html )
Slightly cleaned up, but the exact structure depends on what you actually want to achieve at the end:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MainMenu extends JPanel
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame mainFrame = new JFrame();
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainMenu = new MainMenu();
mainFrame.getContentPane().add(mainMenu);
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
MainMenu()
{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
Dimension expectedDimension = new Dimension(690, 540);
setPreferredSize(expectedDimension);
setBackground(new Color(14, 36, 69));
JButton newGameButton = new JButton ("Nieuw Spel");
newGameButton.setAlignmentX(JComponent.CENTER_ALIGNMENT);
newGameButton.setFont(new Font("Old English Text MT", Font.BOLD, 40));
newGameButton.setForeground(new Color(217,144,39));
newGameButton.setBackground(new Color(14,36,69));
newGameButton.setBorderPainted(false);
newGameButton.setFocusPainted(false);
newGameButton.addActionListener(new PlayListener());
add(newGameButton);
}
private class PlayListener implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
removeAll();
GamePanel gamePanel = new GamePanel();
add(gamePanel);
revalidate();
}
}
}
class GamePanel extends JPanel
{
GamePanel()
{
setBackground(new Color(255,36,69));
}
}
You should use a JButton and not a JLabel. Then:
you add to your JButton : Your_JB.addActionListener(this); (don't forget to implement ActionListener to your class).
Now, we are gonna add the detector:
#Override
public void actionPerformed(ActionEvent e){
Object src = e.getSource();
if(src == Your_JB){
panel.setVisible(false);
}
}
When you click the button, it will make your panel disapear.
Try this:
this.remove(panel);
this.validate();
this.repaint(); //if you use paintComponent
this.add(panelgame);
this.revalidate();
Swing is hard to making nice UI. You just need to use validate() after remove().
I hope it's helpfull.

Categories