This question already has an answer here:
How to keep and remove multiple graphic objects in java swing applications?
(1 answer)
Closed 7 years ago.
Pressing Button 1 puts a box in pane2, pressing Button 2 puts another box up, but the 1st one disappears.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GuiDemo extends JPanel implements ActionListener {
JFrame pane1 = new JFrame("pane1");
JFrame pane2 = new JFrame("pane2");
public GuiDemo(){
pane1.setSize(400,400);
pane1.setLocation(100, 100);
pane2.setSize(400,400);
pane2.setLocation(800, 100);
pane1.setVisible(true);
pane2.setVisible(true);
pane1.setLayout(new FlowLayout());
JButton b1 = new JButton("Button 1");
JButton b2 = new JButton("Button 2");
pane1.add(b1);
pane1.add(b2);
b1.setVisible(true);
b1.addActionListener(this);
b2.setVisible(true);
b2.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
switch (e.getActionCommand()){
case "Button 1":{
placeCircle pc = new placeCircle(0);
pane2.add(pc);
pane2.setVisible(true);
break;}
case "Button 2":{
placeCircle pc = new placeCircle(1);
pane2.add(pc);
pane2.setVisible(true);
break;}
}
}
public static void main(String[] args) {
new GuiDemo();
}
}
a is passed as the offset beteween box 1 and box 2.
class placeCircle extends JPanel{
int a;
public placeCircle(int a){
this.a = a;
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawRect(20+a*100, 20, 20, 20);
}
}
but my main question is, should I be using painComponent?
Pressing Button 1 puts a box in pane2, pressing Button 2 puts another box up, but the 1st one disappears.
The default layout manager for a JFrame is the BorderLayout. You are adding components to the CENTER of the BorderLayout, but only a single components can be displayed at one time so you only see the last one.
should I be using painComponent?
Yes, but all of your painting needs to be done in a single component in the paintComponent() method of that component.
So basically you need to keep a List of Objects to paint. Then the paintComponent() method iterates through the list and paints each object.
Check out the Draw On Component example from Custom Painting Approaches. For an example of this approach.
Related
I am attempting to add another checkbox to this program but for some reason it will not display when I run the program. Only the check box for the blue pill displays. I have attempted to add a couple things or change the way the program is structured, but nothing I have done so far has helped.
Code Below:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CMIS242WK4DonnersonAReply {
static JCheckBox red;
static JCheckBox blue;
static JButton button;
public CMIS242WK4DonnersonAReply() {
button = new JButton("submit"); // Creates submit button
widget
ButtonHandler listener = new ButtonHandler(); // Creates the handler for the button.
button.addActionListener((ActionListener) listener); // adds the handler to the button widget
JPanel content = new JPanel(); // "container"
content.setLayout(new BorderLayout());
content.add(button, BorderLayout.PAGE_END);// places submit button at the bottom of panel.
JLabel label = new JLabel("At last. Welcome, Neo. As you no doubt have guessed, I am Morpheus. This is your last chance. After this there is no turning back."); // Label in frame.
content.add(label, BorderLayout.NORTH);// places label at the top of the screen.
//Creating Check Boxes
JCheckBox red = new JCheckBox("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
red.setBounds(100,100, 50,50);
content.add(red);
JCheckBox blue = new JCheckBox("You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe. ");
blue.setBounds(100,100, 50,50);
content.add(blue);
//Adding Frame
JFrame window = new JFrame("Matrix Monologue"); // JFrame = Window
window.setContentPane(content);
window.setSize(750,200); // Length, Height
window.setLocation(200,200); // X/Y "OF THE ENTIRE FRAME" Not the contents
window.setVisible(true); // makes window visible
}
// Method handles what happens when button is pressed.
private static class ButtonHandler implements ActionListener{
public void actionPerformed1(ActionEvent e) {
// Checks if which pill was selected and responds to user depending on their action.
if (red.isSelected() == true) {
System.out.println("Follow me");
System.out.println();
}
if (blue.isSelected() == true) {
System.out.println("Very Well, You may go back to your world");
System.out.println();
}
else
System.out.println("You must make a choice for what pill you will take");
System.exit(0); //closes program
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
// Main/driver method that runs everything.
public static void main(String[] args) {
CMIS242WK4DonnersonAReply matrixMonologue= new CMIS242WK4DonnersonAReply();
}
}
Any pointers?
When you're stuck on a problem, it never hurts to go back and consult the documentation.
You'll find information like this:
A border layout lays out a container, arranging and resizing its
components to fit in five regions: north, south, east, west, and
center. Each region may contain no more than one component, and is
identified by a corresponding constant: NORTH, SOUTH, EAST, WEST, and
CENTER. When adding a component to a container with a border layout,
use one of these five constants...
When you add your button, you do this:
content.add(button, BorderLayout.PAGE_END);
But then, when it's time to add checkboxes, you do this:
content.add(red);
...
content.add(blue);
Are you seeing what's missing? My bet is that you only see the blue checkbox because you added it on top of (or simply displaced) the red checkbox. Remember, the doc says "Each region may contain no more than one component..."
Try specifying the region of your BorderLayout where you want to see each checkbox.
If you want them to appear in the same region, put them in a JPanel of their own and lay them out at NORTH and SOUTH or EAST and WEST and then add that checkbox panel to your content panel in the region you want them to appear.
I feel that you need some guidance with your Swing programming. I have rewritten your CMIS242WK4DonnersonAReply class. Code is below. But first some comments about the code in your question.
JCheckBox red = new JCheckBox("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
You have created a local variable which is hiding the class member. Hence static JCheckBox red; remains null and consequently the following if statement will throw NullPointerException.
if (red.isSelected() == true) {
By the way, the == true is not necessary. The following is sufficient.
if (red.isSelected()) {
Now another point.
red.setBounds(100,100, 50,50);
Since you are using a layout manager, namely BorderLayout, method setBounds will be ignored. The layout manager determines where to place the component on the screen.
window.setContentPane(content);
By default, the content pane of JFrame is a JPanel with BorderLayout so no need to replace the default content pane.
private static class ButtonHandler implements ActionListener
No need to create a nested class. Simply make class CMIS242WK4DonnersonAReply implement the ActionListener interface.
System.out.println("Follow me");
I don't think it's a good idea to involve the console in a GUI application. I would use JOptionPane to display a message to the user.
static JCheckBox blue;
I think that JRadioButton is more appropriate than JCheckBox in your situation.
Here is my code.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
public class CMIS242WK4DonnersonAReply implements Runnable, ActionListener {
private JButton button;
private JRadioButton blue;
private JRadioButton red;
private JFrame window;
#Override
public void actionPerformed(ActionEvent event) {
if (red.isSelected()) {
JOptionPane.showMessageDialog(window, "Follow me.");
}
else if (blue.isSelected()) {
JOptionPane.showMessageDialog(window, "Very Well, You may go back to your world");
}
else {
JOptionPane.showMessageDialog(window, "You must make a choice for what pill you will take");
}
}
#Override
public void run() {
createAndShowGui();
}
private void createAndShowGui() {
window = new JFrame("Matrix Monologue");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("At last. Welcome, Neo. As you no doubt have guessed, I am Morpheus. This is your last chance. After this there is no turning back."); // Label in frame.
window.add(label, BorderLayout.PAGE_START);
window.add(createCheckBoxes(), BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
button = new JButton("submit");
button.addActionListener(this);
buttonPanel.add(button);
window.add(buttonPanel, BorderLayout.PAGE_END);
window.setSize(750,200); // Length, Height
window.setLocation(200,200); // X/Y "OF THE ENTIRE FRAME" Not the contents
window.setVisible(true); // makes window visible
}
private JPanel createCheckBoxes() {
JPanel panel = new JPanel();
BoxLayout layout = new BoxLayout(panel, BoxLayout.PAGE_AXIS);
panel.setLayout(layout);
red = new JRadioButton("You take the red pill, you stay in Wonderland and I show you how deep the rabbit hole goes.");
blue = new JRadioButton("You take the blue pill, the story ends, you wake up in your bed and believe whatever you want to believe.");
ButtonGroup grp = new ButtonGroup();
grp.add(red);
grp.add(blue);
panel.add(red);
panel.add(blue);
return panel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new CMIS242WK4DonnersonAReply());
}
}
Here is how the app looks when I run it.
Basically what I am searching for is how to make a button's text and functionality change dynamically depending on the situation. For example I am working on a card game where I save selected cards of the user into an array, and I want it so when 1 or more card is selected, the button's name should be Play, and have the player to play that move, while if 0 cards are selected, the button's name should be Pass so on click the user can pass the turn. The button's text should change itself only depending on the number of selected cards, and not on click etc.
Image
The functionality part is easy, you just add action listener to the button as usual, but do something different depend on the number of selected cards.
As for the button text, you should have a method like updateButtonText() which assign different text to the button based on currently selected cards. And you call this method at start to assign the initial text.
Then whenever you detected user has change in card selection, you simply call updateButtonText() again to have the button text updated.
You could create two separate buttons where each has its own ActionListener and change which buttons are visible depending on the situation:
JButton pass_button = new JButton("Pass");
JButton play_button = new JButton("Play");
// Loop this code on separate thread or use callback
if(num_cards_selected == 0 && panel.contains(play_button)) {
panel.remove(play_button);
panel.add(pass_button);
} else if(num_cards_selected > 0 && panel.contains(pass_button)) {
panel.remove(pass_button);
panel.add(play_button);
}
Or you could check the state of the card game and have an ActionListener that is tied to the JButton act according to the condition:
JButton button = new JButton("");
// Loop this code on separate thread or use callback
if(num_cards_selected == 0)
button.setText("Pass");
else
button.setText("Play");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(num_cards_selected == 0)
pass();
else
play();
}
});
What you need is :
check the number of cards selected
add action listener to button and change the outcome of the action as per the cards selection
Code example :
check all the comments provided in the code
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class cardGame implements ActionListener {
int cards[];
JButton b1;
JFrame f;
JPanel panel;
public cardGame(int n) { // taking input n as how many cards have been
// selected
cards = new int[n]; // number of cards selected
f = new JFrame(); // creating a jFrame
f.setPreferredSize(new Dimension(400, 400)); // size of JFrame
panel = new JPanel(); // creating a panel
b1 = new JButton("click"); // creating a JButton
b1.setSize(20, 30); // setting size of JButton
b1.addActionListener(this); // adding action listener
panel.add(b1); // adding JButton to panel
f.add(panel); // adding panel to JFrame
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // setting default
// close operation
f.setVisible(true); // set JFrame visible
}
#Override
public void actionPerformed(ActionEvent e) {
if (cards.length >= 3) { // if cards are more than or equal to 3
// setBackground color blue
b1.setText("Play");
panel.setBackground(Color.blue);
}
// you can change the functionality as per your need
else {// else setBackground color green
b1.setVisible(true);
b1.setText("pass");
panel.setBackground(Color.green);
}
}
public static void main(String[] args) {
new cardGame(2); // providing input as number of cards selected try
// giving 2 and 3
}
}
I am making a GUI for a game, and I have a splash screen which I created using JFrame. I have a button which says play and what I want after that to happen is when I press play, I want to switch to another JFrame, which is going to have different stuff in it. However, I do not want the window to close and open another one, I want it to just switch from one frame to another frame.
I have no experience on GUI, if you have any information that would help it would be greatly appreciated.
Here is an example:
import javax.swing.JFrame;
import javax.swing.JButton;
public class Test {
public static void main(String[] args) {
JFrame f = new JFrame();
f.setBounds(10, 10, 500, 200);
JButton b1 = new JButton("b1");
b1.addActionListener((c) -> {
buttonPressed(f);
});
f.setContentPane(b1);
f.setVisible(true);
}
private static void buttonPressed(JFrame f) {
JButton b2 = new JButton("b2");
f.setContentPane(b2);
f.revalidate();
}
When b1 is pressed, the content pane for the frame is replaced with a new button. the revalidate() call is needed in order for the UI to refresh after the change.
I am trying to create a basic game menu for a game right now. I am just testing out the menu for now, and most of the options I wrote are just to test out whether the menu actually works or not. So I have a Menu class and a OptionPanel class as well.
Here is the Menu Class:
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
public class Main extends JFrame {
JPanel cardPanel;
public Main(String title) {
super(title);
setBounds(100, 100, 800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
cardPanel = new JPanel();
CardLayout cl = new CardLayout();
cardPanel.setLayout(cl);
OptionPanel panel1 = new OptionPanel(this);
Board panel2 = new Board();
Rules panel3 = new Rules();
cardPanel.add(panel1,"1");
cardPanel.add(panel2,"2");
cardPanel.add(panel3,"3");
add(cardPanel);
setVisible(true);
}
public static void main(String[] args)
{
Main w = new Main("AP Animation Demo");
}
public void changePanel() {
((CardLayout)cardPanel.getLayout()).next(cardPanel);
requestFocus();
}
}
And here is my Option Panel class:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class OptionPanel extends JPanel implements ActionListener {
Main w;
public OptionPanel(Main w) {
this.w = w;
JButton button = new JButton("Press me!");
button.addActionListener(this);
add(button);
JButton button2 = new JButton("Game rules");
button2.addActionListener(this);
add(button2);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
setBackground(Color.BLACK);
}// Call JPanel's paintComponent method to paint the background
public void actionPerformed(ActionEvent e) {
w.changePanel();
}
}
How do I make it so when the menu pops up, I can click on one button that leads to the game, and when clicking on another button, get linked to another screen. I think it has something to do with the actionPerformed thing, so I tried adding if (e.getSource == button) and stuff like that, but it could not find any button variable. Any advice/feedback?
If you want the actionPerformed() method to be able to access a button variable, then the variable has to have an instance scope (or static, less preferable almost always). Referring to it in the method as you have it written won't work because the button variable is local to the constructor.
The suggestion in the comments is to make a separate ActionListener for each button; you only need to use the if (e.getSource() == button) if the one actionPerformed() method is getting called for multiple buttons. The difference between these is a little much for a SO answer; you can get a tutorial on action listeners in the Java tutorials at Oracle.
The way you have started above suggests you are going to use the OptionPanel as a single action listener for all buttons, and therefore it needs to test which button invoked it. If instead you have a separate action listener for each button, then it knows which button invoked it and doesn't need to test.
Try looking up "anonymous inner classes" as they relate to action listeners in Java.
There is a JCheckBox called "one" and another called "two". There is also a JScrollPane called "sp". In it is a JTextArea. The point of the checkboxes is to hide and show certain parts of the program. I simplified the program and here I tediously explain what is supposed to happen just to make sure you understand the program.
This is supposed to happen:
Initially only one is visible and it is unselected. Whenever one is selected, two should be set visible. Whenever two is selected, sp should be set visible. When a checkbox is unselected, the corresponding component is set invisible. However, when one is unselected, sp is also set invisible. (one controlls two and sp).
The problem:
When one is selected, two is visible. But when two is selected, sp is not visible (it should be). When one is unselected while two is selected, two is invisible (this should happen). But when one is selected, two is visible and all of a sudden sp is now visible. After this point, the program functions as it was intended.
This however works with other JComponents (in replace of the JScrollPane).
What could be wrong?
package tests;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Checkboxscrollpane extends JPanel {
private JCheckBox one, two;
private JScrollPane sp;
private Checkboxscrollpane() {
Listener listener = new Listener();
one = new JCheckBox();
one.addActionListener(listener);
add(one);
two = new JCheckBox();
two.addActionListener(listener);
add(two);
sp = new JScrollPane(new JTextArea("hello"));
add(sp);
one.setVisible(true);
two.setVisible(false);
sp.setVisible(false);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
one.setLocation(50, 50);
two.setLocation(70, 70);
sp.setLocation(90, 90);
}
private class Listener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == one) {
two.setVisible(one.isSelected());
}
sp.setVisible(one.isSelected() && two.isSelected());
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(300, 200);
frame.add(new Checkboxscrollpane());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
You should revalidate the Checkboxscrollpane panel.
But you shouldn't set location of components on every paint event:
setLayout(null);
one.setSize(100, 20);
two.setSize(100, 20);
sp.setSize(100, 20);
one.setLocation(50, 50);
two.setLocation(70, 70);
sp.setLocation(90, 90);
And remove the public void paintComponent(Graphics g) { method.