Sorry about this question but I have been struggling with an assignment my professor gave us for days and have no idea where to begin. I don't want someone to do it for me or anything, I am just looking to learn/get some good pointers because I can't find a foothold in this at all.
The assignment is as follows :
Implement a graphical user interface with the GridLayout class with a 10 5 grid of JButtons and JLabels. The JButtons should be on the top five rows and the JLabels should be on the next five rows. (The first JButton should have the text 1-1 and the last the text 5-5.) The JButton on the i th row and j th column should have the text i - j on it. The text of the JLabels should be 0.
The purpose of the JLabels is to count the clicks of the corresponding JButtons. For example, when a user clicks button
i - j for the first time, the text of the JLabel of the (5 + i )th row and j th column should change to 1.
You are not allowed to use any instance variables.
Hint 1: use and inner class for the labels.
Hint 2: you can increment the “number” the label by getting the text of the label, parsing it to an int with Integer.parseInt( ), and by changing the text of the label.
You must also add one more JButton which resets the counters on the JLabels. The
text on the JButton should be reset.
So far I have just been studying notes with no understanding or cluelessly typing away and come up with a completely non-functioning desperate attempt which is as follows :
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class NewFrame extends JFrame {
private static JButton[] buttons;
public static void main ( String[] args ) {
NewFrame frame = new NewFrame( );
}
public void NewFrame( ){
JFrame frame = new JFrame ("JFrame");
JPanel panel = new JPanel( );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE);
int noOfButtons = 25;
buttons = new JButton[ noOfButtons ];
for(int i = 0; i<buttons.length ; i++){
buttons[i] = new JButton();
panel.add(buttons[i]);
JLabel label = new JLabel( "Initial Text" );
}
frame.getContentPane( ).add( panel );
frame.setSize( 500, 500);
frame.setVisible( true );
}
}
Can someone please offer me some advice or hints here as I have been struggling with this for an age ?
Please have a look at this link: So, You Need to Write a Program but Don't Know How to Start which will give you great tips on how to start. The key is to break down your big problem into small steps and then try to solve each step in isolation. Then if you get stuck at least you'll be able to post a much more specific question, one that is more easily answered with a specific and helpful answer. Another good resource are the Swing tutorials which can show you how to use the various Swing components including JFrames, JPanels, JButtons, text components, and what not. You can find them here: Using Swing Components
Best of luck!
Edit 1:
Your code now compiles but there are two glaring issues that first need to be fixed:
1) Your class has no constructor but rather a "pseudo-constructor". Remember constructors have no return type, not even void.
2) You don't use a GridLayout.
Other issues: again the key is to break the problem down. I recommend you do just that on paper, and then type your version of the steps you think you need to solve the problem. Then we can go through them one at a time.
Generally, when you write a Swing application, your main class extends JFrame. You do all the initialization / create the buttons / etc in the constructor, then create an instance of the class in main()
-- edit --
see hovercraft's comment - you don't have to do the following in the constructor of an extended JFrame. Just change this to your JFrame variable if you do it externally.
The java documentation is your best friend - use it. http://download.oracle.com/javase/6/docs/api/
Create a GridLayout object, assign it to your content pane (this.getContentPane()) with setLayout
Create your buttons / labels, add those to the content pane
etc, etc
Look at the documentation for JButton.setActionCommand, JButton.addActionListener
You can access the labels later to increment / reset them with this.getContentPane().getComponents(), or one of the other access methods
Before I look at the code, you will surely need the Java tutorials on buttons and actions:
http://download.oracle.com/javase/tutorial/uiswing/components/button.html
http://download.oracle.com/javase/tutorial/uiswing/misc/action.html
The first issue with your code is that you use an instance variable to store the buttons in an array. You don't need this, since you are already adding them to the panel immediately.
The second issue is actually getting your buttons to do stuff when clicked. You need to add an ActionListener of your own design to each button, as follows:
myButton = new JButton();
myButton.addActionListener(new MyButtonListener());
and declare some MyButtonListener:
public class MyButtonListener implements ActionListener
{
}
the contents of the ActionListener class are beyond the scope of my help for your homework. But the Java tutorials are a great resource if you have no idea how to implement ActionListener.
Related
My code consists of three classes, say: x(extends JFrame), y(extends JPanel) and z. x has the main function. It has borderLayout and has two panels in it: left and center. Left panel has bunch of JButtons and JTextFields where user inputs his values and those values are used to draw some things into my center panel handled by my y class.
The z class is used by the y class for general calculation purposes. Now I am almost done making the program and am working on a "clear" button in my left panel which will clear all the text user has entered and what has been drawn into my center panel (handled by y class).
What i can do is set some values to their default values and repaint() my center panel but the problem is that there are a LOT of variables and then there are again a lot of variables in my z class(which is instantiated by y).
This is getting confusing and tiresome so i am thinking if there is any way i can (i am going against the rules of garbage collection here) i can kill the instance of y in my x class and make a new one. That will be so neat. Tell me what i should do in such situation. Thanks.
EDIT: i want the clear button to remove what has already been drawn into my panel so can i do this in my x class?
remove(myRightpanelInstance);
myRightPanel myRightpanelInstance2 = new myRightPanel();
add(myRightpanelInstance2, BorderLayout.CENTER);
it doesnt work btw.
Based on your edit you want to add a new panel and overwrite the old one. You can simply:
MyRightPanel myRightPanelInstance2 = new myRightPanel();
add(myRightPanelInstance2, BorderLayout.CENTER);
This will overwrite the existing panel with the new one.
Make sure this code is in your listener for the clear button. This only happens if you call this code inside the listener.
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Either above code here or above code in a method and method call here
}
})
I have a frame with a var , I added that var to a JPanel, and if I want to add the same var to another JPanel, it`s disappearing from the first JPanel. I want a logical explanation for my problem please, thank you !
I want to store my JLabel in both of my jpanels.
public class Gui {
JPanel panel1, panel2;
JLabel text = new JLabel("some text");
JFrame frame = new JFrame();
public Gui {
panel1 = new JPanel();
panel1.setLayout(null);
panel1.add(text);
panel1.getComponent(0).setBounds(50,50,50,50);
panel1.setBorder(BorderFactory.createLineBorder(Color.black));
panel1.setBounds(x,y,w,h);
// it`s working, the labels it`s visible
panel2 = new JPanel();
panel2.setLayout(null);
panel2.add(text);
panel2.getComponent(0).setBounds(100,100,50,50);
panel2.setBorder(BorderFactory.createLineBorder(Color.black));
panel2.setBounds(x,y,w,h);
//it`s not working, the label ins`t visible ...
frame.add(panel1);
frame.add(panel2);
}
}
Disclaimer: I am editing my answer in response to comments from the OP. However, I am still not entirely sure about some of the details of the question. I will gladly edit my answer as more clarifications are given.
Answer: One possible solution is to create subclasses of the Swing components you are using. For example,
public class MyPanel extends JPanel {
private JLabel label = new JLabel("some text");
public MyPanel() {
this.add(label);
}
}
Now you can create multiple instances of MyPanel which each have its own JLabel. Then you can add these panels to your frame.
Added: With the additional information given in the comments, I would go a step further and create a custom JFrame class:
public class MyFrame extends JFrame {
private MyPanel panel = new MyPanel();
public MyFrame() {
this.add(panel);
}
}
Now you can create several instances of MyFrame. If you want to go even further, you can add parameters to the constructors of both of these custom classes to set the JLabel text to different values in each instance MyFrame. I will leave the details as an exercise to the reader. (Of course, please ask if you get stuck, though.)
Just as it's discussed with in other posts. All Swing UI components (ie JLabel included) can only have one parent (ie JPanel). If you add it to another panel it will remove itself from the prior parent. There are very good reasons for this behavior. For example, JPanel 1 might not use the same Layout as JPanel 2 and hence the label would have to support two different placements within each JPanel. The whole point of using Objects as components is to provide encapsulation of data like (font, position within the parent, width, height, etc) inside that object. If you want two visual elements just create another element. Now that creates a problem "How do you synchronize the data across all of these controls?" That's basically scratching how do you build a proper Swing architecture for your program?
What you don't want to do is use the Swing component model (ie. Jabel, JTextField, etc) as your data model. And after reading your question and code I believe that's what you are doing. You may not realize it. UI Components should be used for display only. They reflect what is in the data model. So you'll want to create a model that doesn't involve Swing. It should model your problem regardless of how its displayed. That means you shouldn't assume it will always be Swing or web, etc.
There are very practical reasons for this. Say in a year you want to redesign your UI. If you combined the view components and data model together you pretty much have to start completely over. Even if you aren't switching technologies. Say you are switching from a JList to a JTable or a JTreeTable. Just simple changes of the types of components you have on the screen can be an absolute nightmare if you don't segment your view from the model. Plus the View displays thing, but the model might need information that isn't displayed to the user but is tied to what is being displayed. For example, the ID of the row in the database. If you stuff the view and data model together you have to play little hacks to store this invisible information in weird ways. Things that make it hard for other people to understand.
If you don't know what I mean you either will in 6 months when you have to make your first major redesign or you'll save yourself some pain now and try and understand what I mean now. Just simple POJOs will suffice. Then share those POJOs with your Swing components. For example:
MySpecialPanel panel1 = new MySpecialPanel();
MyOtherSPecialPanel panel2 = new MyOtherSpecialPanel();
frame.add( panel1 );
frame.add( panel2 );
...a little while later...
MySpecialPOJO specialPOJO = ...some call to a service...;
panel1.setSpecialPOJO( specialPOJO );
panel2.setSpecialPOJO( specialPOJO );
Notice that I created two subclasses of JPanel called MySpecialPanel and MyOtherSpecialPanel. Inside there they create the components contained within them. Then then expose a setter method taking a data model object of type MySpecialPOJO. Inside those methods we might see something like the following:
public void setSpecialPOJO( MySpecialPOJO specialPOJO ) {
this.model = specialPOJO;
textField1.setText( specialPOJO.getName() );
textField2.setText( specialPOJO.getDescription() );
radioButtonGroup.setSelected( specialPOJO.getGender() );
....
}
Now you have a way to take a model object, and update the relative UI components that make up that view. Notice it doesn't care about any other external dependencies (ie where it got the object from). It just updates the controls it owns to reflect what's carried by the POJO. Now if you follow these simple rules it makes instantiating your special panels easy. Whether you need only one instance or many instances. Also if you need to move panels within your program it's pretty easy to do that if you reduce your dependencies to just your POJOs. There's a lot more to this, but for now this will get you started. You still have to figure out how to get data out of the UI and back into your POJOs (events!). Controllers, Services, etc.
This might help you as well:
Up-to-date Swing MVC example + Question
You can't. As you noticed, a control can only be attached to one window at a time, and if you try to attach it to another one, it will remove itself from the first.
Suggestions:
panel2.add(text.clone()); // clone the existing label
panel2.add(new JLabel("some text")); // make a new label from scratch
I am teaching myself Java and I am reading "Java All in One Desk Reference For Dummies." I am currently using the code provided in the book to practice Swing. Here is the code I am using that comes from the book: `import javax.swing.*;
public class JavaBook6 extends JFrame
{
public static void main(String[] args)
{
new JavaBook6();
}
public JavaBook6()
{
this.setSize(400, 400);
this.setLocation(500, 0);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setTitle("Sample");
this.setVisible(true);
JPanel pnlMain = new JPanel();
JCheckBox chkMy = new JCheckBox("Save");
JButton btnMy = new JButton("Search");
JTextField txtMy = new JTextField(20);
pnlMain.add(chkMy);
pnlMain.add(txtMy);
pnlMain.add(btnMy);
this.add(pnlMain);
}
}
I seem to get inconsistent results when I press run. A window always shows up. However, sometimes the only thing displayed in the window is the Frame title and other times the components such as JCheckBox, JTextArea and JButton show up, as I would expect.
My question is why do the components show up sometimes and not others? I have tried using other components and get the same inconsistent results.
As I stated I am a beginner and I therefore have a very basic understanding of how java works, so please forgive me if the answer to my question is obvious.
I'm not too impressed with the text book:
The GUI should be created on the EDT. Read the section from the Swing tutorial on Concurrency for more information. I would also recommend you use the examples from the tutorials since they incorporate the suggestions from the tutorial.
Component must be added to the GUI before the setVisible( true ) method is invoked. (There are ways around this, but for now keep it simple and follow this rule).
You generally need to do...
this.pack();
before it will display everything.
I suspect if you resize the window, everything shows up?
Adding the pack() tells the layout manager to position and size all the components.
Also if you resize the window or force it to refresh in some way it will also display the components.
I want to know how I can make a Java program where an unknown amount of objects can be added to a GUI depending on user input. I can program in objects one at a time within the program, but I haven't seen a more dynamic program.
Can I do that with Java? If not, what can I do it with?
For more information, here's a picture.
There can be more than one question per question block, and each question can have it's own question block.
Yes you can dynamically add and remove components. The basic code would be:
panel.add( ... );
panel.revalidate();
panel.repaint();
Ofcourse you can do it with Java Swings. All you gotta do is based on user input you gotta take a decision to add new JPanels. From the picture you've given in the example, you would need to add a Q&A block dynamically. Simply attach that to any event handler within your application so that it gets added dynamically
public getQandAPanel(){
JPanel questPanel = new JPanel();
JPanel answerPanel = new JPanel();
JPanel wrappingPanel = new JPanel();
wrappingPanel.setLayout(new GridLayout(0,1));
//CODE TO DECORATE question and answer panels should go here
wrappingPanel.add(questPanel);
wrappingPanel.add(answerPanel);
}
Now everytime when you call this getQandAPanel, this would return you a fresh JPanel everytime which you can add it to your parent JFrame. You should have a good idea of Java Swings to know what I'm talking about.
I've only just begun writing GUI programs, this being my second one. With both projects (both homework assignments) I have had the same issue. The GUI objects (such as JTextField) do not show when the application runs until after I resize the window or move keyboard focus to them. If I do not do one of those two things, then I'll just have an empty application window.
Any ideas why this is happening and what I could do to solve it? I'm working on Mac OS 10.6.1.
My code is below. Feel free to comment on my coding style, but please focus on the problem I'm having.
import javax.swing.*;
import java.awt.*;
public class ToDo extends JFrame {
private int height = 30,
width = 300;
public ToDo() {
this.setSize(400,400);
this.setVisible(true);
this.setLayout(null);
this.setResizable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("To Do List");
JTextField todoItem[] = new JTextField [10];
Container contentpane = this.getContentPane();
contentpane.setLayout(null);
for(int i=0; i<10; i++) {
todoItem[i] = new JTextField();
todoItem[i].setBounds(10,(height*(i)+10),width,height);
contentpane.add(todoItem[i]);
}
}
public static void main(String[] args) {
new ToDo();
}
}
You have to add the elements before the component is made visible.
Put this as your last line:
this.setVisible(true);
alt text http://img10.imageshack.us/img10/8210/capturadepantalla200911s.png
This is not OSX related, it happens in Windows also.
There are some rules about how you should never touch Swing objects from outside the Swing thread once they've been realized. I always ignore these rules, but it could well be you've been bitten by them under Mac OS.
As a step in the officially right direction, try to not do setVisible() until you've assembled the whole thing, i.e. at the bottom of the constructor.
Reference material: http://www.math.vu.nl/~eliens/documents/java/tutorial/ui/swing/threads.html
A guess: add the component before setBoundsing it.
I could be wrong--been a long time since I've done a GUI in java--but I'm guessing your issue is making the JFrame visible before you finish adding elements. I think you need to either do that afterwards, or call update on the frame.
EDIT - Also, not sure setting the layout to null is a good idea. I've always used GridBag, but it might lose its default if you set it to null.