Hi Im using the setBounds method to open a window whith a certain size. But the size that I pass in the argument is the size of the window including the bars of the frame. How can I set the dimensions only for the content?
Set the size of the content, then call pack() on the JFrame.
Edit: Because Guillaume Polet will not stop griefing me, here is a complete working example. Notice how you don't need to (mis)use inheritance at all, and it gets the job done in much fewer lines:
import java.awt.Dimension;
import javax.swing.JFrame;
public class Main {
public static void main(String... args) {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setPreferredSize(new Dimension(500, 500));
frame.pack();
frame.setVisible(true);
}
}
There are 2 ways to fix this:
Take into account the border of the frame when setting the bounds of the frame
Override getPreferredSize() of the content pane of the JFrame and then call pack() on the frame.
Here is a demo of the two techniques:
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
protected void initUI() {
JFrame frame = new JFrame("Insets technique");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
Insets i = frame.getInsets();
System.out.println(i);
Rectangle bounds = new Rectangle(50, 100, 400, 500);
bounds.width += i.right + i.left;
bounds.height += i.bottom + i.top;
frame.setBounds(bounds);
}
protected void initUI2() {
JFrame frame = new JFrame("Preferred size technique");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 500);
}
});
frame.pack();
frame.setLocation(50, 100);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test test = new Test();
test.initUI();
test.initUI2();
}
});
}
}
Related
Here is my code, i can run it in class extended with JFrame. But now i need to add this code to a class extended with JPanel. Is it possible to add this in JPanel class? If cannot how can i add an image in JPanel class?
JLabel img;
String url = "image/Screenshot(295).png";
void Car() {
frame=new JFrame("Malaysia Checker");
frame.getContentPane().setBackground(Color.white);
img = new JLabel();
ImageIcon icon = new ImageIcon(url);
img.setIcon(icon);
img.setBounds(200, 200, 200, 200);
add(img);
frame.setVisible(true);
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Simple answer is, yes, and you should. A JPanel is just a type of container, a JFrame is a specialised type of container, so many of the concepts are transferable.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
setBackground(Color.WHITE);
try {
// Warning, this is a blocking call and my slow down the launch/presentation of the view
BufferedImage background = ImageIO.read(new URL("https://upload.wikimedia.org/wikipedia/en/thumb/3/30/Java_programming_language_logo.svg/234px-Java_programming_language_logo.svg.png"));
JLabel label = new JLabel(new ImageIcon(background));
add(label);
} catch (IOException ex) {
ex.printStackTrace();
add(new JLabel("Could not load background image"));
}
}
}
}
Remember, in order to display any component, you need some kind of Window class, here I've just used a JFrame as the top level container
This kind of question would be better answer by reading through the Creating a GUI With JFC/Swing tutorials
Here is my Code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class Main {
// code main
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(460, 500);
frame.setTitle("Circles generator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
String input = JOptionPane.showInputDialog("Enter n:");
CustomComponents0 component = new CustomComponents0();
frame.add(component);
frame.getContentPane().validate();
System.out.println("work before");
frame.getContentPane().repaint();
System.out.println("work");
frame.getContentPane().repaint();
System.out.println("work after");
}
// why is not JComponent
static class CustomComponents0 extends JLabel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(200, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
#Override
public void paintComponent(Graphics g) {
System.out.println("paint");
int margin = 10;
Dimension dim = getSize();
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(margin, margin, dim.width - margin * 2, dim.height - margin * 2);
}
}
here is the code and I want run repaint before work and run repaint after work.
When I run it, it should print
work before
paint
work
paint
work after
but there are only one paint and it's after work, Why is that happen? How can I fix that?
Thanks.
You must construct and manipulate Swing GUI objects only on the event dispatch thread. Because your program is incorrectly synchronized, any result is possible. It will depend in part on how far the initial thread gets before starting the EventQueue. Moreover, println() itself may be synchronized, and "events being posted to the EventQueue can be coalesced."
The variation below reliably shows the following output because events are dispatched "In the same order as they are enqueued." Note in particular how the calls to repaint() are coalesced. While this approach is illustrative, it is needlessly cumbersome for your likely goal. Instead, use javax.swing.Timer to pace animation as shown here.
Console:
paint
work before
work
work after
paint
Code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JLabel;
/** #see https://stackoverflow.com/a/44212328/230513 */
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame frame = new JFrame();
frame.setTitle("Circles generator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CustomComponent component = new CustomComponent();
frame.add(component);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
EventQueue.invokeLater(() -> { System.out.println("work before"); });
EventQueue.invokeLater(() -> { frame.repaint(); });
EventQueue.invokeLater(() -> { System.out.println("work"); });
EventQueue.invokeLater(() -> { frame.repaint(); });
EventQueue.invokeLater(() -> { System.out.println("work after"); });
});
}
static class CustomComponent extends JLabel {
private static final int N = 10;
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
System.out.println("paint");
g.setColor(Color.red);
g.fillRect(N, N, getWidth() - N * 2, getHeight() - N * 2);
}
}
}
I am (still) a beginner in Java, and I created a little software which contains a main frame.
I need to cover all the Desktop behind my software such as a windows 98 installing screen : (I need the black and blue screen behing, covering all the task bar etc).
In order to do this, I used GraphicsDevice which goes full screen. It is exactly what I needed :
public class Fond_noir extends JFrame {
private boolean isFullScreen = false;
private GraphicsDevice device;
public Fond_noir(int etat) {
GraphicsEnvironment env = GraphicsEnvironment
.getLocalGraphicsEnvironment();
this.device = env.getDefaultScreenDevice();
initFullScreen(etat);
}
private void initFullScreen(int etat) {
isFullScreen = device.isFullScreenSupported();
if (etat==0)
{
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
}
if (etat==1)
{
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
setUndecorated(isFullScreen);
setResizable(!isFullScreen);
if (isFullScreen) {
// Full-screen mode
device.setFullScreenWindow(this);
validate();
} else {
// Windowed mode
this.setExtendedState(MAXIMIZED_BOTH);
this.setVisible(true);
}
}
}
Then, I call this method in a main somewhere else, (there's no problem with this) :
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Fond_noir(0);
Choix_Langue inst = new Choix_Langue(); // main frame
inst.setLocationRelativeTo(null);
inst.setVisible(true);
} } ); }
But the problem is, that my main frame can't show-up, and it's hidden behind my fullscreen.. I'd like the opposite !
Or when I click on my main frame in my task bar (aften using the window key of my keyboard ofc..) I can only see my main frame, and the fullscreen is not showing-up with the frame
=> Is there a way to show both my frame and my GraphicsDevice ? Using "priorities" between them..?
Thanks for reading !
Use this:
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setUndecorated(true);
frame.setAlwaysOnTop(true)
Undecorated will remove the titlebars. Also instead of trying to show both the frames seperately. Add the small one to the bigger one.
bigFrame.add(smallFrame);
bigFrame.setVisible(true);
Example to show that it works:
I'm not sure you need to go full screen exclusive mode, for example, you can size a border-less frame to fit the default screen size and make it always on top to help it cover all other windows in the system and then simply use a JDialog as the primary interface to work with the user, for example...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class FullScreenBackground {
public static void main(String[] args) {
new FullScreenBackground();
}
public FullScreenBackground() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
JFrame frame = new JFrame("Testing");
frame.setAlwaysOnTop(true);
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new BackgroundPane());
frame.setLocation(0, 0);
frame.setSize(dim);
frame.setVisible(true);
JDialog dialog = new JDialog(frame);
dialog.setContentPane(new InstallPane());
dialog.pack();
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
});
}
public class InstallPane extends JPanel {
public InstallPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(new JLabel("<html><h1>Welcome to my fancy pancy background screen<h1></html>"), gbc);
}
}
public class BackgroundPane extends JPanel {
private BufferedImage bg;
public BackgroundPane() {
}
#Override
public void invalidate() {
super.invalidate();
bg = null;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (bg == null) {
bg = new BufferedImage(1, getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bg.createGraphics();
LinearGradientPaint lgp = new LinearGradientPaint(
new Point(0, 0),
new Point(0, getHeight()),
new float[]{0f, 1f},
new Color[]{Color.BLACK, Color.BLUE}
);
g2d.setPaint(lgp);
g2d.fillRect(0, 0, 1, getHeight());
}
g.drawImage(bg, 0, 0, getWidth(), getHeight(), this);
}
}
}
Updated
If changing all the "frames" is not hard, you could consider making the following changes to the above example...
JFrame frame = new JFrame("Testing");
frame.setAlwaysOnTop(true);
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new BackgroundPane());
frame.setLocation(0, 0);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setSize(dim);
// This will stop the background window from become focused,
// potentially hiding the other windows
frame.setFocusableWindowState(false);
frame.setFocusable(false);
frame.setVisible(true);
JFrame dialog = new JFrame();
// Will need to add this to each frame...
dialog.setAlwaysOnTop(true);
dialog.setContentPane(new InstallPane());
dialog.pack();
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
The other problem you might face is the fact that alwaysOnTop is platform dependent, meaning that it might behaviour differently on different platforms.
Changing extends JFrame to extends JDialog really would be a simpler and more stable change...
I found a solution with all your anwers.
Instead of using another frame I used a JWindow for the background :
public class Fond_noir extends JWindow{
Panel panel = new Panel();
public Fond_noir(int etat) {
if (etat==0)
{
setSize(2300,4000);
setLocationRelativeTo(null);
setVisible(true);
}
if (etat==1)
{
dispose();
}
panel.setBackground(Color.black);
add(panel);
}
class Panel extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
}
}
}
Then while trying to change the "extends JFrame" of my main frame to "extends JDialog", it made me delete this horrible line in the code : this.setState(Frame.ICONIFIED); !!!!
It explains why I had to look for my icon all the time.. So I kept my JFrame..
So now it opens a background window AND the frame at the same time :)
Thank you everyone ! Next time I won't use that much frames.
I'm still very new to Java.
In C# we have the ability to just go and set the form border style like this:
this.FormBorderStyle = FormBorderStyle.None;
How can I accomplish this.
You can use the JFrame method setUndecorated(true). Here is an example:
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("TitleLessJFrame");
frame.getContentPane().add(new JLabel(" HEY!!!"));
frame.setUndecorated(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setVisible(true);
}
}
I can't seem to figure this out.
Please help I need this to work out to continue my project.
Awww I have to add this for allowing me to post
import javax.swing.*;
import java.awt.*;
#SuppressWarnings("serial")
public class MainFrame extends JFrame {
public static void Draw(){
DrawFrame();
}
public static void DrawFrame(){
int h = 600;
int w = 340;
JFrame frame = new JFrame();
JLabel background1 = new JLabel(new ImageIcon("/res/mariocraft_main.png"));
frame.setResizable(false);
frame.setSize(h, w);
frame.setTitle("MarioCraft");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(background1);
background1.setVisible(true);
background1.setIcon(new ImageIcon("/res/mariocraft_main.png"));
background1.setText("Background failed to load");
}
}
A JLabel always displays the image at its actual size so you should not be manually setting the size of the frame.
Instead the code should be something like:
JLabel background1 = new JLabel(new ImageIcon("/res/mariocraft_main.png"));
JFrame frame = new JFrame();
frame.add(background1);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
You need to add the JLabel instance to the JFrame before you realize it (i.e. make it visible). Also, remove these three calls:
background1.setVisible(true);
background1.setIcon(new ImageIcon("/res/mariocraft_main.png"));
background1.setText("Background failed to load");
They are completely unnecessary. Also, another approach to setting a background image to a component is to override it's paintComponent method and draw the image directly to it's Graphics object.
Do you want to set JLabel as background image for the JFrame. Then,
frame.setContentPane(new JLabel(new ImageIcon("someimage.jpg"));
See a sample code snippet taken for here
frame.setLayout(new BorderLayout());
frame.setContentPane(new JLabel(new ImageIcon("someimage.jpg")));
frame.setLayout(new FlowLayout());
l1=new JLabel("Here is a button");
b1=new JButton("I am a button");
frame.add(l1);
frame.add(b1);
import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Mainframe extends JFrame
{
public JLabel image ;
public Container c;
public Mainframe()
{
c=this.getContentPane();
image=new JLabel(new ImageIcon("bg.jpg"));
image.setSize(500, 550);
c.setLayout(new FlowLayout());
c.add(image);
add(image);
this.setSize(500, 550);
this.show();
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args)
{
new Mainframe();
}
}