How to make a class a component in Java Swing? - java

I am a beginner in Java programming so I do not know if I may be using the correct terms here. Basically, I have an assignment to program a little applet that changes the color of the background to whatever of the 4 color buttons is pressed. I was given a sample code with ActionListener and was told to use MouseListener to implement it.
I was able to successfully program it to work and then the requirements changed. Below is my current code that works (before the requirements changed).
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ButtonPanel extends JPanel implements MouseListener{
private JButton abutton, bbutton, cbutton, dbutton;
public ButtonPanel(){
abutton = new JButton("Cyan");
bbutton = new JButton("Orange");
cbutton = new JButton("Magenta");
dbutton = new JButton("Yellow");
add(abutton);
add(bbutton);
add(cbutton);
add(dbutton);
/* register the specific event handler into each button */
abutton.addMouseListener(this);
bbutton.addMouseListener(this);
cbutton.addMouseListener(this);
dbutton.addMouseListener(this);
}
/* implementation for the Mouse Event */
public void mouseClicked(MouseEvent evt){
Object source = evt.getSource();
if (source == abutton) setBackground(Color.cyan);
else if (source == bbutton) setBackground(Color.orange);
else if (source == cbutton) setBackground(Color.magenta);
else if (source == dbutton) setBackground(Color.yellow);
repaint();
}
public void mousePressed(MouseEvent evt){
}
public void mouseEntered(MouseEvent evt){
}
public void mouseReleased(MouseEvent evt){
}
public void mouseExited(MouseEvent evt){
}
}
class ButtonFrame extends JFrame{
public ButtonFrame(){
setTitle("Low-level Mouse Event to Set Color");
setSize(50, 50);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){ System.exit(0);}
});
Container contentPane = getContentPane();
contentPane.add(new ButtonPanel());
}
}
public class ME_SetColor {
public static void main(String[] args) {
JFrame frame = new ButtonFrame();
frame.pack();
frame.setSize(400, 250);
frame.setVisible(true);
}
}
The new requirement is to exclude extends JPanel and any other extensions for class ButtonPanel. So the modified class has to be
class ButtonPanel implements MouseListener{
private JButton abutton, bbutton, cbutton, dbutton;
Without JPanel, the ButtonPanel class would not be a component and therefore it can not be added to contentPane. Is there another way to make this ButtonPanel a component so it can be added to contentPane? Or is there any other ways to implement this program?

Without JPanel, the ButtonPanel class would not be a component
You could extend JComponent. JComponent is the base class for Swing components. JPanel itself is a simple extension of JComponent (with one minor difference: a JPanel's opaque property is true by default, whereas it's false by default for JComponent).
But if your requirement is to exclude any extensions for ButtonPanel, you're right, you can't actually make it a component that can be added to a container.
However, you could include a component as a field of ButtonPanel:
class ButtonPanel implements ... {
private JPanel panel;
private JButton abutton, bbutton, cbutton, dbutton;
...
public JPanel getPanel() { return panel; }
}
Then in ButtonFrame:
add(new ButtonPanel().getPanel());
You don't need to call getContentPane() and contentPane.add by the way, as a frame's own add methods automatically do this.

Related

Is it a bad idea to call pack() in JFrame.invalidate?

I've built a simple gui that adds panels based on user input. My initial problem was that when the panel was added the frame did not resize. Because it was a jpanel object that handled the user input adding a new panel to itself and therefore could not 'see' the jframe (at least I couldn't find how it could) I couldn't work out how to call repaint() or revalidate() on the parent frame from within that object. However,through trial and error I did find that this worked
JFrame jFrame = new JFrame(title){
#Override
public void invalidate(
super.invalidate();
this.pack();
}
};
But because I don't really know what goes on behind the scenes with invalidate I want to know whether this is a good idea or not (It seems kinda sketchy). Any advice would be great, thanks.
EDIT
Hope this makes the problem a bit clearer
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class TestFrame {
JFrame jframe;
NewPanel jpanel;
public TestFrame(){
jframe = new JFrame(); // without above addition frame won't resize
jpanel = new NewPanel();
jframe.add(jPanel);
jframe.pack();
jframe.setVisible(true);
}
public static void main(String [] args){
TestFrame testframe= new TestFrame();
}
}
class NewPanel extends JPanel implements ActionListener{
public NewPanel(){
JTextField textField = new JTextField (10);
textField.addActionListener(this);
this.add(textField);
}
// Adds a label when action is performed on textfield
#Overide
public void actionPerformed(ActionEvent ae){
JPanel extraPanel = new JPanel();
extraPanel.add(new JLabel("hi"));
this.add(extraPanel);
this.revalidate(); this.repaint();
}
}
Your issue is not that revalidate() or repaint() aren't working.
The issue here is that your JFrame has been pack()ed already and thus it has a preferred size set. If you want to change its size you need to call pack() on it again. Not necessarily to call it on invalidate().
I made some changes to your code to compile (typos) and I came with this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestFrame {
JFrame jframe;
NewPanel jpanel;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new TestFrame());
}
public TestFrame(){
jframe = new JFrame(); // without above addition frame won't resize
jpanel = new NewPanel();
jframe.add(jpanel);
jframe.pack();
jframe.setVisible(true);
}
class NewPanel extends JPanel implements ActionListener{
public NewPanel(){
JTextField textField = new JTextField (10);
textField.addActionListener(this);
this.add(textField);
}
// Adds a label when action is performed on textfield
#Override
public void actionPerformed(ActionEvent ae){
System.out.println("WOLOLO");
JPanel extraPanel = new JPanel();
extraPanel.add(new JLabel("hi"));
this.add(extraPanel);
this.revalidate();
this.repaint();
jframe.pack();
}
}
}
Another way to solve this is to override getPreferredSize method from the JPanel:
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
And you can delete jframe.pack() in the previous code.

Focus component after changing content pane of JFrame

I'm changing my JFrame's content pane and simply want to focus a JTextField in the new panel. So I'm doing this:
JPanel pNew = new JPanel();
frame.setContentPane(pNew);
frame.revalidate();
frame.repaint();
public JPanel() {
...
tf.requestFocusInWindow();
}
When I use setVisible(false) and setVisible(true) instead of revalidating and repainting my frame, I get my wished effect, but that's not the way I want to do it.
What else happens in setVisible() but revalidating and repainting?
A CardLayout is typically used to swap panels.
However, even the default implementation of CardLayout does not set focus on the panel when it is swapped. However you can check out Card Layout Focus which will allow you to request focus on the panel when it is switched.
The requestFocusInWindow() method only works on a component that is displayed in a visible frame. So you can't invoke the method in the constructor of the class.
You could use the RequestFocsListener found in Dialog Focus. It will wait until the panel is added to a visible GUI before generating the event.
I got it to work simply by putting the requestFocusInWindow() call in the button's action listener. As camickr mentioned the call needs to be made after the constructor. Here's an example program showing how I got it to work. Hope it helps!
public class PanelRevalidate {
public JFrame frame;
public MyPanel panel1, panel2;
public PanelRevalidate() {
frame = new JFrame();
panel1 = new MyPanel(1);
panel2 = new MyPanel(2);
frame.setContentPane(panel1);
panel1.getSwap().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
frame.setContentPane(panel2);
frame.revalidate();
panel2.getTextField().requestFocusInWindow();
}
});
panel2.getSwap().addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
frame.setContentPane(panel1);
frame.revalidate();
panel1.getTextField().requestFocusInWindow();
}
});
frame.setVisible(true);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
new PanelRevalidate();
}
});
}
}
And the MyPanel class:
public class MyPanel extends JPanel {
public JTextField tf;
public JButton swap;
public JLabel panel_label;
public MyPanel(int n) {
tf = new JTextField(25);
swap = new JButton("Swap");
panel_label = new JLabel("panel " + n);
add(tf);
add(swap);
add(panel_label);
}
public JButton getSwap() {
return swap;
}
public JTextField getTextField() {
return tf;
}
}

"Linking" JComponents in Java?

I have a few buttons and a few panels. Each button corresponds to a panel. I want to add an ActionListener to each button so that when the buttons are clicked, the visibility of the panels are toggled. However, inside the ActionPerformed method, I cannot get the JPanel. Here's basically what I have:
JFrame frame1=new JFrame();
JPanel panel=new JPanel();
frame1.add(panel);
JFrame frame2=new JFrame();
JButton btn=new JButton(panel.getName());
btn.addActionListener(new ActionListener(){
public void ActionPerformed(ActionEvent e){
(somehow get panel).setVisible(false);
}
});
frame2.add(btn);
It might be better to create a class that implements ActionListener. You could then pass in a reference to the parent JPanel and then refer to that in the actionPerformed method.
But if you really wanted to, you could use this convoluted one-liner.
((JComponent)e.getSource()).getParent().setVisible(false);
An AbstractAction could work well:
class ButtonAction extends AbstractAction {
private JPanel panel;
public ButtonAction(JPanel panel) {
super(panel.getName());
this.panel = panel;
}
public void actionPerformed(ActionEvent e) {
panel.setVisible(false);
}
}
elsewhere:
someContainer.add(new JButton(new ButtonAction(panel)));
It is not very good solution, but you can link swing components in following way
button.putClientProperty("panel", panel1);
//and somewhere in code
((JPanel)button.getClientProperty("panel")).setVisible(false);
This should work:
e.getSource().getParent().setVisible(false);

Java actionlistener doesn't work

I just started learning Java 1 week ago, and I'm a 100% totally beginner. In this code, I can't seem to be able to put an actionlistener/get one to work. I don't even know where/how/in what way to put it, despite reading dozens of tutorials. I've created a JFrame with a JPanel in it, and on the JPanel there's a button. So far so good (and working). But then, I want it to be so that if the button is clicked, another button appears. Thank you sooo much in advance!
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
public class Skeleton extends JFrame implements ActionListener {
public static void main(String[] args) {
//------------------------------------------------
JFrame frame = new JFrame("Skeleton");
JPanel panel = new JPanel();
frame.setContentPane(panel);
frame.setSize(600,600);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
JButton button = new JButton("This is a button.");
JButton button2 = new JButton("Hello");
panel.setLayout(null);
button.setBounds(20,20,200,25);
button2.setBounds(20,70,200,25);
panel.add(button);
//-------------------------------------------
button.addMouseListener(this);
}
public void ActionPerformed(ActionEvent e) {
System.out.println("Hello");
}
}
i will give you some advice
1) Don't implement ActionListener in top classes, use anonymous classes or private classes instead.
Example :
Anonymous class (also call Swing Actions)
myComponent.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt){
//code here
}
})
or
//inner class
public class Skeleton{
// in some part
private class MyActionListener implements ActionListener{
public void actionPerformed(ActionEvent evt){
//code here
}
}
}
2) Your code won't compile cause you are not implementing ActionListener interface
public void actionPerformed(ActionEvent evt) is the signature.
You have to addActionListener to your component
button.addActionListener(this);
3) Don't use null layout, cause you'll have a lot of problem if you want to add more components or resize windows cause you have to setBounds manually and it will be frustrating instead use [Layout Manager][1].
4) Try to not extends JFrame if is not necesary instead have a reference in your class, for example.
public class Skeleton{
private JFrame frame;
}
You need to add the actionlistener.
Register an instance of the event handler class as a listener on one or more components. For example:
yourdesiredcomponent.addActionListener(this);
For more details check the doc

Java JButton - making simple menu

Hi take a look on this code:
package arkanoid;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.event.*;
public class Arkanoid extends JFrame
{
private static final long serialVersionUID = 6253310598075887445L;
static JFrame frame;
static class Action1 implements ActionListener {
public void actionPerformed (ActionEvent e) {
//frame = new JFrame("Arkanoid");
frame.setLocationRelativeTo(null);
frame.setIgnoreRepaint(true);
frame.setResizable(false);
frame.setVisible(true);
frame.setSize(500,400);
frame.add(new Gra());
}
}
static class Action2 implements ActionListener {
public void actionPerformed (ActionEvent e) {
frame.dispose();
System.exit(0);
}
}
public static void main(String[] args)
{
//new Arkanoid();
frame = new JFrame("Arkanoid");
frame.setSize(500,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Arkanoid BETA");
frame.setLocationRelativeTo(null);
frame.setIgnoreRepaint(true);
frame.setResizable(false);
frame.setVisible(true);
JPanel panel = new JPanel();
frame.add(panel);
JButton button = new JButton("Nowa Gra");
panel.add(button);
button.addActionListener (new Action1());
JButton button2 = new JButton("Wyjscie");
panel.add(button2);
button2.addActionListener (new Action2());
}
}
This code almost works, I want to make a button2 a quit button working like X button in top right frame's icons and button1 need to open a Gra() in the same window. When im doing it like this it isnt work fine:/ i need to click 2 times on button1 to go to Gra() and what is more KeyListeners in Gra() arent working :(
Im new in buttons, frames and panels in java so please help with this code. Correct it please.
There are a number of fundamental problems with your code, the least of which is why your button1 requires 2 clicks.
However, for your problem you should try rearranging the order of your button1 listener, so that your Component is added to the frame first, before setting it to be visible. An example that should work:
static class Action1 implements ActionListener {
public void actionPerformed (ActionEvent e) {
frame.add(new Gra());
frame.revalidate();
}
}
Note you have already set the size, location etc of frame in main, so there is no need to set them again every time the button is clicked.
I stress that there are more important problems with your code than this issue. You should take a look at Java's Modifier Types (static does not seem applicable here), as well as object-oriented concepts such as inheritance (you define your Arkanoid class to extend JFrame, yet have a JFrame object as a class variable).
I want to make a button2 a quit button working like X button in top right frame's
You can use the ExitAction class found in Closing an Application.
For other examples of how to use buttons read the Swing tutorial on How to Use Buttons. This is the place to start for all you Swing related questions.
There are many problems with your code. I've refactored it a little. With below code & #ricky116 answer I think you should get all of them.
import javax.swing.*;
import java.awt.Color;
import java.awt.event.*;
public class Arkanoid extends JFrame
{
public Arkanoid() {
super("Arkanoid");
setSize(500,400);
setTitle("Arkanoid BETA");
setLocationRelativeTo(null);
setResizable(false);
final JPanel panel = new JPanel();
setContentPane(panel);
panel.add(new JButton(new AbstractAction("Nowa Gra") {
public void actionPerformed (ActionEvent e) {
panel.removeAll();
panel.add(new Gra());
panel.revalidate();
panel.repaint();
}
});
panel.add(new JButton(new AbstractAction("Wyjscie") {
public void actionPerformed (ActionEvent e) {
Arkanoid.this.setVisible(false);
}
});
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Arkanoid frame = new Arkanoid();
frame.setVisible(true);
}
});
}
}

Categories

Resources