people of the internet.
I want to have a sort of start screen for a game ive been writing. Thus far it features 4 Buttons for each one of the 4 Players that change color on click from red to green and vice versa representing their individual "ready"-status if that makes sense. I used JFrame and JButtons.
Now i want that window to close if every one of those Buttons is currently set to "ready" aka button.getBackground() == Color.GREEN.
Any suggestions as to which EventListeners to use for this/implementation tips/code snippets would be greatly appreciated since my research on Windowclosing on Event didnt bring up much for me.
Thank you in advance and Greetings.
Since you're awaiting and acting on button presses, the most logical listener would be an ActionListener.
Consider making the buttons JToggleButtons, and then in your listener querying each button to see if it is selected (isSelected()) and if so, launch your program. As a side bit, I'd consider making the intro window a JDialog and not a JFrame, either that or making it a JPanel and swapping it out via a CardLayout when necessary.
For example:
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class AreWeReady extends JPanel {
List<AbstractButton> buttons = new ArrayList<>();
private int userCount;
public AreWeReady(int userCount) {
this.userCount = userCount;
ButtonListener buttonListener = new ButtonListener();
for (int i = 0; i < userCount; i++) {
JButton btn = new JButton("User " + (i + 1));
buttons.add(btn);
btn.addActionListener(buttonListener);
add(btn);
}
}
private class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
AbstractButton btn = (AbstractButton) e.getSource();
Color c = Color.GREEN.equals(btn.getBackground()) ? null : Color.GREEN;
btn.setBackground(c);
for (AbstractButton button : buttons) {
if (!Color.GREEN.equals(button.getBackground())) {
// if any button does not have a green background
return; // leave this method
}
}
// otherwise if all are green, we're here
Window win = SwingUtilities.getWindowAncestor(btn);
win.dispose();
// else launch your gui
}
}
private static void createAndShowGui() {
int userCount = 4;
AreWeReady areWeReadyPanel = new AreWeReady(userCount);
JFrame frame = new JFrame("Main Application");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(Box.createRigidArea(new Dimension(400, 300)));
frame.pack();
frame.setLocationByPlatform(true);
JDialog dialog = new JDialog(frame, "Are We Ready?", ModalityType.APPLICATION_MODAL);
dialog.add(areWeReadyPanel);
dialog.pack();
dialog.setLocationByPlatform(true);
dialog.setVisible(true);
// this is only reached when the modal dialog above is no longer visible
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I'm making a program that has a popup menu with two buttons, one of which should close the popup menu, but I have no idea how to do that and googling hasn't gone too well.
I've tried using popup.hide() but then the menu wouldn't come back, despite doing so when I tried just moving the popup. It also required me to put a SuppressWarning in that case and it took a few seconds for it to close at all. Is there any better way of doing it?
I'm not sure what kind of code is relevant, but here's the relevant buttons and their roles in this(I skipped all the creating the GUI parts that didn't seem relevant, everything looks good and I know that the buttons are working):
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
interface CustomButton {
JButton create();
void react(JPopupMenu popup, JFrame frame);
}
class ErrandsButton implements CustomButton {
private JButton errands = new JButton("Errands");
public JButton create() {
return errands;
}
public void react(JPopupMenu popup, JFrame frame) {
errands.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
popup.show(frame, 120, 65);
}
});
}
}
class Test {
static JFrame frame = new JFrame("List");
static CustomButton errands = new ErrandsButton();
static JButton cancelTask = new JButton("Cancel");
static JPopupMenu popup = new JPopupMenu();
static void cancelTask() {
cancelTask.addActionListener(new ActionListener() {
#SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e) {
popup.hide();
}
});
}
public static void main(String args[]) {
createInterface();
cancelTask();
errands.react(popup, frame);
}
static void createInterface() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JPanel popup1 = new JPanel();
JPanel button = new JPanel();
popup1.add(cancelTask);
popup.add(popup1);
frame.add(popup);
button.add(errands.create());
frame.getContentPane().add(BorderLayout.CENTER, button);
frame.setVisible(true);
}
}
Use popup.setVisible(true) and popup.setVisible(false).
frame.add(popup); is the problem. Do not add a JPopupMenu to a Container. Instead, use setComponentPopupMenu.
Alternatively, you could do the work yourself by adding a MouseListener whose mousePressed, mouseReleased and mouseClicked methods call isPopupTrigger and show. (It is vital that you do this in all three of those methods—different platforms have different conditions for showing popup menus.)
But really, using setComponentPopupMenu is easier.
Hello so i started learning java a week back and i basically started making a gui just to see how things work and i found a weird "bug" or i don't exactly understand how things work and it's not even a bug
i have a class called startPanel that makes a panel that is visible from the start
and it asks you as to what you wish to log in admin,user or a guest
this is startPanel:
package library;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/*
* this panel is responsible for the first opening panel and redirects you to your panel
*
*
*/
import javax.swing.*;
public class startPanel extends JFrame {
boolean adminState=false;
boolean userState=false;
boolean guestState=false;
JButton adminBut,userBut,guestBut ;
//start of constructor
public startPanel(){
//frame size,close when pressing x,title,and spawn at middle of the screen
this.setSize(500,500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Welcome guest");
this.setLocationRelativeTo(null);
//making the panel
JPanel panel1 = new JPanel();
//making a label to fill things up it doesn't really do anything
JLabel startLabel = new JLabel("you wan't to log in as...");
//3 buttons for the user to click 1 only and the according frame will show up
adminBut = new JButton("Admin");
userBut = new JButton("User");
guestBut = new JButton("Guest");
//making an event handler for admin only so far just for test purposes
ListenForButton lForButton = new ListenForButton();
adminBut.addActionListener(lForButton);
//adding comps to the panel
panel1.add(startLabel);
panel1.add(adminBut);
panel1.add(userBut);
panel1.add(guestBut);
//adding the panel to the frame
this.add(panel1);
} // end of startPanel constructor
private class ListenForButton implements ActionListener {
#Override
public void actionPerformed(ActionEvent event) {
/*probably not the correct way to do what i want to but just figured this might work
*it only works for admin button if the user presses the adminBut
*it will change the states and with a getter we can change each state
*from main accordingly
*/
if (event.getSource() == adminBut ){
adminState=true;
guestState=false;
userState= false;
}
}
} // end of Listen for button
//all getters for the states
public boolean getAdminState(){
return adminState;
}
public boolean getUserState(){
return guestState;
}
public boolean getGuestState(){
return userState;
}
}
this is main :
package library;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class mainLibrary {
public static void main(String[] args) {
adminPanel adminP = new adminPanel();
userPanel userP = new userPanel();
startPanel gui = new startPanel();
gui.setVisible(true);
while(true){
System.out.println(gui.getAdminState());
if (gui.getAdminState() == true) {
gui.setVisible(false);
userP.setVisible(true);
}
}
the problem now is that if i remove System.out.println(gui.getAdminState());
this does not work it doesn't even get in the if at all if it's false at start
if i don't remove it works correctly :/
so what is going on
this is adminPanel for the adminPanel if it matters
package library;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class adminPanel extends JFrame {
//start of adminPanel constructor
public adminPanel(){
//frame size,close when pressing x,title,and spawn at middle of the screen
this.setSize(500,500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Admin panel area");
this.setLocationRelativeTo(null);
JPanel panel1 = new JPanel();
this.add(panel1);
} //end of admin constructor
}
This is not a good GUI design. Never use such active loop.
Remarks: use standard naming convention (uppercase/lowercase), and never call a frame a panel (this is too confusing).
A better design would be to have references to Panels to be activated in the startPanel and setting appropriate property reacting to button actions. Something like:
class StartFrame extends JFrame implements ActionListener {
private JFrame adminFrame;
private JFrame userFrame;
...
// add construtor to initialize adminFrame and userFrame appropriately
...
public void actionPerformed(ActionEvent e) {
if (e.getSource() == adminBut) {
this.setVisible(false);
adminFrame.setVisible(true);
}
if (e.getSource() == userBut) {
this.setVisible(false);
userFrame.setVisible(true);
}
}
}
Is it possible to add more than 1 mouselistener to a JButton? You know when I click on the button it should change color and text, and do something (e.g system.out.println), and when I click it again it should go back to the previous state, and print something else.
What I've tried:
JButton b = new JButton("First");
b.setBackground(Color.GREEN);
b.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
b.setBackground(Color.RED);
b.setText("Second");
System.out.println("You've clicked the button");
}
if(b.getModel.isPressed){
b.setBackground(Color.GREEN);
b.setText("Second");
System.out.println("You're back");
}
The problem is that the button doesn't go back to the previous state with the color (green) and text, and I don't how to handle that.
First of all, you shouldn't be using a MouseListener to do these things, because a better listener, ActionListener, was built specifically to be used with JButtons and similar entities to notify programs that a button has been pressed.
Having said that, sure you can add multiple ActionListeners (or MouseListeners) to a JButton, or you can have an ActionListener change its behaviors depending on the state of the program (usually meaning the values held by fields of the class).
A problem with your code and question is that I don't see when you expect or want the button to change its color back to green. If after a certain period of time, then have your ActionListener start a Swing Timer that changes the button's color back to green after x milliseconds.
Edit: I see, you want to toggle color -- then use a boolean field that you toggle or check the button's current color and base the listener's response based on that color.
example
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class ToggleColor extends JPanel {
public ToggleColor() {
JButton button = new JButton(new MyButtonAction());
button.setBackground(Color.GREEN);
add(button);
}
private static void createAndShowGui() {
ToggleColor mainPanel = new ToggleColor();
JFrame frame = new JFrame("ToggleColor");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class MyButtonAction extends AbstractAction {
// !! parallel arrays being used below -- avoid if possible
private static final String[] TEXT = {"First", "Second", "Third"};
private static final Color[] COLORS = {Color.GREEN, Color.RED, new Color(108, 160, 220)};
private int index = 0;
public MyButtonAction() {
super(TEXT[0]);
}
#Override
public void actionPerformed(ActionEvent e) {
index++;
index %= TEXT.length;
putValue(NAME, TEXT[index]);
Component c = (Component) e.getSource();
c.setBackground(COLORS[index]);
}
}
This uses an AbstractAction class which is like an ActionListener but on "steroids"
You should only register one lister, but that listener will maintain some state regarding the number for mouse clicks. A simple if/else block will change the actions and change the text on the button label.
I have 2 jframes, 1 is kinda like the main menu, i want an attribute to change in the level jframe when a button is pressed so i tried:
SpeelVeld frame = new SpeelVeld();
frame.level = 1;
System.out.println(frame.level);
I used the sout to see what really happens because it wasnt working, but i see that the level goes from 0 to 1 back to 0 and goes on and on, does someone know why and how to fix?
SpeelVeld frame = new SpeelVeld();
frame.setBounds(0,0,519,591);
frame.setLocationRelativeTo(null);
frame.getContentPane().setBackground(Color.WHITE);
frame.setTitle("RWINA");
frame.setVisible(true);
frame.setLevel(1);
this is in the main method of my original GameProject file.
How can i make a jdialog
I have 2 jframes, 1 is kinda like the main menu,
You shouldn't use 2 JFrames for this. The dependent sub-window, likely your main menu window, should in fact be a JDialog, probably a non-modal dialog from the looks of it.
I want an attribute to change in the level jframe when a button is pressed so i tried:
SpeelVeld frame = new SpeelVeld();
frame.level = 1;
System.out.println(frame.level);
and here's a big problem. Understand that in this code, you're creating a new SpeelVeld object, the stress being on the word new. Changing the state of this object will have no effect on the other SeelVeld object that is currently being displayed. Do do that, your second window will need a valid reference to the displayed SeelVeld object. How to do this will depend all on code not yet shown, but often it can be done simply by passing in the displayed SpeelVeld object into the main menu object by use of a constructor parameter or setter method.
For example:
import java.awt.Dialog.ModalityType;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
// JPanel for our main GUI
public class SpeelVeldFoo {
private static void createAndShowGui() {
// JPanel used by the main JFrame
SpeelVeldPanel speelVeldPanel = new SpeelVeldPanel();
// JPanel used by the main menu JDialog. Pass the above into it
MainMenuPanel mainMenuPanel = new MainMenuPanel(speelVeldPanel);
// create your JFrame
JFrame frame = new JFrame("Speel Veld");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(speelVeldPanel); // add the JPanel
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
// create your non-modal JDialog
JDialog menuDialog = new JDialog(frame, "Main Menu", ModalityType.MODELESS);
menuDialog.add(mainMenuPanel); // add the JPanel that holds its "guts"
menuDialog.pack();
menuDialog.setLocationByPlatform(true);
menuDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
#SuppressWarnings("serial")
class SpeelVeldPanel extends JPanel {
private int level = 1; // simple example just has a level int
private JLabel levelLabel = new JLabel("1"); // and displays it in a JLabel
public SpeelVeldPanel() {
add(new JLabel("Level:"));
add(levelLabel);
int ebGap = 50;
setBorder(BorderFactory.createEmptyBorder(ebGap, 2 * ebGap, ebGap, 2 * ebGap));
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
// whenever level is changed, update the display
this.level = level;
levelLabel.setText(String.valueOf(level));
}
}
// class for the JPanel held by the JDialog
#SuppressWarnings("serial")
class MainMenuPanel extends JPanel {
private JSpinner levelSpinner = new JSpinner(new SpinnerNumberModel(1, 1, 5, 1));
private SpeelVeldPanel speelVeldPanel = null; // reference to the main GUI
// note the parameter.... you pass in the displayed main GUI so you can
// change it
public MainMenuPanel(final SpeelVeldPanel speelVeldPanel) {
this.speelVeldPanel = speelVeldPanel; // set the field
// respond when the spinner's data changes
levelSpinner.addChangeListener(new LevelListener());
add(new JLabel("Set the Speel Veld's level:"));
add(levelSpinner);
int ebGap = 10;
setBorder(BorderFactory.createEmptyBorder(ebGap, ebGap, ebGap, ebGap));
}
private class LevelListener implements ChangeListener {
#Override
public void stateChanged(ChangeEvent e) {
// when the spinner's data changes
int level = (int) levelSpinner.getValue(); // get the data
speelVeldPanel.setLevel(level); // and send it to the main GUI
}
}
}
You'll note that I don't like extending JFrame or JDialog if I can avoid it. My feeling is that one can paint oneself into a corner by having your class extend JFrame, forcing you to create and display JFrames, when often more flexibility is called for. More commonly your GUI classes will be geared towards creating JPanels, which can then be placed into JFrames or JDialogs, or JTabbedPanes, or swapped via CardLayouts, wherever needed. This will greatly increase the flexibility of your GUI coding.
You probably want the JFrame to be the top-level container, then have a JPanel that holds your menu. The menu could be whatever you want, I'm using a JTextArea. Then, you need a JButton for the JPanel or JFrame that when pressed, changes the text in the JTextArea. Here is an implementation that you could work from. I'm using the ActionEvent as the trigger for when to mess with the JTextArea:
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.JTextArea;
public class SimpleSwing {
public static void main(String[] args) {
JFrame mainFrame = new JFrame();
JPanel mainMenuPanel = new JPanel();
JTextArea textAttribute = new JTextArea("Original Text");
JButton changeAttributeButton = new JButton("Change Attribute");
changeAttributeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
textAttribute.setText("Whatever new text you want");
}
});
mainMenuPanel.add(textAttribute);
mainMenuPanel.add(changeAttributeButton);
mainFrame.add(mainMenuPanel);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setSize(500, 500);
mainFrame.setVisible(true);
}
}
When I am trying to hide or close popup dialog invoked as a modal, the components disappears as they should, but the grey screen that indicates modality of the window is still visible, until the fist mouse click event at this window area.
WebPopup darkenScreen = new WebPopup(PopupStyle.gray);
ContructPopUP(darkenScreen);
darkenScreen.showPopupAsModal(this);
And popup settings method :
private void ContructPopUP(WebPopup darkenScreen)
{
final JFrame mFrame = this;
final WebTextField inputTime = new WebTextField("(sekundy)");
darkenScreen.setLayout(new GridLayout(3, 1));
darkenScreen.add(new WebLabel("Podaj czas : "));
darkenScreen.add(inputTime);
darkenScreen.add(new WebButton(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
int secTime = Integer.parseInt(inputTime.getText());
if (secTime > 0 && secTime < 7200)
{
Connection.TurnOff(secTime);
System.out.println("clicked!");
}
darkenScreen.hidePopup();
}
}));
}
When invoking as ordinary popup everything disappears as indented. I've tried to close it in many ways but none of them worked.
Before clicking button and executing popup.hide :
after doing it :
Assuming you are using the WebLaF library, I think your problem might be caused by the PopupLayer.hidePopup method. This method is called by the WebPopup.hidePopup method and should hide the modal popup, but as you noticed, the gray layer does not disappear. If you look at PopupLayer.hideAllPopups, all popups are removed in this method and the popup layer is made invisible. I do not have experience with the WebLaF library and it feels hackish, but you might be able to solve your problem by hiding the popup layer yourself:
import com.alee.laf.button.WebButton;
import com.alee.laf.label.WebLabel;
import com.alee.laf.text.WebTextField;
import com.alee.managers.popup.PopupStyle;
import com.alee.managers.popup.WebPopup;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class ModalWebPopup {
public static void main(final String[] arguments) {
new ModalWebPopup().launchGui();
}
private void launchGui() {
final JFrame frame = new JFrame("Stack Overflow: modal WebPopup");
frame.setBounds(100, 100, 800, 600);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
final JPanel panel = new JPanel();
final JButton button1 = new JButton("Show a modal WebPopup");
panel.add(button1);
frame.getContentPane().add(panel);
button1.addActionListener(actionEvent -> {
final WebPopup darkenScreen = new WebPopup(PopupStyle.gray);
constructPopup(darkenScreen);
darkenScreen.showPopupAsModal(frame);
});
frame.setVisible(true);
}
private void constructPopup(final WebPopup darkenScreen) {
//final JFrame mFrame = this;
final WebTextField inputTime = new WebTextField("(sekundy)");
darkenScreen.setLayout(new GridLayout(3, 1));
darkenScreen.add(new WebLabel("Podaj czas : "));
darkenScreen.add(inputTime);
darkenScreen.add(new WebButton(actionEvent -> {
int secTime = Integer.parseInt(inputTime.getText());
if (secTime > 0 && secTime < 7200) {
//Connection.TurnOff(secTime);
System.out.println("clicked!");
}
System.out.print("Hide the modal WebPopup ");
// Normal way to hide the popup:
//darkenScreen.hidePopup();
System.out.println("by making the parent of the WebPopup invisible.");
// Alternative way to hide the popup:
darkenScreen.getParent().setVisible(false);
// Compare the PopupLayer.hideAllPopups and PopupLayer.hidePopup methods
// for more details.
}));
}
}