Should the panels be fields inside the frame? - java

I created a frame with almost 20 panels inside (all with different kind and characteristics) simply creating them and adding them to the content Panel and remembering his order number for accessing them.
But now I'm trying to generate an UML diagram from the source code and I noticed that i don't have any reference to this panels inside the frame. Should I create 20 field panels and reference them one by one? Or It's just fine? I don't know the right way, thanks!
P.S: I don't know if this matters but my language is Java

The way you write about your panels (all with different kind and characteristics) I suspect that these panels also have different classes.
So to access a specific panel your code probably looks like
((MyPanelType1) getContentPane().getComponent(0)).someMethod();
whereas with fields for every panel
private MyPanelType1 firstPanel;
the code would look like
firstPanel.someMethod();
Now decide which code is easier to read, and decide accordingly.

You can store the panels in JPanel[] array so you can call them any time.
import java.awt.Color;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TestClass {
static JFrame frame = new JFrame();
static JPanel[] panel_order = new JPanel[20]; // 20 the number of panels you have
//generating the panels
public static void main(String[] args){
frame.setBounds(0, 0, 500, 400);
for(int i=0;i<panel_order.length;i++){
JPanel panel = new JPanel();
// you can set the panel's location like:
panel.setBounds(20*i, 0, 80, 50);
//and border if you are making diagrams
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
panel_order[i] = panel;
frame.add(panel);
}
frame.setVisible(true);
//now you can access your panels by calling panel_order[panel_number];
//example display the 5th panel's location
System.out.println(panel_order[5].getLocation());
}
}

Related

Cannot refer to the non-final local variable display defined in an enclosing scope

This might be a very basic question. But I am stuck at this. The error that I get for the String variable display states:
Cannot refer to the non-final local variable display defined in an enclosing scope.
If I use a final keyword, I get the message:
The final local variable display cannot be assigned, since it is defined in an enclosing slope.*
The code is:
public class Frame {
public static void main(String[] args) {
String display=" ";
Frame ob=new Frame();
JFrame frame=new JFrame("Test");
frame.setBounds(300,100,800,500);
//Container c=frame.getContentPane();
frame.setLayout(null);
final JTextField name=new JTextField();
name.setBounds(500,212,150,20);
JLabel nameLabel=new JLabel("Name: ");
nameLabel.setForeground(Color.WHITE);
nameLabel.setBounds(450,171,100,100);
JTextField ohr=new JTextField();
ohr.setBounds(500,282,150,20);
JLabel ohrID=new JLabel("OHR ID: ");
ohrID.setForeground(Color.WHITE);
ohrID.setBounds(450,241,100,100);
final JButton button=new JButton("Submit");
button.setBounds(530,350,90,20);
frame.add(name);
frame.add(ohr);
frame.add(ohrID);
frame.add(nameLabel);
frame.add(button);
frame.getContentPane().setBackground(Color.DARK_GRAY);
frame.setVisible(true);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if(e.getSource()==button){
display=name.getText();
JOptionPane.showMessageDialog(null, "Hi "+ display);
System.exit(0);
}
}
});
}
Thanks in advance!
There are multiple issues with your code, and we'll address them right here, right now and solve your problem at the same time.
public class Frame { this particular line has an error, Frame is the name of an AWT class, so it might confuse you or anyone who reads this code later on, give it a more meaningful name and avoid those names that could be confused with other Java packages.
Frame ob=new Frame(); you create an instance of your class and never use it again, why?
frame.setLayout(null); NEVER, please don't use null-layout, Swing has to deal with multiple PLAFs, screen sizes and resolutions, different OS, pixel perfect apps might seem like the easiest way to create complex UIs but later on you'll find that errors like this happen very often.
.setBounds(...) on every component, again, this is due to null-layout but it's better to use Layout managers
final JTextField name=new JTextField(); There's no need to declare any of your components as final, this is due to a poor design of your class, your components should be declared as class members (outside any method including main).
Speaking about main, separate your program into smaller pieces, don't throw everything at main or at the very least create a method that is not static so you can call it after creating an instance of your class (or else later on you'll end up with tons of static variables and that's a poor design of your class once again).
System.exit(0); it will stop the JVM, it's never a good idea to do that, it's better to .dispose() the JFrame and have your JFrame's defaultCloseOperation set to EXIT_ON_CLOSE which will safely dispose your app and then stop the JVM.
display=name.getText();, for this particular case, display could be an inner variable rather than a class member. This will solve your particular question
JOptionPane.showMessageDialog(null, "Hi "+ display); that null should be a reference to your JFrame, this will place your dialog in the middle of that JFrame rather than in the middle of the screen.
You never place your program inside the EDT, see point #2 in this answer.
So, having all the above points in mind, here's an improved version of your code.
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class UsingVariablesInsideActionListenerExample {
//We declare our components here
private JFrame frame;
private JButton button;
private JTextField name;
private JTextField ohr;
private JLabel nameLabel;
private JLabel ohrID;
private JPanel pane;
private JPanel namePane;
private JPanel ohrPane;
public static void main(String[] args) {
SwingUtilities.invokeLater(new UsingVariablesInsideActionListenerExample()::createAndShowGUI); //This is using Java 8 lambdas to place your program in the EDT
}
private void createAndShowGUI() {
frame = new JFrame("Test"); //Create your JFrame
pane = new JPanel();
pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS)); //This will make this JPanel to arrange components vertically
namePane = new JPanel(); //By default, JPanels have FlowLayout which will arrange components horizontally
ohrPane = new JPanel();
name = new JTextField(10); //We create a JTextField with 10 columns
nameLabel = new JLabel("Name: ");
nameLabel.setForeground(Color.WHITE);
ohr = new JTextField(10);
ohrID = new JLabel("OHR ID: ");
ohrID.setForeground(Color.WHITE);
button = new JButton("Submit");
//Add the action listener
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
String display = name.getText(); //The display variable is now an inner variable rather than a class member
JOptionPane.showMessageDialog(frame, "Hi " + display);
frame.dispose(); //We dispose the JFrame and it will be closed after due to EXIT_ON_CLOSE below.
}
}
});
//We add the components to the namePane (horizontally), the order matters
namePane.add(nameLabel);
namePane.add(name);
//Now we add these components to the ohrPane (horizontally again)
ohrPane.add(ohrID);
ohrPane.add(ohr);
//We then add the name and ohr panes to a bigger JPanel (pane, which if you remember will add them vertically) and we add the button at the end
pane.add(namePane);
pane.add(ohrPane);
pane.add(button);
//We make them non opaque (transparent) so that we can see the background color of the JFrame
namePane.setOpaque(false);
ohrPane.setOpaque(false);
pane.setOpaque(false);
frame.add(pane);
frame.getContentPane().setBackground(Color.DARK_GRAY);
frame.pack(); //This will get every component's preferred size and make the JFrame as small as possible where it looks good on every OS, PLAF, screen size and resolution.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true); //We make the frame visible (always at the very end, when we've added everything to it).
}
}
And this is how it looks like now.
The UI may not be perfectly equal to the one you have, but I'm sure you can play with the different layout managers, and nest various JPanels to get a much better looking UI than mine, or at least a more similar one to the one you had.
Variable used in side an inner class should be effectively final . You can use a string[] of length 1 instead of string to resolve this . Please read bellow post for more details
Difference between final and effectively final
Also check this post for more details
Variable used in lambda expression should be final or effectively final

Keeping components horizontally aligned using a flow layout manager

For reasons I won't discuss in detail, I am limited to using a flow layout manager. The obvious problem with this and my necessity to keep components on the same line, is that it pushes components further down the frame is they surpass the panel edges.
Are there methods I can use to align components to make sure that labels and their corresponding text fields appear on the same line?
If I have understood correctly, the main problem is that the label and the input are separated (the label on the right side, and the input in the next line on the left).
One solution for that problem is the group the label and the input field into a sub panel, and add this sub panel to the main panel which uses the FlowLayout.
The code below illustrates this technique:
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
/**
*
* #author acampos
*/
public class Main02 {
public static void main(String[] args) {
JFrame jFrame = new JFrame();
JPanel mainPanel = new JPanel();
JPanel dynamicPanel;
JLabel dynamicLabel;
JTextField dynamicInput;
for (int i = 0; i < 5; i++) {
// Creates the panel that will contain the Label AND the Input
dynamicPanel = new JPanel();
// Creates the dynamic label
dynamicLabel = new JLabel("Label " + i + ": ");
// Creates the dynamic text field
dynamicInput = new JTextField(10);
// Adds the label and the text field to the dynamic panel
dynamicPanel.add(dynamicLabel);
dynamicPanel.add(dynamicInput);
dynamicPanel.setSize(100, 100 );
// Adds the dynamic panel to the main panel <-- HERE IS THE KEY
mainPanel.add(dynamicPanel);
}
// Set the FlowLayout to the MAIN PANEL, so the dynamic panels
// will 'flow' but the label and the text field will be kept together
mainPanel.setLayout(new FlowLayout(3));
// Adds the main panel (which contains the dynamic panels) to the main frame
jFrame.add( mainPanel );
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setVisible(true);
jFrame.setSize(600, 150);
jFrame.setResizable(true);
}
}
When you run this code (yes, you can run it) and change the jFrame's size you see that the label and the input don't split anymore.
Note: For the next questions, I strongly suggest you that you share your code with the community. That's a good practice that is more detailed on https://stackoverflow.com/help/how-to-ask

How can i add two components to my screen without them overlapping and only showing one?

Right now i can only have one of my two components show up on the screen the second one always just overlaps the first so the second is only showing.
How can I get both of them to show up at the same time.
package Game;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.io.IOException;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Amazing {
private final int width = 300;
private final int height = width / 16 * 9;
private int scale = 3;
private static Graphics g;
private static JFrame frame = new JFrame();
public Amazing(){
Dimension size = new Dimension(width*scale, height*scale);
frame.setPreferredSize(size);
frame.setResizable(false);
frame.setTitle("Amazing!");
Character character = new Character(50,50,scale,width,height);
Map map = new Map(scale, width, height);
frame.add(map);
frame.add(character);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
character.requestFocus();
}
public static void main(String[] args){
Amazing amazing = new Amazing();
}
}
I figured you don't need to see the other two classes(if you want i can also post them) but I think all you need to know about them are that the map class creates and paints with paintComponent(Graphics g) 2 randomly generated rectangles while the Character class creates and uses the paintComponent(Graphics g) method to show and Image on the screen.
Since you didn't specify a layout, you were using BorderLayout which only displays 1 component in each section. Unless you specify a different location as an additional arg when using the default BorderLayout, the add(component) method will "overwrite" whatever was there previously. Therefore, when you add your second component to your frame it overwrites the first.
I noticed that you imported GridLayout, but i don't see it used in your code. If you add a statement in the constructor like:
this.setLayout(new GridLayout(4, 2));
it will change the layout from the default BorderLayout to the GridLayout, and you will have 4 rows of 2 compartments each in which to place components. Calling the add(component) method will add a component in the next available section, starting with row 1 spot 1.
If you only want to add those two items, try putting in the statement
this.setLayout(new GridLayout(1, 2));
before you add your components. This will place them side by side.
When adding components to a panel in Swing you should choose a LayoutManager for the panel (FlowLayout is simple, GridBoxLayout flexible, but there are many more). Depending on the layout chosen you also associate data with the component to tell the LayoutManager where to place the component.
The "main" problem you're having is the fact that by default JFrame uses a BorderLayout. BorderLayout will only only a single component to occupy each of its five available positions. By default, BorderLayout will place components at the CENTER position.
You should explore a different layout manager which meets your requirements.
Take a look at Laying Out Components Within a Container

Adding an unknown number of JComponents to a JPanel

Good day,
I am building an Applet (JApplet to be exact) and I sub divided that into two panels. The top panel is called DisplayPanel which is a custom class that extends JPanel. The bottom panel is called InputPanel which also extends JPanel.
As mentioned above, I can add those two Panel's to the applet and they display fine. The next thing that I would like to do is have the InputPanel be able to hold a random number of JComponent Objects all listed veritcally. This means that the InputPanel should be able to have JButtons, JLabels, JTextFields etc thrown at it. I then want the InputPanel to display some sort of scrolling capability.
The catch is that since these two panels are already inside my applet, I need the InputPanel to stay the same size as it was given when added to the Applet. So for example, if my applet (from the web-browser html code) was given the size 700,700, and then the DisplayPanel was 700 by 350, and the InputPanel was below it with the same dimensions, I want to then be able to add lots of JComponents like buttons, to the InputPanel and the panel would stay 700 x 350 in the same position that it is at, only the panel would have scroll bars if needed.
I've played with many different combinations of JScrollPane, but just cannot get it.
Thank you.
Good day,
Okay, I was able to answer what I was trying to do, so I thought I would post an answer for future reference. Remember, my goal was to have two panels attached to a JApplet and then the bottom panel should have been able to take in as many JComponents as need be and the size of the Applet wouldn't change, but the bottom panel would then be scrollable with JScrollPane.
This is useful for if in the top Panel you some how select an object and then down below a panel is displayed that you can then control that object that you selected. I am making a network simulator where in the top panel you have a network diagram and you can select a host for example, and then set its IP address. But then if you select a firewall for example, you can determine what ports to block.
I hope this helps and thanks #Andrew Thompson.
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class Applet extends JApplet
{
JPanel p1;
JPanel p2;
JPanel p3;
JScrollPane s1;
public Applet()
{
p1 = new JPanel();
p2 = new JPanel();
p3 = new JPanel();
s1 = new JScrollPane(p3,s1.VERTICAL_SCROLLBAR_ALWAYS,s1.HORIZONTAL_SCROLLBAR_ALWAYS);
}
#Override
public void init()
{
super.init();
for(int i=0;i<100;i++)
{
p3.add(new JButton("Hello"));
p3.add(new JLabel("blah"));
p3.add(new JButton("Sup"));
}
p1.setPreferredSize(new Dimension(this.getWidth(), this.getHeight()));
p2.setPreferredSize(new Dimension(this.getWidth(),(int) (this.getHeight()*0.6667)));
p3.setLayout(new BoxLayout(p3,BoxLayout.PAGE_AXIS));
s1.setPreferredSize(new Dimension(this.getWidth(),(int)(this.getHeight()*0.33333)));
p1.add(p2);
p1.add(s1);
this.add(p1);
}
}

JFrame not being made at right dimensions

This code, when run, will make a window but not at the specified dimensions. What is wrong with it?
import javax.swing.*;
import java.awt.*;
public class Windowing {
void JFrame(){
JFrame frames = new JFrame("Total recall");
frames.setSize(1000,8000);
frames.setVisible(true);
frames.pack();
//Buttons push = new Buttons();
//((Buttons) push).buttons();
JTextField wager = new JTextField(1);
wager.setSize(100,200);
wager.setVisible(true);
wager.setLocation(100, 200);
frames.add(wager);
//frames.add(push);
}
}
You could remove the call to frames.pack(); it overrides the previously set frame size.
However, what you really want to do is remove the frames.setSize(1000,8000) and move frames.pack() down to the bottom of the method; that will ensure that the frame is big enough to display its contents but not too big to fit on the screen.
If you call pack before adding anything to the frame (like you are doing now), it will make the window extremely small; it's probably appearing near the upper left of your screen, but you won't notice it unless you know where to look.
It looks like you have a number of "opportunity areas" here.
To start, it seems like you set frame size to 1000x8000 because you didn't see any change right?
Secondly you call setVisible on the textField because you didn't see that either.
And finally you're setting the size of the textfield ( I guess because you're seeing it take the whole frame )
The problem here is that you have to invoke pack and setVisible at the end of the construction. Also, you have to learn how to use layout managers and frames.
Swing, is very powerful, but it is a bit hard to grasp at the beginning.
These two links will be helpful:
How to make frames
Using Layout Managers
I've changed your code and the result looks like this:
Here's the modified source code.
import javax.swing.*;
import java.awt.*;
public class Windowing {
public static void main( String [] args ) {
Windowing windowing = new Windowing();
windowing.showFrame();
}
void showFrame(){
JFrame frame = new JFrame("Total recall");
JButton push = new JButton("Push");
JTextField wager = new JTextField(15);
// Panels do have "FlowLayout"
JPanel panel = new JPanel();
panel.add(wager);
panel.add(push);
frame.add( panel );
frame.pack();
frame.setVisible(true);
}
}
Try to use setPreferredSize(Dimension) instead.

Categories