I'm trying to add a JPanel to a tab.
The panel is created with the LanguageTab class but I can't figure out why it doesn't work.
It maybe stupid but self taught is not enough here.
Hope someone can give me a little hand. thanks!
I have my code down here for you to understand what I'm going through!
public class MainTab extends JPanel {
JTabbedPane mainTab;
JPanel languageTab;
JFrame mainFrame;
JPanel mainPanel;
public MainTab(){
mainFrame = new JFrame();
mainTab = new JTabbedPane();
mainPanel = new JPanel();
//mainPanel.add(new JTextField("ciao"));
mainPanel.add(new JLabel(new ImageIcon("C:\\Users\\angelica\\Desktop\\developed.jpg")));
//languageTab = new LanguageTab();
mainTab.add("main",mainPanel);
mainTab.add("Language Tab",languageTab);
add(mainTab);
mainFrame.add(mainTab);
mainFrame.setVisible(true);
mainFrame.setDefaultLookAndFeelDecorated(true);
}
public static void main(String args[]){
MainTab mt = new MainTab();
}
}
and this is my LanguageTab
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JPanel;
public class LanguageTab extends JPanel implements ActionListener{
public LanguageTab(){
ImageIcon icona = new ImageIcon("C:\\Users\\angelica\\workspace\\whatever\\src\\whatever\\ita.jpg");
ImageIcon icona_DSA = new ImageIcon("C:\\Users\\angelica\\workspace\\whatever\\src\\whatever\\ita2.jpg");
ImageIcon iconb = new ImageIcon("C:\\Users\\angelica\\workspace\\whatever\\src\\whatever\\brit.jpg");
ImageIcon iconb_DSA =new ImageIcon("C:\\Users\\angelica\\workspace\\whatever\\src\\whatever\\brit2.jpg");
JPanel langTab= new JPanel();
langTab.setLayout(new GridLayout(2,2));
JButton ADHDbutton = new JButton("ADHD ENGLISH");
ADHDbutton.setIcon(iconb);
ADHDbutton.setActionCommand("adhd_english");
ADHDbutton.addActionListener(this);
JButton ADHDbutton1 = new JButton("ADHD \n ITALIANO");
ADHDbutton1.setIcon(icona);
ADHDbutton1.setActionCommand("adhd_italiano");
ADHDbutton1.addActionListener(this);
JButton DSAbutton = new JButton("DSA ENGLISH");
DSAbutton.setIcon(iconb_DSA);
DSAbutton.setActionCommand("dsa_english");
DSAbutton.addActionListener(this);
JButton DSAbutton1 = new JButton("DSA ITALIANO");
DSAbutton1.setIcon(icona_DSA);
DSAbutton1.setActionCommand("dsa_italiano");
DSAbutton1.addActionListener(this);
langTab.add(ADHDbutton);
langTab.add(ADHDbutton1);
langTab.add(DSAbutton);
langTab.add(DSAbutton1);
//return toModify;
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
You need to set the size of your JFrame so that it's large enough to see its contents.
Add the following as the last line of your MainTab constructor:
mainFrame.setSize(new Dimension(300, 300));
Additionally, inside your LanguageTab constructor, you have a variable called langTab, when the class itself (this) is supposed to represent the language tab. You then add all your buttons to langTab and never do anything with it.
Delete the variable langTab replace every call to it with this in the LanguageTab Constructor. Your constructor should then look something like this:
public LanguageTab() {
// button initialization goes here...
this.add(ADHDbutton);
this.add(ADHDbutton1);
this.add(DSAbutton);
this.add(DSAbutton1);
}
Now that your question has been answered, if you don't mind I would like to suggest a few things that might improve your future code quality.
Only use global variables when it's necessary to.
You declare four global variables for different parts of your UI, all of which can be declared instead as local variables. Working with Swing, it is often necessary to declare components as global so that they can be accessed in various places within the class, and that may eventually be the case for you. But you should always prefer local scoped variables when it's possible.
Give your variables the smallest possible scope
You don't have any access level (scope) modifiers on your global variables, which gives them a package scope by default. As I mentioned before it is often necessary to make swing components global for various reasons, but it is almost never necessary for them to have a scope larger than private (so they can only be accessed from within the class in which they are declared.
Access static methods in a "static way".
You call JFrame's setDefaultLookAndFeelDecorated() method using your variable mainFrame. mainFrame is an instance of the JFrame class (you declared it by saying mainFrame = new JFrame()), so you only use it to call instance methods. setDefaultLookAndFeelDecorated() is a static method (declared with the keyword static) and should therefore be accessed with the class name: JFrame.setDefaultLookAndFeelDecorated(true)
Be careful with your reference types.
You have declared your languageTab variable (in the MainTab class) as a JPanel. JPanel does not implement the ActionListener interface like your LanguageTab does, so by declaring your variable as a JPanel, you lose the ability to call actionPerformed() on it (or more likely set it as an action listener of some swing component).
Variables in Java, by convention, should begin with a lower case letter.
You gave your four buttons in the LanguageTab class names that start with capital letters. The Java convention is for variable names to begin with a lower case letter, in the same way that classes should begin with an upper case letter.
Related
Im working on a lab that requires me to make a JFrame with 2 inner classes. One that entends JPanel, has a text area and a jbutton. And another that implements action listener. How do i add an anonymouse instance of the second class to my JButton that is already in an inner class. Here is the brief to get a better understanding.
here is the code i have written so far. I can get the Frame to appear, but the JPanel doesnt appear, nor does the JButtons or JTextArea.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
#SuppressWarnings("serial")
public class FormFrame extends JFrame
{
public static void main(String[] args)
{
JFrame frame = new FormFrame();
frame.setLocationRelativeTo(null);
}
public FormFrame()
{
Container contentPane = getContentPane();
RegisterPanel p = new RegisterPanel();
p.button.addActionListener(new SubmitResponder());
//
// Here is where im lost...
//
contentPane.add(p);
setSize(300, 200);
setVisible(true);
}
class RegisterPanel extends JPanel
{
JPanel panel = new JPanel();
JTextField text = new JTextField();
JButton button = new JButton("Submit");
}
class SubmitResponder implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource()== RegisterPanel.button) //Asks me to make button static here
{
//Shows "No enclosing instance of the type FormFrame.RegisterPanel is accessible in scope"
RegisterPanel.this.text.setText("Submit Complete");
}
}
}
}
Any help with this would be much appreciated
You could pass the RegisterPanel instance to the action listener:
class SubmitResponder implements ActionListener {
private final RegisterPanel rp;
public SubmitResponder(RegisterPanel rp) {
this.rp = rp;
}
#Override
public void actionPerformed(ActionEvent e) {
rp.text.setText("Submit Complete");
}
}
There's no need to check the source btw. The AL is only listening to 1 source.
RegisterPanel p = new RegisterPanel();
p.button.addActionListener(new SubmitResponder(p));
p.button.addActionListener(new SubmitResponder());
Here the SubmitResponder is already an anonymous instance, quite literally, because it has no name.
Your error about "no enclosing instance" is unrelated. Since SubmitResponder is not an inner class of RegisterPanel (it's a sibling) it doesn't belong to an instance of RegisterPanel and so it cannot logically refer to RegisterPanel.this. How would it know which instance that is? There might be many, or even zero, depending on how many the parent FormFrame decides to create. It so happens that there's only one, but that's not the point. On the other hand if you said FormFrame.this there would be no doubt what that meant no matter the code did, unless RegisterPanel stopped being an inner class or it became static. Does that make sense?
To do what you want, the SubmitResponder needs to talk to RegisterPanel via a method in FormFrame. Incidentally you don't actually need to say FormFrame.this.doSomething() unless SubmitResponder also has a method called doSomething.
The instructions tell you that the RegisterPanel should be a field in the FormFrame class, which you haven't done. Something like this:
public class FormFrame extends JFrame
{
RegisterPanel panel;
...
public FormFrame()
{
panel = new RegisterPanel();
...
}
...
class SubmitResponder implements ActionListener
{
#Override
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == panel.button)
{
panel.text.setText(...);
}
}
}
}
Now you can access panel from inside the SubmitResponder class.
As a side note, the instructions are using some terminology in an ambiguous and incorrect way:
"Anonymous instance" is not an official term with a precise meaning.
Using official definitions, "class field" would imply the static modifier. Given the context of the assignment, I doubt that's correct. It should probably have said "instance field".
I have three classes which are shown below ,for a game GUI:-
//this is the parent class.
import javax.swing.*;
import java.awt.*;
public class GameGui extends JFrame{
public void decorateButton(JButton aBut,Color forg,Color back){
Font afont = new Font(Font.SANS_SERIF,Font.PLAIN,18);
aBut.setFont(afont);
aBut.setBackground(back);
aBut.setForeground(forg);
}
public void setFrameDefault(){
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(400, 475);
this.setLocationRelativeTo(null);
this.setResizable(false);
}
public void setConstraints(int x,int y,int weightx,int weighty,GridBagConstraints gbc){
gbc.weighty=weighty;
gbc.weightx=weightx;
gbc.gridx=x;
gbc.gridy=y;
}
}
//this class is for result to be shown for the game.
import javax.swing.*;
import java.awt.*;
class Result extends GameGui{
JPanel mainPanel = new JPanel();
JLabel backImage = new JLabel();//I want this variable to be shadowed by the subclass variable,but it is not happening.
JButton continueGame = new JButton("continueGame");
JButton exitGame = new JButton("exitGame");
public Result(){
this.setFrameDefault();
backImage.setLayout(new BorderLayout());
this.setContentPane(backImage);
mainPanel.setLayout(new GridBagLayout());
decorateButton(continueGame,Color.green,Color.white);
decorateButton(exitGame,Color.green,Color.white);
setGui();
}
public void setGui(){
GridBagConstraints gbc = new GridBagConstraints();
mainPanel.setOpaque(false);
gbc.gridy=200;
gbc.gridx=0;
gbc.insets=new Insets(410,0,0,130);
mainPanel.add(continueGame,gbc);
gbc.gridx=GridBagConstraints.RELATIVE;
gbc.insets = new Insets(410,0,0,0);
mainPanel.add(exitGame,gbc);
setFrameDefault();
this.getContentPane().add(mainPanel);
}
}
//this class is for showing the result for a Win.
import javax.swing.*;
import java.awt.*;
public class Win extends Result{
JLabel backImage = new JLabel(new ImageIcon("C:\\Users\\BSK\\Desktop\\win.png"));//Problem is here as i have declared the same named JLabel as in Result class but iam not getting the image as background.
public static void main(String[] args) { //this main method is for testing.
Win w = new Win();
w.setVisible(true);
}
}
I need two classes at end of hierarchy which are Win and Defeat(second one i have not implemented).I need this because i want wining frame and Defeat frame only differ in the image.
So my question is that although i have declared same named JLabel as backImage in both the classes Result and Win,why i am not getting the image at background?I have tested it by putting the image in JLabel backImage of Result class and then it works!But i want to take the advantage of data shadowing because in my Defeat class(which also extends Result)i will name JLabel having same name as backImage but with different image set to it.I hope you understand,So what is the way out?
Thanks in advance.
NOTE please test with your image.
Shadowing affects which variable a name refers to. That is, since the subclass Win defines its own backImage instance variable, methods of Win that refer to backImage will refer to the instance variable in Win (and thus its value) rather than the one in the superclass, Result.
Shadowing does not replace an object that variables and other objects point to. That is, the superclass Result still defines its own backImage instance variable, and Result's methods still refer to that variable (and thus its value). So Win#backImage shadows Result#backImage but it doesn't change how Result works.
Also note that the initialization lines like JLabel backImage = ... run as part of a class's constructor, and the subclass Win's constructor begins by running its superclass Result constructor. So if the subclass didn't declare another backImage and its constructor assigned a new value to the inherited instance variable Result#backImage, this would happen after the Result constructor built the content pane, so it wouldn't change the display.
You could change the contents of the backImage object:
public class Win extends Result {
public Win() {
super();
backImage.setIcon(new ImageIcon("C:\\Users\\BSK\\Desktop\\win.png"));
}
...
to modify backImage's icon for the Win subclass.
Fields in Java don't get overriden as methods, so this will not work for you. Fortunately, there are plenty solutions.
One of them (i'm definetly not saying the best one!) is to make your Result game abstract with abstract getIcon() method or something and call that from your setGui() method, then your Win/Lose classes will just return different icons in there.
I am trying to create a JFrame in Java, with a JPanel inside of it, which will hold a component.
I know how to add components using
panelname.add(component);
But I am making a class based off a JTextField and want to add the entire CLASS as a component into the JPanel, but when I do, Eclipse tells me:
The method add(Component) in the type Container is not applicable for the arguments (BetterText)
(BetterText been the name of the class)
So all it basically is, is a class with a JTextField setup with methods and such, but I want to add that class as a component to the JPanel. I looked at the JTextField.java class and cant see anything interesting there, it looks like an ordinary class like any other, but you are able to add an instance of that class to a JPanel, whereas with mine, you cant.
Any help will be appreciated, thankyou.
Also, if you know the solution, please post an example class.
Edit: Added code.
public BetterText(String defaultText) {
super();
//Sets up the textFields colours and the defaultText to display in it.
setProperties();
hasDefault = true;
this.defaultText = defaultText;
textField.addActionListener(this);
}
Another edit:
It also extends JTextField already.
public class BetterText extends JTextField implements ActionListener {
Make sure your JFrame, JPanel and JTextField extend the correct classes (if they are custom classes).
Some pseudo code:
public class BetterText() extends JTextField{
public BetterText(){
super();
}
}
And then to create the GUI:
JFrame frame = new JFrame();
JPanel panel = new JPanel();
BetterText textField = new BetterText();
frame.add(panel);
panel.add(textField);
panel.pack();
panel.setVisible(true);
Verify that you are importing javax.swing.JComponent, then make your BetterText class inherit from JTextField.
This is how my code looked in the beginning: https://gist.github.com/anonymous/8270001
Now I removed the ActionListener to a separate class: https://gist.github.com/anonymous/8257038
The program should give me a little UI, but it just keeps running without any UI popup or errors.
Someone told me this:
In your GUI class constructor, you are creating a new nupuVajutus object, but since nupuVajutus extends the GUI class, when you create a nupuVajutus, you are also inherently calling the GUI class constructor by default, thus creating an infinite loop
If this is really the problem, then I have to say I am not that good and could use some help getting this program working with the classes separated.
You have indeed already been given the answer, although what you have is not an infinite loop, but infinite recursion, which will eventually cause a StackOverflowError.
Here's what happens:
new GUI() calls new nupuVajutus(). This creates a new nupuVajutus object by calling its constructor. Because nupuVajutus extends GUI, this means a nupuVajutus object is a GUI object with additional functionality. Therefore, because it is a GUI object, a GUI constructor needs to be called. The nupuVajutus constructor does not explicitly call a super constructor, so it implicitly calls the GUI() (no argument) constructor before executing. In this new call to the GUI() constructor, another new nupuVajutus() call is encountered, and so on, ad infinitum...
It seems to me you need to do some more research around Object Oriented Programming, in particular the topics of sub-classing, inheritance, object instances, and encapsulation. There are plenty of resources available to help you.
After you extracted your ActionListener into a separate file, you should not have changed it to extend GUI. That extends the class (which is like a blueprint) not an instance (which is like a something built using that blueprint) - remember: you can create multiple instances of a class.
Previously, the "nupuVajutus" ActionListener was an inner class, so it had access to all of the enclosing class' fields and methods. Now that it is no longer an inner class, it needs to be passed a reference to the GUI instance so that it can access its methods. Something like this:
public class NupuVajutus implements ActionListener {
private final GUI gui;
public NupuVajutus(GUI gui) {
this.gui = gui;
}
public void actionPerformed(ActionEvent e) {
// The GUI instance can now be accessed through the gui field, for example:
gui.something();
// ...
}
}
And in the GUI() constructor:
NupuVajutus nV = new NupuVajutus(this);
To be honest, though, there is nothing wrong with keeping your ActionListener as an inner class. If you're never going to use that class outside of the GUI class, then it is probably preferable for it to remain as an inner class.
What you are doing it extending the GUI class. This Does Not make then share the Same Fields Say you have a field field in your GUI class
public class GUI {
String field = "Hello";
}
Just because your Listener class extends GUI doesn't mean they will share the exact same field object. I think that's what you think is supposed to occur
public class Listener extends GUI implements ActionListener {
public void actionPerformed(ActionEvent e) {
field = "World";
}
}
The above does nothing the field in GUI. If you were to do this, you would need to access in a static way like line GUI.field = "World";. The above is also what causes in an infinite loop, as you need to instantiate the Listener in the GUI class. This is not really good practice or design.
One option would to use some sort of MVC pattern.
Another option would be to pass the values you need, to a constructor in your Listener class, and instantiate it in your GUI class with those values.
Run this example to see what I'm talking about. I have a MyListener class that I pass a Jlabel to, the same JLabel in the GUI class
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class FieldTest {
private JLabel label = new JLabel(" ");
private JButton button = new JButton("Set Text");
public FieldTest() {
MyListener listener = new MyListener(label);
button.addActionListener(listener);
JFrame frame = new JFrame();
frame.add(label, BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new FieldTest();
}
});
}
}
class MyListener implements ActionListener {
JLabel label;
public MyListener(JLabel label) {
this.label = label;
}
#Override
public void actionPerformed(ActionEvent arg0) {
label.setText("Hello, FieldTest!");
}
}
I’m relatively new to using the javax.swing and java.awt so bear with me if I express my problem awkwardly.
Let’s say I have a custom made class CustomClass that extends and creates a JPanel p. In the class I add a JButton b to p. Later in another program file I create an instance of my CustomClass called cp and want to be able to catch for example a click event from b using the “actionPerformed” method. My question is how do I “reach” (like the written path to) the JButton b from instance cp? (Assuming that all relevant class files are already associated)
Use getters and setters if i understood correctly. I,e your customPanel will have a public getButton() method which would return the JButton instance:
class CustomPanel extends JPanel {
JButton button=new JButton("Some button");
public JButton getMyButton() {
return button;
}
}
class Test {
CustomPanel cp=new CustomPanel();
void someMethod() {
JButton b= cp.getMyButton();
}
}
UPDATE
as per comment:
what if I have like 10 or 20 different components in my JPanel, is
there some way to reach them without having to make a lot of methods
Simply call getComponentCount on JPanel instance and than iterate using a for loop and getComponentAt(int i) this will allow you to get access to all components on JPanel:
CustomPanel cp=...;//this class extends jpanel
for(int i=0;i<cp.getComponentCount();i++) {
Component c=cp.getComponentAt(i);
if( c instanceof JButton) {
//do something
}
}
UPDATE 2
What if I have two or more objects that should be of the same class
but otherwise treated as separate objects, how can I tell them apart
using the loop that you've provided me
look at setName(String name) and getName of JButton this will allow you to assign the instance a unique name which can be gotten by getName(). Alternatively use setActionCommand(String name) and getActionCommand() to differentiate the buttons from another I prefer the latter.
Or you could even use their texts, via getText()