Introduction
I'm learning how to present GUIs for user 'friendly' input. I will reference below some web pages for those who are interested in the matter.
Code
public class TestGUI{
private JFrame mainFrame;
private JLabel headerLabel;
private JLabel statusLabel;
private JPanel controlPanel;
public TestGUI()
{
prepareGUI();
}
private void prepareGUI()
{
mainFrame = new JFrame("TestGUI"); //Header name
mainFrame.setSize(420, 320); //Size of the frame
mainFrame.setLayout(new GridLayout(3, 1)); //??
mainFrame.addWindowListener(new WindowAdapter() //Waits for an user event
{
//When the frame is closes, the program does too.
#Override
public void windowClosing(WindowEvent windowEvent)
{
System.exit(0); //Exit program
}
});
mainFrame.setVisible(true);//GUI is visible
}
public static void main(String[] args) {
TestGUI test = new TestGUI(); //constructor
test.prepareGUI(); //Call the method
}
}
Problem
While running the code I saw that 2 identical frames pop up. I went to debug it and saw that it is executed twice when I call the method!
Why is that?
I only called it once with testGUI.prepareGUI(); in the main function.
Webpages for learning basic GUI in Java
JavaFX
GUI Programming with AWT
You call prepareGUI() in the constructor as well.
public TestGUI()
{
prepareGUI();
}
When you call new TestGUI(), this constructor gets called and so does the function.
You are calling prepareGui twice
Once here
public TestGUI()
{
prepareGUI();
}
and once here
TestGUI test = new TestGUI(); //constructor
test.prepareGUI(); //Call the method
so first block is executed on new TestGUI() call
You are calling the prepareGui() method twice. One in your constructor and once on your created object (in the main method)
The issue is that constructor (that is TestGUI()) you are already calling prepareGUI(). so just omit the other call to prepareGUI(), which is test.prepareGUI().
Related
I am trying to implement mouse listener however I can not seem to get it to work. My code doesnt have any errors, but when I click on the frame I I can not get a message to print out. I have tried extending the class HandleClassOne to viewOne, but that also wouldn't work. Any thoughts?
The main class creates a frame and then creates an instance of viewOne on the frame.
public class main{
protected static JFrame window;
public static void main(String args[]){
window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(400,400);
window.setVisible(true);
new viewOne(window);
}
}
The viewOne class adds a panel and a label to a frame. It also adds a mouse listener to the panel.
public class viewOne {
private static JPanel panel1;
private static JLabel label1;
public viewOne(JFrame frame) {
panel1 = new JPanel();
label1 = new JLabel("View One");
panel1.add(label1);
frame.add(panel1);
panel1.setBackground(Color.red);
frame.validate();
}
public static void mouseAdd() {
HandleClassOne handle = new HandleClassOne();
panel1.addMouseListener(handle);
panel1.addMouseMotionListener(handle);
}
public static void main(String[] args) {
mouseAdd();
}
}
The HandleClassOne class should print out a message when the panel created in viewOne is clicked.
public class HandleClassOne extends main implements MouseListener, MouseMotionListener {
public void mouseClicked(MouseEvent e) {
System.out.println("mouse clicked");
}
}
While you have defined the function mouseAdd(...) I don't see you calling it.
Try (within the constructor)
public viewOne(JFrame frame) {
...
mouseAdd();
...
}
naturally, you'll need to do this after the panel1 is set.
Note that there are other issues, too
You don't invoke presenting the JFrame properly within your main function in your main class. Look up a basic tutorial on Java Swing, where it talks about the event dispatch thread and the requirements to not present within your program's main thread of execution.
You have an additional main function in your viewOne class, which is not how these things are wired up.
You added the mouseAdd() method (which is responsible for registering the mouse listener) inside the main method of viewOne class.
Please keep in mind that main method only gets called whenever you are running it as entry point class for your application. Here you have main class to act as an entry point.
You kept main method in viewOne class as well and it will get called only when you are running it as an individual piece (not along with main class).
To fix the issue here, keep your mouseAdd() method call inside viewOne() constructor as constructor gets called every time whenever object is getting created.
public viewOne(JFrame frame) {
panel1 = new JPanel();
label1 = new JLabel("View One");
panel1.add(label1);
frame.add(panel1);
panel1.setBackground(Color.red);
mouseAdd();
frame.validate();
}
I have a jframe object in a class and I want to be able to close the frame from my jpanel class(which obviously I attach to the frame). Anyway, I tried making a instance field in my jpanel with the jframe object has an instance field and then made a method that I would call in the jframe class with the parameter of the jframe object I made so I could make the jpanel instance field the same object as the jframe object. I then called the instance field.dispose(); hoping it would close the frame. Any ideas would be greatly appreciated!
In case that was hard to understand here is an example:
public class example extends jFrame
{
public static void main(String[]args)
{
examplePanel ep = new examplePanel();
example e = new example(ep);
}
/**
* Constructor for objects of class example
*/
public example(examplePanel ep)
{
//code that handles my frame settings
}
}
public class examplePanel extends jPanel implements ActionListener
{
private example e;
private boolean checkWin;
public void actionPerformed(ActionEvent e)
{
if(this.checkWin())
{
setVisible(false);
e.dispose();
//^this line of code is supposed to dispose of the frame but it does not
}
}
public void getExample(example e)
{
this.e = e;
}
}
Your code and question are hard to follow as you have an ActionListener which you add to no JButton or JMenuItem, You create a JFrame object and a JPanel, but are never observed to add the panel to the frame. You give your JPanel an "example" variable, but never assign it a reference to the visualized JFrame, you don't appear to ever set the default close operation of the JFrame, and so your JFrame as written above should be non-closable. From your code it looks like your examplePanel's e variable in the JPanel should in fact be null and so calling any method on it should throw a NullPointerException, that is unless you're assigning the correct JFrame object reference to it, but are not showing us.
Myself, I'd get the top level window from Swing itself when needed, something like:
#Override
public void actionPerformed(ActionEvent e) {
// get the top-level window that is displaying this JPanel
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
win.dispose(); // dispose of it
}
}
For example:
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.*;
import javax.swing.*;
public class CloseFromJPanel extends JPanel implements ActionListener {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
public CloseFromJPanel() {
JButton closeButton = new JButton("Close Me");
closeButton.addActionListener(this);
add(closeButton);
}
#Override
public void actionPerformed(ActionEvent e) {
// get the top-level window that is displaying this JPanel
Window win = SwingUtilities.getWindowAncestor(this);
if (win != null) {
win.dispose(); // dispose of it
}
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Close From JPanel");
// GUI will exit when the JFrame is closed
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new CloseFromJPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
This code will work for JButtons within JFrames and JDialogs, but not JMenuItems or within JApplets (I don't think). Or if all you want to do is end the application, then you could simply call System.exit(0) from within the actionPerformed method. If you absolutely want to do this using a field of the JFrame, then you'll need to pass in a reference to the JFrame into the JPanel, likely using a constructor parameter, and possibly passing in this.
If this doesn't help, please create and post real code, not kind-of sort-of code, code that we can compile, run and actually test, an MCVE (please check out the link).
Other issues:
Your code does not comply with Java naming standards as class names should all start with capital letters. Please Google this and study it, since if your code follows standards, others, including both us and your future self, will better be able to understand your code.
You'll rarely want to ever extend from JFrame since you rarely need to alter it's innate behavior. Usually you'll create and use a JFrame or JDialog when and where needed.
I'm kind of confused. I'm at work right now (just started apprenticeship) and need to create a fully editable table (I'll use SQL soon). So I have 2 questions here:
What do you mean by "Don't extend JFrame"? Let's say I have a class called "TestDialog" and also a JFrame which is called "TestUI". Would it be okay to write
public class TestDialog extends TestUI ?
As I have understood it, one shouldn't create a class (called MyExample) and inside of this class just write
public class MyExample extends JFrame
Because you create a JFrame within an existing class instead of creating it seperate.
I'll keep it short - Can I use 2 actions in 1 listener (for 1 button)? Something like:
public void actionPerformed(ActionEvent e)
{
Action_One; Action_Two;
}
Or do I need to use 2 different listeners?
Okay that's it I guess. I'm sorry that I haven't written everything clearly, I just registered here and actually concentrate on translating things from my language into english. If anyone could tell me how to write here like in Eclipse I'd appreciate it, because I couldn't really find out how.
Composition over inheritance is an important programming approach. So I preffer following construction of GUI.
public class Application {
private JFrame mainFrame;
private MainPanel mainPanel;
private void installFrame() {
// initialize main frame
mainFrame = new JFrame("Title");
}
private void installComponents() {
// install all components
mainPanel = new MainPanel();
}
private void layout() {
// provide layouting
mainFrame.add(mainPanel.getComponent());
}
private void show() {
mainFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Application app = new Application();
app.installFrame();
app.installComponents();
app.layout();
app.show();
}
});
}
}
Main panel has no inheritance from JPanel, but use an instance of it.
public class MainPanel {
private JPanel mainPanel;
public MainPanel() {
mainPanel = new JPanel(new GridBagLayout()); // or another layout
initComponents();
layout();
}
private void initComponents() {
// init all components here
}
private void layout() {
// layout panel here
}
public Component getComponent() {
return mainPanel;
}
}
The same pattern I use for each complex component (for example for trees, tables, lists, tabbed panes etc.). But this approach has one disadvantage: there is no GUI builder that support it.
About actions: you can provide a combined action. Something like this
public class CombinedAction extends AbstractAction {
private Action[] delegates;
public CombinedAction(String name, Icon icon, Action... someDelegates) {
super(name, icon);
delegates = someDelegates;
}
public void actionPerformed(ActionEvent ae) {
for (Action delegate : delegates) {
delegate.actionPerfromed(ae);
}
}
}
What do you mean 2 actions? You can do anything in the actionPerformed() method. If instead your question is "can I have 2 actionPerformed methods in the class" ie two actionListeners then it's a 'NO'. You must instead read on Inner Classes to do that.
And regarding your first question it's more of a design issue.
I would prefer
public class Example{
JFrame frame;
public void initialize()
{
frame.setSize(//params);
frame......
//other frame initilizing code
}
public static void main(string[] args)
{
Example example=new Example();
example.initialize();
}
}//class ends
while someone else may feel otherwise
I have a button in my GUI that is supposed to close its window. However, its event handler is located in an AbstractAction subclass that is located in a seperate method from the JFrame. Because of this I cannot see a way to tell the JFrame to close from my AbstractAction.
Heres the basic layout of my code:
public PointWindow()
{
initialize();
}
public void initialize()
{
JFrame frame = new JFrame();
// JFrame stuff
frame.setContentPane(createGUI());
frame.setVisible(true);
}
public JPanel createGUI()
{
JPanel gui = new JPanel();
// Code....
class MakeGraphACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
frame.setVisible(false); // <--- How to get this to work?
frame.dispose(); // <---
new GraphWindow(pointList);
}
}
//Code...
return gui;
}
Have I done a bad job planning my code or am I just missing something obvious?
You need to pass the frame as a final parameter to the createGUI() method.
You will then be able to access it from within the inner class.
Basically what I want to do is get a start button to initiate a method running in another class and acting on another object.
My code for the listener:
button1a.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent event) {
// Figure out how to make this work
//sim.runCastleCrash();
}
} );
My code for the other class:
public static void main(String[] args) {
CastleCrash sim;
sim = new CastleCrash();
}
and
public void runCastleCrash() {
System.out.println("Castle Crash is beginning...");
//Other method parts here to be added
}
I get the feeling this can't be too hard, but I'm missing a piece.
One way to reference things in an anonymous class is using the final keyword:
public static void main(String[] args) {
final Object thingIWantToUse = "Hello";
JButton button = new JButton("Click");
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
System.out.println(thingIWantToUse);
}
});
JFrame frame = new JFrame();
frame.setLayout(new FlowLayout());
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
Alternatively, you can access members (variables or methods) of an enclosing type:
public class ActionListenerDemo2 {
private final JFrame frame = new JFrame();
private Object thingIWantToUse = "Hello";
public ActionListenerDemo2() {
JButton button = new JButton("Click");
button.addActionListener(new ActionListener() {
#Override public void actionPerformed(ActionEvent e) {
thingIWantToUse = "Goodbye";
System.out.println(thingIWantToUse);
}
});
frame.setLayout(new FlowLayout());
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new ActionListenerDemo2().frame.setVisible(true);
}
}
I've had the same problem like you and this is how i solved it.
You can either make your object final (final CastleCrash sim = new CastleCrash();), but i didn't want to do that, or you can make something like a setter method to run the method in your other class:
My code for the listener class:
button1a.addActionListener(new ActionListener()
{
public void actionPerformed (ActionEvent event)
{
//How to make this work ?
//Like this:
runCC();
}
});
public void runCC()
{
CastleCrash sim = new CastleCrash();
sim.runCastleCrash();
}
My code for the other class:
public void runCastleCrash()
{
System.out.println("Castle Crash is beginning...");
//Other method parts here to be added
}
Hope this is helpful, good luck ! :)
McDowell already answers practically with good examples on how to access variables from event listeners (or anonymous inner classes in general). There is however a more general Sun resource on Event Listeners in Swing that is canonical and a good overview of all the caveats to take into account when writing them.
Somehow you need a reference to your CastleCrash object available to call from your actionListener.
You probably want to subclass JFrame, or whatever is containing your JButton such that it has your both your main method and a CastleCrash property that can then be referenced from your anonymous inner class Actionlistener.
BUT - be careful, you look like you are calling what will be a long running method from within the GUI event thread (where the action listener will called). This is generally a bad idea, you will case your GUI to become unresponsive.
See http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html especially the bit on SwingWorker class for ideas on how to avoid that problem.