I have a problem when i try to create an extended class from jframe. When i add a panel to the created class with a specific dimension and position it will fill all the window. My code is:
package tuto;
import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class test extends JFrame{
public test(){
super();
initComponents();
}
private void initComponents() {
setBounds(0, 0, 1000, 618);
panel = new JPanel();
panel.setBounds(10, 10, 100, 100);
panel.setBackground(Color.blue);
add(panel);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new test().setVisible(true);
}
});
}
//Components
JPanel panel;
}
After executing the code all the window become blue. Some help please.
JFrame by default, uses a BorderLayout, which is why you component fills the full size of the window. See How to Use BorderLayout for more details.
In fact, I'd recommend also reading through Laying Out Components Within a Container to get a better understanding of how the layout management system.
You should beware that "manual" placement of components is generally discouraged in most cases, instead, you should make use of one or more layout managers.
As a general recommendations, you should also avoid extending from top level containers like JFrame, as it looks you into a single use case, top level containers tend to be complicated, compound components and you're just not adding any new functionality to the class generally. Better to simply create them when you need them and fill them with the components you need.
If you want to use absolute positioning you should set the layout to null.
setLayout(null)
But it’s recommended you have a look at the different layouts. Everything is better than null layouts.
E.g. https://docs.oracle.com/javase/tutorial/uiswing/layout/border.html
Related
How do I make a JLabel text vertically and horizontally aligned to the center?
I have to make use of setHorizontalTextPosition and setVerticalTextPosition. Can this be achieved by using these 2?
I have tried but the text remains at the top itself.
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
public class label extends JFrame
{
private JLabel label;
public label() //constructor
{
super("Simple GUI");
setLayout(new FlowLayout());
label=new JLabel("Centered JLabel");
label.setHorizontalTextPosition(SwingConstants.CENTER);
label.setVerticalTextPosition(SwingConstants.CENTER);
add(label);
}
}
I have tried but the text remains at the top itself.
You have two problems:
Andrew addressed the first problem. You are using the wrong method.
Next you are using the wrong layout. The FlowLayout only display components on a single line so the component will always be at the top. Don't change the layout manager. The default layout manager for a JFrame is the BorderLayout. When you add a component to the CENTER (which is the default when you don't specify a constraint), the component will be sized to fill the entire frame. Then the "alignment" properties will control the position of the text within the size allocated to the label.
Or a different option is to use a GridBagLayout. Then you don't need to play with alignment options of the component:
setLayout( new GridBagLayout() );
add(label, new GridBagConstraints());
Try both options as both may be effective in different situations.
Read the Swing tutorial on Layout Managers to better understand how each layout manager works.
I'm very sorry to don't know why the setHorizontalTextPosition method and the setVerticalTextPosition method doesn't work.
But, I'll let you know that there're several ways to sort the text in the label by inserting parameters an alignment with String when we create the label.
First of all, camickr's answer is the best answer, Because Swing was designed to be used with layout managers!!
Please remember that the most recommended method is to apply GridBagLayout() to the Layout of JFrame by camickr.
This answer is intended to inform you that
This method is also possible, but not recommended in the normal case
Using this method is not recommended because changing the size of the frame
keeps the components in place, but it could give you a little help
when it is indicated that the size and location of components in the
container are used in a way that can be used in special cases, such as
when they need to be fixed without external impact.
To get a better idea of the problem, I'll simply change the code that you uploaded to me so that it can be executed.
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Color;
public class StackOver extends JFrame
{
private JLabel label;
public StackOver() //constructor
{
super("Simple GUI");
setLayout(null);
setSize(500,300);
label=new JLabel("Centered JLabel", JLabel.CENTER);
/*
label.setHorizontalTextPosition(SwingConstants.CENTER);
label.setVerticalTextPosition(SwingConstants.CENTER);*/
add(label);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new StackOver();
}
}
Hmm, let's put some color in JLabel's background to find out more.
label.setOpaque(true); //Transparency Settings
label.setBackground(Color.pink); //Specify background color
//to use 'Color' class, We must import java.awt.Color;
the JFrame setting was set to FlowLayout()which makes the location and size of components were fixed, so we couldn't see it working!
So now we're going to go through the next two processes.
1) Changing JFrame's layout to null to use Absolute Layout ("not recommended, just a case")
2) Changing the size and location of the JLabel
after the progress we can see that the text alignment works!
1) Changing JFrame's Layout
the following link: Layout Manager shows that there are so many Layouts outside of FlowLayout.
Swing is designed to use the layout manager, so of course you should use one of the Layout above link.
But, to use an interesting way that fix the location and size of components absolutely We will switch to setLayout(null);!
2) Changing the size and location of the JLabel
We can directly change the size and position of JLabel with setBounds(int startX, int startY, int Width, int Height) method!
import java.awt.FlowLayout;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Color;
public class StackOver extends JFrame
{
private JLabel label;
public StackOver() //constructor
{
super("Simple GUI");
setLayout(null);
setSize(500,300);
label=new JLabel("Centered JLabel", JLabel.CENTER);
// Since it also sets the size of the JLabel,
//let's use the constructor to set the alignment of the text inside the JLabel.
label.setOpaque(true); //Transparency Settings
label.setBackground(Color.pink); //Specify background color
//to use 'Color' class, We must import java.awt.Color;
Rectangle r = this.getBounds(); //to get Frame Size
label.setBounds(r.x+100, r.y+100, r.width-200, r.height-200);
/*
label.setHorizontalTextPosition(SwingConstants.CENTER);
label.setVerticalTextPosition(SwingConstants.CENTER);*/
add(label);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new StackOver();
}
}
Now we can see the text of JLabel in the middle as intended!
This method can directly fix the size and location of all components (ex buttons), but the location and size of the components are fixed even if the window size of the JFrame changes after the program runs.
so If you really want set components Absolutely by this way, you rather to set JFrame Resizable false by adding below code on JFrame's code
this.setResizable(false);
I hope the answer was helpful to you and have a peaceful day!
Modifiers.java:
package game;
import java.awt.*;
import java.io.*;
import javax.swing.*;
public class Modifiers extends Data{
public static void setupJcomponents(){
frame.setUndecorated(true);
frame.setSize(MW,MH);
frame.setResizable(false);
frame.setVisible(true);
frame.setLayout(null);
for(int btn=0; btn<4; btn++) {
Buttons[btn] = new JPanel();
Buttons[btn].setBounds(btn*100,0,100,100);
Buttons[btn].setVisible(true);
Buttons[btn].setBackground(new Color(btn*50,btn*50,btn*50));
frame.getContentPane().add(Buttons[btn]);
}
menuBackground.setBounds(0,0,MW,MH);
menuBackground.setVisible(true);
menuBackground.setBackground(Color.black);
healthIndicator.setText(String.valueOf(healthValue));
healthIndicator.setFont(new Font("Terminal", Font.PLAIN, 100));
healthIndicator.setBounds(600,600,100,100);
healthIndicator.setForeground(Color.blue);
try{
PixelFont = Font.createFont(Font.TRUETYPE_FONT, new File("PixelFont.ttf"));
} catch (IOException e) {
PixelFont = new Font("Terminal", Font.PLAIN, 100);
} catch(FontFormatException e) {
PixelFont = new Font("Terminal", Font.PLAIN, 100);
}
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(PixelFont);
frame.getContentPane().add(healthIndicator);
frame.getContentPane().add(menuBackground);
}
}
Data.java:
package game;
import java.awt.*;
import javax.swing.*;
public class Data {
// this is where I will declare and alter all variable that will be used
public static JFrame frame = new JFrame();
public static JLabel healthIndicator = new JLabel();
public static JPanel Buttons[] = new JPanel[5];
public static JPanel menuBackground = new JPanel();
public static final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static final int MW = (int) screenSize.getWidth();
public static final int MH = (int) screenSize.getHeight();
public static Font PixelFont;
public static int maxHealth = 100;
public static int healthValue = maxHealth;
}
Frame.java:
package game;
public class Frame {
public static void main(String[] args) {
Modifiers.setupJcomponents();
}
}
whenever i rum Frame.java the menu Background disappears and the text altogether stops showing up. but if the path to the .ttf file is wrong it just skips over the font and uses the default instead. How do i get this font to load properly as well as not cause my background background to disappear? I have tried changing the path to the .ttf file and turning various parts of the code into comments, but even if the font of the health indicator is a default font, these errors will still occur, however if i try removing the try-catch loop then the errors aren't there anymore.
There are all kinds of problems with the code. Not exactly sure why the Fonts is causing an issue, but it has something to do with the overall structure of your code and you aren't using Swing the way it was designed to be used.
whenever i rum Frame.java the menu Background disappears and the text altogether stops showing up
What appears to be directly related to the above question is that the setVisible(true) statement should be executed AFTER all the components have been added to the frame. This will make sure all the components are painted.
Note this will still only work by chance because you happen to add the "background" panel to the frame last. Swing paints components in the reverse order that are added to any given panel.
Regarding other problems.
your painting code only works by chance. You should not be adding all your components directly to the frame. Swing is not designed to paint components in 3 dimensions directly when the components overlap one another. Swing is designed to have a parent child relationship. So that would mean you add your "background" panel to the frame. Then you add a panel containing the buttons to the "background" and you add the "health" component to the background.
Related to above you should NOT be using a null layout. Swing was designed to be used with a layout manager. This will make sure components don't overlap. So in your case you can use a BorderLayout for the "background" panel. Then you can add the "buttons" panel to the BorderLayout.PAGE_Start and the "health" component to the `BorderLayout.PAGE_END. This will ensure that the components are at the top/bottom of the background panel.
Don't set the size of the frame. Instead you use the setExtendedState(JFrame.MAXIMIZED_BOTH) property. The frame will be the size of the screen. The "GamePanel" will be take up all the space of the frame. So there is no need to set or use hardcoded values.
Don't use static variables and method. This indicates poor design. What you should be doing is creating a GamePanel class, which would essentially be your background panel. This class would contain the instance variables needed for the game. It would create the "buttons" panel and the "health" component and add it to itself.
Variable names should NOT start with upper case characters.
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());
}
}
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SimpleExample extends JFrame {
public SimpleExample() {
setTitle("Simple example");
setSize(500, 500);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
JButton jb = new JButton("TEST");
jb.setBorderPainted(true);
jb.setBounds(5, 5, 1, 1); ---> This line
add(jb);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
SimpleExample ex = new SimpleExample();
ex.setVisible(true);
}
});
}
}
Just creating a simple button of a preferred size. The setBounds method doesn't seem to work. Where am I going wrong?
Your frame is under the control of a layout manager, it is making the decisions on how best to layout your components and is overriding the values you have specified using setBounds
Modern GUIs need to run (even on the same OS) in a variety of different graphical environments, including different DPI, screen sizes and font settings for example.
The layout manager makes it possible for you to worry (less) about these issues and it is highly recommended that you make use of them
Take a look at
Using Layout Managers
A Visual Guide to Layout Managers
For more details
As a good practice, you should not add the button directly to the JFrame. Instead, add a JPanel to the frame, set the panel's layout to null, and add the JButton to the JPanel.
I want to put a JPanel in a JApplet, the problem is that I can't see it :( I've overridden the paintComponent of my JPanel in order to have a background image, but I can't see anything. When I remove the paintComponenet method that I had overriden, and set a color to the background of this panel, it seems that JPanel fills the JApplet and still no component is visible :-S I've tried different layouts. I also put my panel in the center of another panel which fills my JApplet but nothing changed, and still no component and no background image is visible :(
import java.awt.BorderLayout;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class Main extends JApplet implements Runnable{
private JTextArea display;
private Thread outputThread;
JPanel boardPanel;
private ClientViewManager view;
#Override
public void init() {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't successfully complete");
}
}
private void createGUI() {
display = new JTextArea(4, 30);
display.setEditable(false);
getContentPane().add(new JScrollPane(display), BorderLayout.SOUTH);
setFocusable(true);
setVisible(true);
setName("CE Tanks");
setSize(600, 600);
setLocation(100, 100);
boardPanel = new JPanel();
boardPanel.setLayout(null);
boardPanel.setBackground(new java.awt.Color(128, 255, 255));
getContentPane().add(boardPanel, BorderLayout.CENTER);
}
public void start() {
outputThread = new Thread(this);
outputThread.start();
}
public void run() {
view = new ClientViewManager();
boardPanel.add(view);
boardPanel.repaint();
repaint();
}
}
class ClientViewManager extends JPanel {
private int rows=8;
private int columns=8;
public ClientViewManager() {
super(null);
JLabel lb= new JLabel("lb.jpg");
lb.setLocation(10, 10);
lb.setSize(50, 50);
lb.setOpaque(false);
lb.setVisible(true);
this.add(lb);
}
public void paintComponent(Graphics g) {
g.drawImage(new ImageIcon("ground.jpg").getImage(), 0, 0, columns * 50,
rows * 50, this);
}
}
The code above can be compiled. I cant even add Keylistener to neither my JPanel nor to my JApplet. I used java.awt.KeyEventDispatcher and in dispatchKeyEvent(KeyEvent e) I printed something in console but, it was printed 3 times. :(
I've overridden the paintComponent of my JPanel inorder to have a background image,
But you didn't add the custom component to your applet:
//boardPanel = new JPanel();
boardPanel = new ClientViewManager();
Also:
get rid of setVisible(). This is not required for any of the controls in your program. By default all components except top level Container (Jframe, JDialog etc) are already visible. In the case of JApplet, you don't need to make it visible as this is part of the process of displaying an applet.
get rid of setSize() and setLocation() you can't control the position of the applet this way.
Don't read the image file in the paintComponent() method. This is not efficient as this method is invoked whenever Swing determines the component needs to be repainted.
JLabels are opaque by default so there is not need to invoke the setOpaque method.
When doing custom painting you should also override the getPreferredSize() method of the component to return the proper size of the custom painting so layout managers can use this information. It works in this case because you added the panel to the CENTER of the BorderLayout. Try adding the panel to the NORTH to see what happens.
Edit:
Now I see where you are adding the ClientViewManager. I'm not sure why you are trying to do this with a Thread but once again there are several problems.
When you add/remove components from a visble GUI then the basic code is:
panel.add(...);
panel.revalidate();
panel.repaint();
However this still won't work because you are using a null layout and the size of the panel is 0. Use a proper layout manager and implement the getPreferredSize() method as suggest above and the component will be displayed properly.
I recommend you to use the GUI Builder of Netbeans to build a GUI like that, and then compare the generated code to your code. Netbeans results really useful to help you create swing code.