Inconsistent results in Eclipse for Java Swing - java

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.

Related

Invisible JButton in JPanel

Here's my JPanel. The first button is always visible, but the secound is visible only when you place a cursour on it. Where the problem can be?
P.S. Please use simple english, if u can, because I don't speak english well
public class GamePanel extends JPanel implements KeyListener{
GamePanel(){
setLayout(null);
}
public void paint(Graphics g){
JButton buttonShip1 = new JButton();
buttonShip1.setLocation(10, 45);
buttonShip1.setSize(40, 40);
buttonShip1.setVisible(true);
add(buttonShip1);
JButton buttonShip2 = new JButton();
buttonShip2.setLocation(110, 145);
buttonShip2.setSize(440, 440);
buttonShip2.setVisible(true);
add(buttonShip2);
}
}
If you want to avoid problems and learn Java Swing correctly, go check out their tutorials here.
There are too many problems to discuss here, so I'll try to keep it simple.
You're using a null layout. null layouts are avoided for the most part because there is usually a layout that does exactly what you want. It takes some time to get it working, but there are some defaults in this tutorial that are fairly simple to use. There are some nice pictures there that show you what you can do with each layout, too. If you use a layout manager, you generally don't need to use setLocation, setSize or setVisible on most components like JButtons.
You're calling the paint method in a Swing application. You want to call paintComponent because you're using Swing and not Awt. You also need to call the super.paintComponent(g) method on the first line of the paintComponent method in order to correctly override the other paintComponent method.
The paint/paintComponent related methods are called very often. You don't want to create/initialize objects in them. The paint/paintComponent methods aren't a one time method like they may sound. They're continuously called and you should design your GUI around this. Design your paint-related methods to be event-driven rather than sequential. In other words, program the paintComponent method with the mindset that your GUI is reacting to things continuously rather than running in sequential order like a normal program. That's a very basic approach to it and hopefully doesn't confuse you, but if you go check out that tutorial you'll see what I mean eventually.
There are two basic types of GUIs in Java. One is Swing and the
other is Awt. Check out this answer on stackoverflow for a
nice description of the two.
Here is an example of what two buttons on a JPanel look like.
public class Test
{
public static void main(String[] args)
{
JFrame jframe = new JFrame();
GamePanel gp = new GamePanel();
jframe.setContentPane(gp);
jframe.setVisible(true);
jframe.setSize(500,500);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static class GamePanel extends JPanel{
GamePanel() {
JButton buttonShip1 = new JButton("Button number 1");
JButton buttonShip2 = new JButton("Button number 2");
add(buttonShip1);
add(buttonShip2);
//setLayout(null);
//if you don't use a layout manager and don't set it to null
//it will automatically set it to a FlowLayout.
}
public void paintComponent(Graphics g){
super.paintComponent(g);
// ... add stuff here later
// when you've read more about Swing and
// painting in Swing applications
}
}
}
Don't use a null layout
Don't create components in a painting method. The paint() method is for custom painting only. There is no need for you to override the paint() method.
Read the section from the Swing tutorial How to Use FlowLayout for a simple example that uses buttons and a layout manager.

adding swing components at run time in netbeans [duplicate]

This question already has answers here:
Closed 10 years ago.
i have learnt core java and just started working with netbeans,but i am stuck at a point when i was trying to add the components like buttons,labels etc. at the run time in my project.I searched for it on google but the examples which i studied include some extra overhead of using panels in them,,,,but why can't i create the components at run time as i was creating them in the simple editor like notepad as follows
JButton b4=new JButton("ok");
add b4;
its not working.
To add Swing framework elements at runtime, you need to have a JFrame to add the elements to. A JFrame is just a window, like any other window you use (and just like NetBeans has), and it has a method called add(Component comp). The parameter is whichever Swing or AWT component you want to add to the JFrame. Here is some sample code to get you started:
// This line creates a new window to display the UI elements:
JFrame window = new JFrame("Window title goes here");
// Set a size for the window:
window.setSize(600, 400);
// Make the entire program close when the window closes:
// (Prevents unintentional background running)
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// This makes it so we can position elements freely:
window.setLayout(null);
// Create a new button:
JButton b4 = new JButton("ok");
// Set the location and size of the button:
b4.setLocation(10, 10);
b4.setSize(100, 26);
// Add the button to the window:
window.add(b4);
// Make the window visible (this is the only way to show the window):
window.setVisible(true);
Hopefully, this helps you out! I remember when I started Java, and I would highly recommend getting as good as possible at non-GUI related stuff first, but if you are ready for Swing, then the code above should work. Best of luck!

how can I use a variable in multiple jpanels?

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

Can I add elements to a Java GUI?

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.

GUI objects not showing in Java on Mac

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.

Categories