I have problems with understanding the behavior of my application. I want to create a simple window (1000x700px), divided into two parts (250px and 750px width respectively). I tried the following code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Example extends JFrame
{
private static final long serialVersionUID = 1L;
public Example()
{
this.setSize(1000, 700);
this.setTitle("Example");
this.setResizable(false);
this.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
JPanel navigation_panel_wrap = new JPanel();
JPanel content_panel_wrap = new JPanel();
navigation_panel_wrap.setPreferredSize(new Dimension(250, 700));
content_panel_wrap.setPreferredSize(new Dimension(750, 700));
content_panel_wrap.setBackground(Color.green);
navigation_panel_wrap.setBackground(Color.red);
this.getContentPane().add(navigation_panel_wrap);
this.getContentPane().add(content_panel_wrap);
}
public static void main(String[] args)
{
Example example = new Example();
example.setVisible(true);
}
}
As you can see I manually set layout manager for JFrame (FlowLayout instead of BorderLayout with zero horizontal and vertical gaps). Of course, I can just use BorderLayout and than use add() method with BorderLayout.EAST and BorderLayout.WEST parameters, but I want to understand what's wrong with FlowLayout.
When I run my application, I get the following (no green JPanel):
If I decrease width of, for example, content_panel_wrap and make it 744px instead of 750px, everything works correctly.
So the question is - what are these strange 6 pixels? I'm not sure this value is constant for all operating systems, so I want to understand its origin.
There's nothing wrong with FlowLayout but you will need to call pack() for all components to be sized.
As for your codes problem (+1 to #Reimeus) calling pack() is the solution.
as per docs:
Causes this Window to be sized to fit the preferred size and layouts
of its subcomponents. If the window and/or its owner are not yet
displayable, both are made displayable before calculating the
preferred size. The Window will be validated after the preferredSize
is calculated.
Tips:
Dont extend JFrame unnecessarily.
Use Event Dispatch Thread when creating and changing UI components:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// create UI components etc here
}
});
Dont call setPreferredSize() rather override getPrefferedSize() of component.
Dont call setSize(...) on JFrame rather call JFrame#pack() before setting it visible.
Dont forget to call JFrame#defaultCloseOperation(..) or your initial/EDT thread will not be terminated when JFrame is closed.
Here is an example combining my advice and your code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Example {
private final JFrame frame;
public Example() {
frame = new JFrame();
frame.setTitle("Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//app exited when frame closes
frame.setResizable(false);
frame.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
JPanel navigation_panel_wrap = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(250, 700);
}
};
JPanel content_panel_wrap = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(750, 700);
}
};
content_panel_wrap.setBackground(Color.green);
navigation_panel_wrap.setBackground(Color.red);
frame.add(navigation_panel_wrap);
frame.add(content_panel_wrap);
//pack frame (size components to preferred size)
frame.pack();
frame.setVisible(true);//make frame visible
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
}
Related
What's wrong? ImageIcon and the frame's size are working properly.
But the JTextField and the JButton aren't.
I need the solution.
import javax.swing.*;
import javax.swing.ImageIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Frame {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setTitle("Alkalmazás");
frame.setVisible(true);
frame.setSize(500,500);
frame.setResizable(false);
JTextField field = new JTextField();
field.setBounds(40,250, 300,35);
JButton button = new JButton(new ImageIcon("table.png"));
button.setBounds(40,400, 250,25);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
tf.setText(""something);
}
});
frame.add(field);
frame.add(button);
}
}
You didn't mention what's "not working properly", but there are a few errors with your code:
Don't call your class Frame, it may confuse you or others about java.awt.Frame, something that may work would be MyFrame
Right now all your class is inside the main method and it's not placed inside the Event Dispatch Thread (EDT), to fix this, create an instance of your class and call a method createAndShowGUI (or whatever you want to name it) inside SwingUtilities.invokeLater()
For Example:
public static void main(String args[]) {
SwingUtilities.invokeLater(new MyFrame()::createAndShowGUI)
}
Or if using Java 7 or lower, use the code inside this answer in point #2.
setVisible(true) should be the last line in your code, otherwise you may find some visual glitches that may be resolved until you move your mouse above your window or something that triggers the call to repaint() of your components.
Instead of calling setSize(...) directly, you should override getPreferredSize(...) of your JPanel and then call pack() on your JFrame, see this question and the answers in it: Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
You're adding 2 components to the CENTER of BorderLayout, which is a JFrame's default layout manager, there are other layout managers and you can combine them to make complex GUI's.
setBounds(...) might mean that you're using null-layout, which might seem like the easiest way to create complex layouts, however you will find yourself in situations like this one if you take that approach, it's better to let Swing do the calculations for you while you use layout managers. For more, read: Why is it frowned upon to use a null layout in Swing?
With all the above tips now in mind, you may have a code similar to this one:
import java.awt.Dimension;
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.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class MyFrame {
private JFrame frame;
private JPanel pane;
private JTextField field;
private JButton button;
public static void main(String[] args) {
SwingUtilities.invokeLater(new MyFrame()::createAndShowGUI);
}
private void createAndShowGUI() {
frame = new JFrame("Alkalmazás");
pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
};
pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS));
field = new JTextField(10);
button = new JButton("Click me");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
field.setText("something");
}
});
pane.add(field);
pane.add(button);
frame.add(pane);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Now you have an output similar to this one:
What about you want the JTextField to have a more "normal" size? Like this one:
You'll have to embed field inside another JPanel (with FlowLayout (the default layout manager of JPanel)), and then add that second JPanel to pane, I'm not writing the code for that as I'm leaving that as an exercise to you so you learn how to use multiple layout managers
I've made a JFrame with Diferent JButtons and i'd like to get an image from another class. Any ideas? Or how draw on the same class but on the action performed?
Because it doesnt let me to do any drawings...my complier always gives me error messages
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import javax.swing.*;
public class red extends JFrame {
public JButton b;
public JButton b1;
public JButton b2;
public JButton b3;
public JButton b4;
public static Image p;
public static Graphics g;
public red() throws IOException {
gui1 x = new gui1();
setTitle(" ");
setSize(1200,700);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
b= new JButton("click");
b1= new JButton();
b.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e0){
b1.setBounds(0, 0, 200, 200);
b.show(false);
add(x);
}
});
b.setBounds(0, 0, 100, 100);
add(b1);
add(b);
setVisible(true);
}
public static void main(String[] args) throws IOException {
red k = new red();
}
}
import java.awt.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class gui1 extends Canvas {
public static Image p;
public void paint(Graphics g){
g.drawImage(p, 700, 200, 100, 100, this);
}
{
try {
p= ImageIO.read(new File("Lighthouse.jpg"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Phew! I see A LOT of errors in your code (even after I corrected the compilation errors):
You're not following the Java naming conventions:
Class names should be nouns, in mixed case with the first letter of each internal word capitalized
while red is a noun it should be more descriptive and be capitalized. The same goes for gui1
You're extending JFrame which in plain english would say: red is a JFrame, you should really avoid this and create your GUI based on JPanels instead... see Java Swing using extends JFrame vs callint it inside of class
You're setting size (a REAAAAAAALLY big one window for the JButton sizes you're using), instead use pack()
You're using null-layout, while pixel-perfect GUIs might seem like the easiest way to create complex GUIs for Swing newbies, the more you use them the more problems related to this you'll find in the future, they are hard to maintain and cause random problems, they don't resize, etc. Please read Null layout is evil and Why is it frowned upon to use a null layout in Swing? for more information about why you should avoid its use and why you should change your GUI to work with Layout Managers along with Empty Borders for extra spacing between components.
You're making use of a deprecated method JFrame#show() you should be using JFrame#setVisible(...) instead.
Related to point #4, you shouldn't be calling setBounds(...) method, but let that calculations to the layout managers.
You're not placing your program on the Event Dispatch Thread (EDT), Swing is not thread safe, you can fix this by changing your main() method as follows:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//Your constructor here
}
});
}
You're mixing AWT and Swing components, instead of using AWT's Canvas use Swing's JPanel which has more functionality and support.
Images will become embedded resources once they're packaged in a JAR file, so it's wise to start treating them as if they already were, not as external files as shown in the embedded-resource tag.
Once you change from Canvas to JPanel you should override its paintComponent(...) method and not paint(...) and call it's super.paintComponent(g) method as the first line, also don't forget to add the #Overrides annotation. See the tutorial on Swing custom painting.
You're abusing the use of static keyword, see how does the static keyword works?
After seeing all the above errors I recommend you to go back and Learn the basics of the language before starting with a graphical environment which will only add more difficulty to your learning.
From what I understand you want to draw an image on a button click, if that's the case then you can wrap your image in a JLabel and add that JLabel to a JPanel which then is added to a parent JPanel which is later added to the JFrame:
As you can see in the GIF above, the icon is displayed after user presses the button.
Obviously this can be improved for the GUI to be more "attractive" with combinations of layout managers and empty borders as stated before.
This was done with the following code:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ImageDrawingFromOneClassToAnother {
private JFrame frame;
private JPanel pane;
private JPanel leftPane;
private JPanel rightPane;
private ImageIcon icon;
private JButton button;
private JLabel label;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ImageDrawingFromOneClassToAnother().createAndShowGui();
}
});
}
public void createAndShowGui() {
frame = new JFrame(getClass().getSimpleName());
icon = new ImageIcon(this.getClass().getResource("king.png")); //Read images as if they were already embedded resources
button = new JButton("Draw image");
label = new JLabel(""); //Create an empty label
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setIcon(icon); //On button click, we set the icon for the empty label
}
});
pane = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200); //Set a size for the main panel
}
};
pane.setLayout(new GridLayout(1, 2)); //The main panel
leftPane = new JPanel(); //The button panel
leftPane.setLayout(new BoxLayout(leftPane, BoxLayout.PAGE_AXIS));
leftPane.add(button);
rightPane = new JPanel(); //The panel where the image will be drawn
rightPane.add(label);
//We add both (button and image) panels to the main panel
pane.add(leftPane);
pane.add(rightPane);
frame.add(pane); //Add the main panel to the frame
frame.pack(); //Calculate its preferred size
frame.setVisible(true); //Set it to be visible
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
frame.add(new JLabel(new ImageIcon("C:/Users/Sam/Pictures/DesktopBackgrounds/image.png")));
I saw this on another question so i tried to use it and the class runs with no errors however no image is on the screen.
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
class FullSceenToggleAction extends AbstractAction {
private JFrame frame;
private GraphicsDevice fullscreenDevice;
public FullSceenToggleAction(JFrame frame) {
this(frame, GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice());
}
public FullSceenToggleAction(JFrame frame, GraphicsDevice fullscreenDevice) {
this.frame = frame;
this.fullscreenDevice = fullscreenDevice;
}
#Override
public void actionPerformed(ActionEvent e) {
frame.dispose();
if (frame.isUndecorated()) {
fullscreenDevice.setFullScreenWindow(null);
frame.setUndecorated(false);
} else {
frame.setUndecorated(true);
fullscreenDevice.setFullScreenWindow(frame);
}
frame.setVisible(true);
frame.repaint();
}
}
public class Main {
public static final void addKeyBinding(JComponent c, String key, final Action action) {
c.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(key), key);
c.getActionMap().put(key, action);
c.setFocusable(true);
}
public static void main(String[] args) {
final JFrame frame = new JFrame("Fullscreen Toggle Test");
Container contentPane = frame.getContentPane();
contentPane.add(new JLabel("Hey"), BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(960, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setTitle("Virtual World");
frame.add(new JLabel(new ImageIcon("C:/Users/Sam/Pictures/DesktopBackgrounds/image.png")));
addKeyBinding(frame.getRootPane(), "F11", new FullSceenToggleAction(frame));
}
}
In case you need it this is the full code.
There are several issues with your codes. In Swing, the order of your codes does makes a difference.
Code order issue:
Currently you are adding an image to the frame after you set the size. When the frame size changes, the paint manager will be consulted to repaint the frame. Hence you will only be able to see the "Hey" label you added earlier but not the image.
It is advisable to set the size after you added all the components you need. If not, you may want to revalidate() your frame later.
I will usually setup the components in the following order:
// Create frame
// Set default close operation for frame
// Add components or container to frame
// pack the frame (frame will be repainted by this action)
// set visible as true
Layout issue:
You are using the frame's default layout (BorderLayout). If you do not state the position/direction for the components to be added in BorderLayout, it will be added to the CENTER by BorderLayout's default.
In your codes, you added the image (2nd label) without stating the position (String specification). Doing so will replace the first label with the second label. Hence only one component will be shown in the frame.
Other issues:
There are some other issues which I would summarize below:
It is advisable to setVisible(true) last to prevent flickering issues.
I would prefer to add another container such as JPanel into the JFrame and add the components in the panel instead of adding directly to the frame.
With the above, you can pack() the frame which allows it to determine its own preferredSize according to the added components.
Try adding imageIcon Label to content pane works.
Container contentPane = frame.getContentPane();
contentPane.add(new JLabel("Hey"), BorderLayout.SOUTH);
contentPane.add(new JLabel(new ImageIcon("C:/Users/Sam/Pictures/DesktopBackgrounds/image.png")));
you may find the code helpful.I posted this code for understanding purpose.
public class AddingIconJLabel {
public static void main(String[] args) {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
frame.setTitle("JLabel Test");
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ImageIcon imageIcon = new ImageIcon("C:/Users/Sam/Pictures/DesktopBackgrounds/image.png");
JLabel label = new JLabel(imageIcon);
frame.add(label);
frame.pack();
frame.setVisible(true);
}
}
this will output the following..Hope you found my help useful.
When I add Swing component (like a JButton) to a JPanel, it renders with it's 'preferred size'.
However, the preferred size is actually larger than the painted button. There appears to be an invisible border around it.
Here's a simple frame with my test panel:
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TestPanel pnl = new TestPanel();
frame.getContentPane().add(pnl);
frame.pack();
frame.setVisible(true);
Here's my test panel ...
public class TestPanel extends JPanel {
JButton btn1 = new JButton("Test1");
JButton btn2 = new JButton("Test2");
public TestPanel() {
this.add(btn1);
this.add(btn2);
}
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
Dimension dim = btn1.getPreferredSize();
g.drawRect(btn1.getX(), btn1.getY(), (int)(dim.getWidth()), (int)(dim.getHeight()));
}
}
Notice I painted btn1's "PreferredSize" in RED to demonstrate that the preferredSize is actually larger than the button itself.
My question is, how can I determine the width and height of the painted button, not the JButton's preferredSize?
Any help is greatly appreciated, thanks!
UPDATE
Because I actually need this to work for all Swing components, here's a screen shot with the more components.
Unfortunately, I need to figure this out, determining the "real" size of the visible widget is crucial to my application.
I don't think this is particular or practically achievable.
The problem is, the button is using the "unpainted" area to paint other elements, like the focus highlight.
You could try look at the AbstractButton#set/getMargin
If nothing better comes along, note that the authors "recommend that you put the component in a JPanel and set the border on the JPanel."
Addendum: Based on your comments below, it's clear that your question is not about rendering borders but about establishing a component's boundary. What you perceive as unused space is actually reserved by the UI delegate for any number of uses, e.g. selection highlighting or esthetic coherence. You can get an idea of how this varies by selecting different Look & Feel themes in the examples here and here.
Using getbounds():
Using setBorder():
import component.Laf;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/**
* #see https://stackoverflow.com/a/15490187/230513
*/
public class Test {
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setLayout(new FlowLayout());
// https://stackoverflow.com/a/11949899/230513
f.add(Laf.createToolBar(f));
f.add(decorate(new JButton("Test")));
f.add(decorate(new JTextField("Test")));
f.add(decorate(new JTextArea(3, 8)));
f.add(decorate(new JCheckBox("Test")));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private JPanel decorate(final JComponent c) {
JPanel p = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Rectangle r = c.getBounds();
g.setColor(Color.red);
// NB pen hangs down and to the right
g.drawRect(r.x - 1, r.y - 1, r.width + 1, r.height + 1);
}
};
p.add(c);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Test().display();
}
});
}
}
Im very new to java. I don't know what's wrong with my frame. I set the size to 300 and 200.
What Im seeing is a short and fat stick like thing.
Below is my code:
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.JFrame;
public class BicycleDemo extends JFrame {
/**
* The serialVersionUID.
*/
private static final long serialVersionUID = -4541236176053545919L;
public static void createGUI () {
JFrame jFrame = new JFrame("JFrame Demo");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container container = jFrame.getContentPane();
container.setLayout(new FlowLayout());
container.setBackground(Color.BLACK);
jFrame.setSize(300, 200);
jFrame.setResizable(false);
jFrame.pack();
jFrame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGUI ();
}
});
}
}
Please help.
You are calling pack(). pack() method resizes the frame to the smallest possible size to hold all the elements. So in fact you set the size to 200 x 300 and then resize the frame once more with pack().
Be aware however, that "hold all elements" is calculated by their preferred size, which can be just 0x0 pixels in a lot of cases.