Setting JScrollPane visible/invisible via JCheckBox not working - 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.

Related

Java program wont react till the window gets resized

I have a simple java program and when I run it, using eclipse, it displays the 3 JButtons that I have set to the layout. The buttons are set to change the alignment of the layout. So you press left to align left and right to align right and center to align center.
While the buttons do this, the alignment doesn't change in the window till you resize it.
Ive tried updating both the jdk and eclipse and didnt make a difference and I cant see a problem with the code itself.
Anyone know why this is?
import javax.swing.JFrame;
public class Main {
public static void main(String []args){
Layout_buttonsAndActionEvents layout = new Layout_buttonsAndActionEvents();
layout.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
layout.setSize(300,300);
layout.setVisible(true);
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Layout_buttonsAndActionEvents extends JFrame {
private static final long serialVersionUID = 1L;
private JButton leftButton;
private JButton rightButton;
private JButton centerButton;
private FlowLayout layout;
private Container container;
public Layout_buttonsAndActionEvents(){
super("The Title");
layout = new FlowLayout();
container = new Container();
setLayout(layout);
leftButton = new JButton("Left");
add(leftButton);
//Align to the left
leftButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.LEFT);
layout.layoutContainer(container);
}
});
centerButton = new JButton("Center");
add(centerButton);
//Align to the right
centerButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.CENTER);
layout.layoutContainer(container);
}
});
rightButton = new JButton("Right");
add(rightButton);
//Align to the right
rightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent event){
layout.setAlignment(FlowLayout.RIGHT);
layout.layoutContainer(container);
}
});
}
}
Because you are adding the buttons to the JFrame's content
pane ( via the add() method which is really a call to
getContentPane().add() under the covers ) you need to call revalidate() on
the content pane.
In the three action listeners, change:
layout.setAlignment(FlowLayout.XXX);
layout.layoutContainer(container);
to:
layout.setAlignment(FlowLayout.XXX);
getContentPane().revalidate();
Also, you can remove all references to the variable named 'container' as it does nothing in your example.
When you resize a JFrame, it is re-validated with the new size and layout. Similarly, you must validate the and repaint the frame after adding the altered layout to apply a visual difference.
Make sure to call these methods in this order after altering the layout:
setLayout(layout);
repaint();
revalidate();

I'm trying to place multiple paintComponents in a JFrame. [duplicate]

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.

Put one JPanel onto another JPanel from a different Java class

I'm developing Java Swing application. My application has two Java classes. Inside class1.java, I include JFrame, JButton and JPanel (panel1). When I click the button I want to hide panel1 and should be shown panel2 of class2.java. I tried this method in button actionPerformed method of class1.java. But it was not working.
class2 pnl = new class2();
this.remove(panel1);
this.add(pnl);
this.validate();
this.repaint();
Analysis
You simply want the JComponents to be displayed on the JFrame. We can achieve this by using a single JPanel, but adding and removing the JComponents from it, during the JButton's action listener.
Without looking at your actual code, it is better to make a manageable way to reach code and instantiated Objects. The code listed below, creates a nice and manageable way to do so.
Achieving This
The entire class is listed below with comments for explanations.
package swing;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MultiPaneledFrame {
JFrame frame = new JFrame();
JPanel window = new JPanel();
// As you can see, we create an array containing all your JComponents.
// We have two of these, to simulate multiple JPanel's.
List<JComponent> window1Contents = new ArrayList<JComponent>();
List<JComponent> window2Contents = new ArrayList<JComponent>();
// NOTE: The above Lists can instead be stuck in their own class like asked for,
// and instantiated on Class invocation.
JButton goto2 = new JButton("Goto Panel 2");
JButton goto1 = new JButton("Goto Panel 1");
int panelToShow = 0; // 0 - First "panel".
// 1 - Second "panel".
// Main method of class. Change 'Multi_Paneled_Frame' to the name of your Class.
public MultiPaneledFrame() {
// Execute anything else you want here, before we start the frame.
window1Contents.add(goto2);
window2Contents.add(goto1);
// Here is where I personally am setting the coordinates of the JButton's on the JPanel.
goto2.setPreferredSize(new Dimension(200, 100));
goto1.setPreferredSize(new Dimension(200, 100));
//goto2.setBounds(5, 5, 150, 30); < Used for 'null' layout.
//goto1.setBounds(5, 5, 150, 30); < Used for 'null' layout.
goto2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addComponents(panelToShow = 1);
}
});
goto1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
addComponents(panelToShow = 0);
}
});
initialiseFrame();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MultiPaneledFrame();
}
});
}
private void initialiseFrame() {
frame.setSize(600, 400); // Change it accordingly.
// Optional
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setResizable(false);
// Needed
frame.setVisible(true);
frame.add(window);
window.setLayout(new BorderLayout()); // Assuming your using a BorderLayout.
//window.setLayout(null); < Uses 'null' layout.
addComponents(panelToShow);
// I always like to make sure that everything is on the frame nicely.
frame.repaint();
frame.validate();
}
private void addComponents(int panelNo) {
if (panelNo == 0) {
for (JComponent component : window1Contents) {
window.removeAll(); // We're removing everything that it contains and replacing it...
window.revalidate();
window.add(component, BorderLayout.CENTER);
//window.add(component); < Uses 'null' layout.
// Since we are using the first panel, we are adding
// everything from the first list of components to the window...
}
} else {
for (JComponent component : window2Contents) {
window.removeAll(); // We're removing everything that it contains and replacing it...
window.revalidate();
window.add(component, BorderLayout.CENTER);
//window.add(component); < Uses 'null' layout.
// Since we are using the second panel, we are adding
// everything from the second list of components to the window...
}
}
// Refreshes the frame.
frame.repaint();
frame.validate();
}
}
Conclusion
Although there are countless ways to achieve something like this, the way I have given, is semi-efficient, and very flexible. Feel free to edit the code, or drop a question if you have any concerns, and I will be happy to respond.
PS: This code was tested and works on a Macbook Air running OS X 10.11 and Java Version 8 Update 65.
CardLayout should be your solution. In this tutorial they show how to switch from panel to another one by selecting a value in ComboBox.
A little bit of explanation for the CarLayout:
The CardLayout lets you place different panel on top of each other but shows only one at the time. With your code, you select the one you want to display.
Initialisation:
this.setLayout(new CardLayout());
class1 pnl1 = new class1();
class2 pnl2 = new class2();
this.add(pnl1, "PANEL1");
this.add(pnl2, "PANEL2");
On your button actionPerformed:
CardLayout cl = (CardLayout)(this.getLayout());
cl.show(this, "PANEL2");

Add drawing to a Panel

This should be simple enough, yet I can't make it work.
I have two classes, one which should draw a circle, and the other which sets up a frame and panel with a button. On clicking the button, a circle should appear on the frame. I am confused as to why it doesn't appear. It's probably something very simple, sorry.
package ballsOnPane;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Display implements ActionListener{
private JFrame frame;
private JPanel panel;
private JButton button;
public static void main(String[] args) {
Display display = new Display();
}
public Display() {
frame = new JFrame();
frame.setSize(800, 500);
frame.setTitle("Show balls");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
panel = new JPanel();
frame.add(panel, BorderLayout.CENTER);
button = new JButton("New Ball");
frame.add(button, BorderLayout.SOUTH);
button.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
Ball ball = new Ball(100, 100, 50);
panel.add(ball);
}
}
and ball class:
package ballsOnPane;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import javax.swing.JPanel;
public class Ball extends JPanel{
private int x;
private int y;
private int r;
public Ball(int x, int y, int r){
this.x = x;
this.y = y;
this.r = r;
}
public void paintComponent(Graphics g) {
Graphics2D g2 =(Graphics2D) g;
Ellipse2D circ = new Ellipse2D.Float(x, y, r, r);
g2.draw(circ);
}
}
When you add components to a visible GUI the basic code is:
panel.add(...);
panel.revalidate(); // to invoke the layout manager
panel.repaint(); // to repaint the components
Otherwise the size of the components added is (0, 0) so there is nothing to paint. The same goes for the button. It should be added BEFORE the frame is visible, or you need to do the revalidate()/repaint() as well.
In this case you also have a second problem:
frame.add(panel, BorderLayout.CENTER);
First you add an empty panel to the CENTER of the BorderLayout, then when you click the button you add the Ball to the CENTER.
Swing will paint the last component added first. So the ball gets painted and then the empty panel gets painted over top.
Get rid of the panel, it serves no purpose.
Edit:
For some reason I thought you were adding the Ball to the frame instead of the panel when you clicked the button.
My explanation above was correct if you did in fact add the Ball directly to the frame.
However, my explanation is incorrect since your code in the ActionListener does add the Ball to the panel. The proper explanation is below.
When you add the Ball to the panel, you don't see the Ball because by default a JPanel uses a FlowLayout and the FlowLayout respects the preferred size of any component added to it. You did not implement the getPreferredSize() method so the size is (0, 0) so there is nothing to paint.
So if you do implement the getPreferredSize() method in your Ball class the Ball will dislay on the panel. Also, you will be able to display a new Ball every time you click on the button.
As camickr answered, you need to revalidate() (or call both invalidate() & validate(), both will work) and then repaint() the panel.
The invalidate method marks the panel as being ''incorrect''; basically marking it for inspection.
Validate performs the layout of the component.
Revalidate does both, however, validate is synchronous whilst revalidate is not.
After you've validated the panel, you'll need to call repaint to redraw that panel.
As a side-note, JavaFX is replacing Swing/AWT, and in my opinon, is easier to use. You may want to look into it. :)
A short code example to do something similar to what you're currently doing, in JavaFX:
public class test extends Application{
Scene scene;
#Override
public void start(Stage primaryStage) throws Exception{
StackPane root = new StackPane();
root.setBackground(
new Background(new BackgroundFill(Color.ALICEBLUE,null,null)));
Button begin = new Button("Add Circle");
begin.setOnAction((ActionEvent e)->{
Circle c = new Circle(200,200,100,Color.RED);
root.getChildren().add(c);
});
root.getChildren().add(begin);
scene = new Scene(root, 700, 700);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Where have I messed up regarding creating a Game Menu?

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.

Categories

Resources