I had a frame with two buttons. The first button opened a second frame and the other button was closing it. It worked. Now I want to make a single button that opens a frame and by clicking it again the frame shall close. But it is not working. I set boolean conditions. By clicking the button once it is set from false to true. If it is set to "true" the actionListener is supposed to recognize that annother action (close frame) shall be performed. But nothing happens. Here the code.
public class Main {
public static void main(String[] args) {
FrameOne frameOne = new FrameOne ();
}
}
.
public class FrameOne extends JFrame implements ActionListener {
private FrameTwo frameTwo;
private boolean frameIsOpen = false; // By clicking the button once the value is set to true.
private JButton btn = new JButton();
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
FrameOne(){
btn.addActionListener(this);
add(btn);
setSize(400,400);
setLocation(300, 250);
setLayout(new FlowLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btn && frameIsOpen == false) {
frameTwo = new FrameTwo(); // Opens the new frame
boolean frameIsOpen = true;} // Fulfills the condition for the else if statement.
else if (e.getSource() == btn && frameIsOpen == true) {
frameTwo.dispatchEvent(new WindowEvent(frameTwo, WindowEvent.WINDOW_CLOSING)); }
}
}
.
public class FrameTwo extends JDialog {
FrameTwo() {
setSize(400,400);
setLocation(900, 250);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
}
You do not need having a boolean value. You can make the frameTwo null when you close it. Then check if it is null and create/show a new dialog. Also since you want to create a new dialog every time (and not hide it), I suggest you instead of frameTwo.dispatchEvent(new WindowEvent(frameTwo, WindowEvent.WINDOW_CLOSING)); to use frameTwo.dispose().
An example:
public class TestFrame extends JFrame {
private JDialog dialog;
public TestFrame() {
super("test");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
JButton button = new JButton("open");
button.addActionListener(e -> {
if (dialog == null) {
dialog = new CustomDialog();
dialog.setVisible(true);
} else {
dialog.dispose();
dialog = null;
}
});
add(button);
setLocationByPlatform(true);
pack();
}
static class CustomDialog extends JDialog {
public CustomDialog() {
super();
add(new JLabel("hello world"));
setLocationByPlatform(true);
pack();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new TestFrame().setVisible(true));
}
}
Related
I have two frames in separate classes (FrameOne and FrameTwo) FrameOne has two buttons. One to open FrameTwo and One shall close FrameTwo. How to open FrameTwo I know. But not how to close from Frame One. How do I code it to make it working? Thanks. (I know that there are similar questions. I red them all. But it didn't gave me the answer. Also GUI guides didn't helped.)
public class Main {
public static void main(String[] args) {
FrameOne frame = new FrameOne();
}
}
FrameOne class:
public class FrameOne extends JFrame implements ActionListener{
private JButton btn1, btn2;
FrameOne () {
setVisible(true);
setSize(400,400);
setLayout(new FlowLayout());
setTitle("Main");
setDefaultCloseOperation(EXIT_ON_CLOSE);
btn1 = new JButton("opens FrameTwo");
btn2 = new JButton("close FrameTwo");
btn1.addActionListener(this);
btn2.addActionListener(this);
add(btn1);
add(btn2);
}
#Override
public void actionPerformed (ActionEvent e) {
if(e.getSource()== btn1) {
FrameTow frameTwo = new FrameTwo();
}
else if(e.getSource()== btn2) ;
// {???.dispose(); }
}
}
`
Frame2 class:
public class FrameTow extends JFrame {
FrameTwo () {
setVisible(true);
setSize(400,400);
setTitle("FrameTwo");
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocation(400, 400);
}
}
Any of the below solutions will work
frameTwo.dispatchEvent(new WindowEvent(frameTwo, WindowEvent.WINDOW_CLOSING));
OR
frameTwo.setVisible(false);
The short answer is modify FrameOne :
private JFrame frameTwo; //introduce a field
#Override
public void actionPerformed (ActionEvent e) {
if(e.getSource()== btn1) {
frameTwo = new FrameTwo(); //use field in action listener
}
else if(e.getSource()== btn2){
frameTwo.dispose(); //use field in action listener
}
}
The longer answer: using a JDialog for the 2nd frame is a better practice:
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
new FrameOne();
}
}
class FrameOne extends JFrame implements ActionListener{
private final JButton btn1, btn2;
private JDialog frameTwo; //introduce a field
FrameOne () {
setSize(400,400);
setLayout(new FlowLayout());
setTitle("Main");
setDefaultCloseOperation(EXIT_ON_CLOSE);
btn1 = new JButton("opens FrameTwo");
btn2 = new JButton("close FrameTwo");
btn1.addActionListener(this);
btn2.addActionListener(this);
add(btn1);
add(btn2);
setVisible(true); //make it visible after construction is completed
}
#Override
public void actionPerformed (ActionEvent e) {
if(e.getSource()== btn1) {
frameTwo = new FrameTwo(); //use field in action listener
}
else if(e.getSource()== btn2){
frameTwo.dispose(); //use field in action listener
}
}
}
class FrameTwo extends JDialog {
FrameTwo() {
setSize(400,400);
setTitle("FrameTwo");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
this.setLocation(400, 400);
setVisible(true); //make it visible after construction is completed
}
}
In the example you show, one can open several instances of FrameTwo. Which one should the second button close?
Assuming you want there to be only one, you could introduce a field in in FrameOne, initially set to null. btn1 would then only open a frame if the field is null, and assign it to the field. Then btn2 can call dispose() on the field (and reset it to null).
Example, based on your attempt:
public class FrameOne extends JFrame implements ActionListener {
private JButton btn1, btn2;
private FrameTwo frameTwo = null;
FrameOne () {
setVisible(true);
setSize(400,400);
setLayout(new FlowLayout());
setTitle("Main");
setDefaultCloseOperation(EXIT_ON_CLOSE);
btn1 = new JButton("opens FrameTwo");
btn2 = new JButton("close FrameTwo");
btn1.addActionListener(this);
btn2.addActionListener(this);
add(btn1);
add(btn2);
}
#Override
public void actionPerformed (ActionEvent e)
{if(e.getSource()== btn1)
{
if (frameTwo == null) {
frameTwo = new FrameTwo();
}
}
else if(e.getSource()== btn2) {
frameTwo.dispatchEvent(new WindowEvent(frameTwo, WindowEvent.WINDOW_CLOSING));
frameTwo = null;
}}}
I am trying to change the background color on click of a radio button, but the second radio button, "bt2" variable is not found by the compiler.
I keep getting this error message:
"cannot find symbol bt1" in the e.getSource()==bt1
Here is my code:
public class ColorChooser extends JFrame implements ActionListener {
public static void main(String[] args) {
new ColorChooser();
}
public ColorChooser() {
super("ColorChooser");
Container content = getContentPane();
content.setBackground(Color.white);
content.setLayout(new FlowLayout());
JRadioButton bt1 = new JRadioButton("Red");
JRadioButton bt2 = new JRadioButton("Yellow");
bt1.addActionListener(this);
bt2.addActionListener(this);
content.add(bt1);
content.add(bt2);
setSize(300, 100);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == bt1)
getContentPane().setBackground(Color.RED);
else
getContentPane().setBackground(Color.YELLOW);
}
}
You should declare your bt1 as instance variable
Like that
public class ColorChooser extends JFrame implements ActionListener
{
private JRadioButton bt1;
...
}
declare bt1 outside of constructor
JRadioButton bt1;
then initialize inside constructor
bt1 = new JRadioButton("Red");
the problem in your code is bt1 is not visible to outside of constructor.it's declared as a block variable.you should declare as instance varible [in class area].
example
public class ColorChooser extends JFrame implements ActionListener {
JRadioButton bt1;//declare
public static void main(String[] args) {
new ColorChooser();
}
public ColorChooser() {
super("ColorChooser");
Container content = getContentPane();
content.setBackground(Color.white);
content.setLayout(new FlowLayout());
bt1 = new JRadioButton("Red");//initializing
JRadioButton bt2 = new JRadioButton("Yellow");
bt1.addActionListener(this);
bt2.addActionListener(this);
content.add(bt1);
content.add(bt2);
setSize(300, 100);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == bt1) {
getContentPane().setBackground(Color.RED);
} else {
getContentPane().setBackground(Color.YELLOW);
}
}
}
My problem is this. I got this two windows that work together and move together.
However if I then open broweser or something that will go in front of the screen, and then I try to show my program in front by clicking it on taskbar, then only one window goes in front. Dialog is in the back and I dont know how to fixe it.
I know there is function ToFront() however I stil dont know how to use it in this scenario.
Instead of creating two JFrames, create a JFrame for your main window and create all other windows as non-modal JDialogs, with the JFrame as their owner. This will cause them to be stacked as a single group; whenever the user brings one to the front, all are brought to the front.
This should solve your problem, as VGR already said... Non-modal Dialog will follow it's parent:
public class FocusMain extends JFrame {
private static FocusMain frame;
private static JDialog dialog;
private JCheckBox checkBox;
private JPanel contentPane;
public static void main(String[] args) {
frame = new FocusMain();
frame.setVisible(true);
dialog = new JDialog(frame);
dialog.setSize(100, 100);
}
public FocusMain() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
setContentPane(contentPane);
checkBox = new JCheckBox("show dialog");
checkBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (checkBox.isSelected()) {
dialog.setVisible(true);
} else {
dialog.setVisible(false);
}
}
});
contentPane.add(checkBox);
}
}
With extended JDialog you will need to pass the parent frame through the constructor and if your constructor looks like this: public ExtendedJDialog(JFrame parentFrame) then you can connect it with it's parent frame with super(parentFrame); as the first line in your constructor...
public class FocusMain extends JFrame {
private static FocusMain frame;
private static FocusDialog dialog;
private JCheckBox checkBox;
private JPanel contentPane;
public static void main(String[] args) {
frame = new FocusMain();
frame.setVisible(true);
dialog = new FocusDialog(frame);
}
public FocusMain() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
setContentPane(contentPane);
checkBox = new JCheckBox("show dialog");
checkBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (checkBox.isSelected()) {
dialog.setVisible(true);
} else {
dialog.setVisible(false);
}
}
});
contentPane.add(checkBox);
}
}
and extended JDialog
public class FocusDialog extends JDialog {
public FocusDialog(JFrame parentFrame) {
super(parentFrame);
setSize(100, 100);
}
}
if you need the dialog to block the parent, use super(parentFrame, true);
Is there any good way to change a JFrame opacity real time. right now i need to restart the window to get the opacity
if (Variables.LoggerOpacity){
if (AWTUtilities.isTranslucencySupported(AWTUtilities.Translucency.TRANSLUCENT)) {
AWTUtilities.setWindowOpaque(Frame, true);
AWTUtilities.setWindowOpacity(Frame, 0.60f);
}
}
When i use
AWTUtilities.setWindowOpacity(Frame, 0.60f);
On a button JCheckBox i won't change the opacity.
Q: How can i change the opacity realtime?
Even if you have set the JFrame to static, you should be able to reference it if your opacity method is within the same class, if it isn't - create a getter method to reference your JFrame and pass that to your function. Here's an example program that executes and the opacity works fine:
public class JFrameOpacityExample extends JFrame {
private static JFrame myFrame;
private static boolean loggerOpacity;
private static JButton button;
public static void main(String[] args) {
myFrame = new JFrame("Test Frame");
myFrame.setSize(400, 400);
myFrame.setVisible(true);
JPanel panel = new JPanel();
button = new JButton("Press me");
button.setBounds(100, 100, 50, 50);
button.setVisible(true);
panel.add(button);
myFrame.add(panel);
loggerOpacity = true;
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
Object src = evt.getSource();
if (src == button && loggerOpacity) {
AWTUtilities.setWindowOpacity(myFrame, 0.40f);
}
}
});
}
}
Add the following command to a frame's constructor. The name of the frame in this example is MyFrame.
jCheckBox1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
AWTUtilities.setWindowOpacity(MyFrame.this, 0.2f);
}
});
I have a button in a java frame that when pressed it reads a value from a text field and uses that string as a port name attempting to connect to a serial device.
If this connection is successful the method returns true if not it returns false. If it returns true I want the frame to disappear. A series of other frames specifed in other classes will then appear with options to control the serial device.
My problem is: the button is connected to an action listener, when pressed this method is invoked. If I try to use the frame.setVisible(true); method java throws a abstract button error because I'm effectively telling it to disappear the frame containing the button before the button press method has exited. Removing the frame.setVisible(true); allow the program to run correctly however I am left with a lingering connection frame that is no longer any use.
How to I get the frame to disappear upon pressing a the button?
package newimplementation1;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
*
* #author Zac
*/
public class ConnectionFrame extends JPanel implements ActionListener {
private JTextField textField;
private JFrame frame;
private JButton connectButton;
private final static String newline = "\n";
public ConnectionFrame(){
super(new GridBagLayout());
textField = new JTextField(14);
textField.addActionListener(this);
textField.setText("/dev/ttyUSB0");
connectButton = new JButton("Connect");
//Add Components to this panel.
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
add(connectButton, c);
connectButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
boolean success = Main.mySerialTest.initialize(textField.getText());
if (success == false) {System.out.println("Could not connect"); return;}
frame.setVisible(false); // THIS DOES NOT WORK!!
JTextInputArea myInputArea = new JTextInputArea();
myInputArea.createAndShowGUI();
System.out.println("Connected");
}
});
}
public void actionPerformed(ActionEvent evt) {
// Unimplemented required for JPanel
}
public void createAndShowGUI() {
//Create and set up the window.
frame = new JFrame("Serial Port Query");
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
//Add contents to the window.
frame.add(new ConnectionFrame());
frame.setLocation(300, 0);
//Display the window.
frame.pack();
frame.setVisible(true);
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentHidden(ComponentEvent e) {
System.out.println("Exiting Gracefully");
Main.mySerialTest.close();
((JFrame)(e.getComponent())).dispose();
System.exit(0);
}
});
}
}
Running your snippet (after removing/tweaking around the custom classes), throws an NPE. Reason is that the frame you'r accessing is null. And that's because it's never set. Better not rely on any field, let the button find its toplevel ancestor and hide that, like in
public void actionPerformed(final ActionEvent e) {
boolean success = true;
if (success == false) {
System.out.println("Could not connect");
return;
}
Window frame = SwingUtilities.windowForComponent((Component) e
.getSource());
frame.setVisible(false); //no problem :-)
}
Your problem is with this line:
frame.add(new ConnectionFrame());
You're creating a new ConnectionFrame object, and so the frame that your button tries to close on is not the same as the one being displayed, and this is the source of your problem.
If you change it to,
//!! frame.add(new ConnectionFrame());
frame.add(this);
so that the two JFrames are one and the same, things may work more smoothly.
But having said that, your whole design smells bad and I'd rethink it in a more OOP and less static fashion. Also, use dialogs where dialogs are needed, not frames, and rather than dialogs consider swapping views (JPanels) via CardLayout as a better option still.
Myself, I'd create a "dumb" GUI for this, one that creates a JPanel (here in my example it extends a JPanel for simplicity, but I'd avoid extending if not necessary), and I'd let whoever is calling this code decide what to do with the information via some control. For e.g.,
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ConnectionPanel extends JPanel {
private JTextField textField;
private JButton connectButton;
private ConnectionPanelControl control;
public ConnectionPanel(final ConnectionPanelControl control) {
super(new GridBagLayout());
this.control = control;
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (control != null) {
control.connectButtonAction();
}
}
};
textField = new JTextField(14);
textField.addActionListener(listener);
textField.setText("/dev/ttyUSB0");
connectButton = new JButton("Connect");
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.fill = GridBagConstraints.HORIZONTAL;
add(textField, c);
c.fill = GridBagConstraints.BOTH;
c.weightx = 1.0;
c.weighty = 1.0;
add(connectButton, c);
connectButton.addActionListener(listener);
}
public String getFieldText() {
return textField.getText();
}
}
Again, something outside of the simple GUI would make decisions on what to do with the text that the textfield contains and what to do with the GUI that is displaying this JPanel:
public interface ConnectionPanelControl {
void connectButtonAction();
}
Also, you will likely do any connecting in a background thread so as to not freeze your GUI, probably a SwingWorker. Perhaps something like this:
import java.awt.event.ActionEvent;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyMain extends JPanel {
public MyMain() {
add(new JButton(new ConnectionAction("Connect", this)));
}
private static void createAndShowGui() {
JFrame frame = new JFrame("My Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new MyMain());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class ConnectionAction extends AbstractAction {
private MyMain myMain;
private ConnectionPanel cPanel = null;
private JDialog dialog = null;
public ConnectionAction(String title, MyMain myMain) {
super(title);
this.myMain = myMain;
}
#Override
public void actionPerformed(ActionEvent e) {
if (dialog == null) {
dialog = new JDialog(SwingUtilities.getWindowAncestor(myMain));
dialog.setTitle("Connect");
dialog.setModal(true);
cPanel = new ConnectionPanel(new ConnectionPanelControl() {
#Override
public void connectButtonAction() {
final String connectStr = cPanel.getFieldText();
new MySwingWorker(connectStr).execute();
}
});
dialog.getContentPane().add(cPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
dialog.setVisible(true);
}
private class MySwingWorker extends SwingWorker<Boolean, Void> {
private String connectStr = "";
public MySwingWorker(String connectStr) {
this.connectStr = connectStr;
}
#Override
protected Boolean doInBackground() throws Exception {
// TODO: make connection and then return a result
// right now making true if any text in the field
if (!connectStr.isEmpty()) {
return true;
}
return false;
}
#Override
protected void done() {
try {
boolean result = get();
if (result) {
System.out.println("connection successful");
dialog.dispose();
} else {
System.out.println("connection not successful");
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
Your code would be much more readable if you named JFrame instances xxxFrame, and JPanel instances xxxPanel. Naming JPanel instances xxxFrame makes things very confusing.
It would also help if you pasted the stack trace of the exception.
I suspect the problem comes from the fact that frame is null. This is due to the fact that the frame field is only initialized in the createAndShowGUI method, but this method doesn't display the current connection panel, but a new one, which thus have a null frame field:
ConnectionFrame firstPanel = new ConnectionFrame();
// The firstPanel's frame field is null
firstPanel.createAndShowGUI();
// the firstPanel's frame field is now not null, but
// the above call opens a JFrame containing another, new ConnectionFrame,
// which has a null frame field
The code of createAndShowGUI should contain
frame.add(this);
rather than
frame.add(new ConnectionFrame());
for Swing GUI is better create only once JFrame and another Top-Level Containers would be JDialog or JWindow(un-decorated by default),
simple example here
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SuperConstructor extends JFrame {
private static final long serialVersionUID = 1L;
public SuperConstructor() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(300, 300));
setTitle("Super constructor");
Container cp = getContentPane();
JButton b = new JButton("Show dialog");
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
FirstDialog firstDialog = new FirstDialog(SuperConstructor.this);
}
});
cp.add(b, BorderLayout.SOUTH);
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
System.exit(0);
}
});
add(bClose, BorderLayout.NORTH);
pack();
setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SuperConstructor superConstructor = new SuperConstructor();
}
});
}
private class FirstDialog extends JDialog {
private static final long serialVersionUID = 1L;
FirstDialog(final Frame parent) {
super(parent, "FirstDialog");
setPreferredSize(new Dimension(200, 200));
setLocationRelativeTo(parent);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setModalityType(Dialog.ModalityType.DOCUMENT_MODAL);
JButton bNext = new JButton("Show next dialog");
bNext.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
SecondDialog secondDialog = new SecondDialog(parent, false);
}
});
add(bNext, BorderLayout.NORTH);
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
setVisible(false);
}
});
add(bClose, BorderLayout.SOUTH);
pack();
setVisible(true);
}
}
private int i;
private class SecondDialog extends JDialog {
private static final long serialVersionUID = 1L;
SecondDialog(final Frame parent, boolean modal) {
//super(parent); // Makes this dialog unfocusable as long as FirstDialog is visible
setPreferredSize(new Dimension(200, 200));
setLocation(300, 50);
setModal(modal);
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
setTitle("SecondDialog " + (i++));
JButton bClose = new JButton("Close");
bClose.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
setVisible(false);
}
});
add(bClose, BorderLayout.SOUTH);
pack();
setVisible(true);
}
}
}
better would be re-use Top-Level Containers, as create lots of Top-Level Containers on Runtime (possible memory lack)