JPanel location issues - java

I have to create a GUI and I'd really like to set a background to it.
In order to do this, I've created a class called "Backround" where I'm using the paintComponent method. I gave it the file I want to set on the background and it worked.
Here is my Background class :
public class Background extends JPanel
{
public void paintComponent(Graphics g)
{
try {
Image img = ImageIO.read(new File("./fond.jpg"));
g.drawImage(img, 0, 0, this.getWidth(), this.getHeight(), this);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
However, once the image is on the background, the panels that were on my frame are not anymore in the same location and I've really no idea how to fix that and still haven't found any relevant topics about this.
Here is a quote of my class where I'm describing the GUI :
this.setContentPane(new Background());
this.setTitle("Arena");
this.setSize(800, 500);
this.setLocationRelativeTo(null);
//this.setLayout(new FlowLayout(FlowLayout.CENTER));
//this.setLayout(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
// ******************************************** PANEL 1 ******************************************
Panel P1 = new Panel();
this.add("NORTH", P1);
P1.setLayout(new FlowLayout());
P1.add(new Label ("Joueur 1"));
P1.add(new Label ("Action"));
P1.add(new Label ("Joueur 2"));
//P1.setVisible(true);
// ********************************************* PANEL 2 ******************************************
Panel P2 = new Panel();
P2.setLayout(new FlowLayout());
P2.add(Liste1);
// Boutons
Button B1 = new Button("FIGHT");
P2.add(B1);
Button B2 = new Button("HEAL");
P2.add(B2);
P2.add(Liste2);
this.add("WEST", P2);
// P2.setVisible(true);
Furthermore, when I remove the call to my Background constructor, the panels are getting back to their inital locations.
I hope you could help me or redirect me!
Thanks!
Antoine Sbert

Make sure you call super.paintComponent before performing any customer painting
Don't load resources (like images) from with in the paint method, this will have an impact on the performance of you program
JPanel by default use a FlowLayout, but you never change the layout after you apply the Background panel as the contentPane. After calling setContentPane, use setLayout(new BorderLayout()) or apply the layout in the classes constructor (at the same time when you load the image)
Make sure you call setVisible last, after you've established the basic UI

Related

How do you make it so that a button doesn't interfere with the location of drawn shape?

So basically when I add a button it essentially pushes the black rectangle drawn in this program down, putting it out of its given location. How would you fix this?
import javax.swing.*;
import java.awt.*;
public class Grid {
public class homeGraphics extends JComponent {
homeGraphics() {
setPreferredSize(new Dimension(450, 600));
}
public void paint(Graphics g) {
super.paint(g);
g.fillRect(200, 275, 50, 50);
}
}
public void homeFrame() {
JFrame frame1 = new JFrame();
frame1.setSize(450, 600);
frame1.setResizable(false);
frame1.setDefaultCloseOperation(frame1.EXIT_ON_CLOSE);
JButton playButton = new JButton("Play");
playButton.setPreferredSize(new Dimension(60, 30));
JPanel panel1 = new JPanel();
panel1.add(playButton);
panel1.add(new homeGraphics());
frame1.add(panel1);
frame1.setVisible(true);
}
public static void main(String args[]) {
Grid frame = new Grid();
frame.homeFrame();
}
}```
it essentially pushes the black rectangle drawn in this program down, putting it out of its given location.
What do you mean out of its location? Painting is always done relative to the component. So your painting will always be done at (200, 275) of the component.
If you are attempting to paint at (200, 275) relative to the "frame", then don't. That is NOT how painting works.
Other problems with your code:
Don't attempt to set the size of your frame. If the custom panel is (450, 600) how can the frame possibly be the same size? The frame also contains the "title bar" and "borders". Instead of using setSize(), you invoke frame.pack()just beforeframe1.setVisible(….)`.
Class names start with an upper case character. Learn by example. Have you ever seen a class name in the JDK that doesn't start with an upper case character?
Custom painting is done by overriding paintComponent(…), not paint().
By default a JPanel uses a FlowLayout. So what you see it the button on one line and then the "HomeGraphics" class is too big to fit on the same line so it wraps the to the second line.
You should be more explicit when you do frame layout. So your code should be something like:
JPanel wrapper = new JPanel();
wrapper.add( playButton );
//JPanel panel1 = new JPanel();
//panel1.add(playButton);
//panel1.add(new homeGraphics());
JPanel panel1 = new JPanel( new BorderLayout() );
panel1.add(wrapper, BorderLayout.PAGE_START);
panel1.add(new HomeGraphics(), BorderLayout.CENTER);
Now the code shows your layout attempt more clearly.

Best practice to resize JScrollPane

I read some answered questions in this forum (this one for example) where it is strictly recommended to avoid the use of setXXXSize() methods to resize components in swing applications.
So, coming to my problem, i would like to know how to best resize a JScrollPane in order to avoid its parent panel to increase its size without any control.
Before writing some code, i want to describe the real situation, since i will post a "toy example".
In my JFrame i'm currently using a border layout for my content pane. At BorderLayout.CENTER there is a JPanel where i do some custom painting.
At BorderLayout.EAST there is a JPanel (say eastPanel) containing some components inside another panel (this panel will be added to eastPanel at BorderLayout.NORTH), and a JScrollPane which contains a JTable (added to eastPanel at BorderLayout.CENTER). This table will have a lot of rows.
Since i want eastPanel's height to be the same as centerPanel's height, i need some way to avoid the JScrollPane to increase its size in order to try to display as much rows as possible.
For now i wasn't be able to find another solution apart from calling setPreferredSize on the eastPanel containing the scrollpane, but i have to admit that i hate this kind of solution.
Sample Code
In this code sample i added some random labels at the north of eastPanel and inside the JScrollPane, since my purpose was to post a short sample of code.
However, the situation is very similar to the one i have described above.
I wasn't be able to solve my problem without using this "terrible" line of code :
eastPanel.setPreferredSize(new Dimension(eastPanel.getPreferredSize().width, centerPanel.getPreferredSize().height));
I would like to avoid a more complex layout for a simple situation like this. Am i missing something ? Also, is setting that empty border an acceptable way to set the size of the panel where i will do some custom painting?
Code :
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class Test
{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
new TestFrame().setVisible(true);
}
catch(Exception exception) {
JOptionPane.showMessageDialog(null, "Fatal error while initialiing application", "Error", JOptionPane.ERROR_MESSAGE);
}
}
});
}
}
class TestFrame extends JFrame
{
public TestFrame() {
super("Test");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel pane = new JPanel(new BorderLayout(20, 0));
pane.setBorder(new EmptyBorder(20, 20, 20, 20));
JPanel centerPanel = new JPanel();
centerPanel.setBackground(Color.WHITE);
centerPanel.setBorder(new EmptyBorder(400, 400, 0, 0));
// centerPanel.setPreferredSize(new Dimension(400, 400));
JPanel eastPanel = new JPanel(new BorderLayout(0, 20));
JPanel labelsContainer = new JPanel(new GridLayout(0, 1));
for(int i=0;i<7;i++) labelsContainer.add(new JLabel(String.valueOf(i)));
eastPanel.add(labelsContainer, BorderLayout.NORTH);
JPanel moreLabelsContainer = new JPanel(new GridLayout(0, 1));
for(int i=7;i<70;i++) moreLabelsContainer.add(new JLabel(String.valueOf(i)));
JScrollPane scroll = new JScrollPane(moreLabelsContainer, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
eastPanel.add(scroll, BorderLayout.CENTER);
eastPanel.setPreferredSize(new Dimension(eastPanel.getPreferredSize().width, centerPanel.getPreferredSize().height));
pane.add(centerPanel, BorderLayout.CENTER);
pane.add(eastPanel, BorderLayout.EAST);
setContentPane(pane);
pack();
setLocationRelativeTo(null);
}
}
Thanks for your help !
I am not aware of a layout manager that restricts the height of the panel based on the height of a specific component in the panel.
One way is to customize the behaviour of the parent panel that contains the two child components.
The code might be something like:
#Override
public Dimension getPreferredSize()
{
Dimension d = super.getPreferredSize();
BorderLayout layout = (BorderLayout)getLayout();
Component center = layout.getLayoutComponent(BorderLayout.CENTER);
int centerHeight = center.getPreferreidSize().height;
if (d.height > centerHeight)
d.height = centerHeight;
return d;
}
This approach will allow for dynamic calculation of the height based on the component in the center.
Another option is to write you own layout manager. Then you can control this type of logic from within the layout manager.
Also, is setting that empty border an acceptable way to set the size of the panel where i will do some custom painting?
I override the getPreferredSize() to return the appropriate dimension.
By using the EmptyBorder you lose the ability to add a true Border to the panel, so I wouldn't recommend it.

How to add a background image on a frame or a panel [duplicate]

I am creating a simple GUI, and I want to have a background image (2048 X 2048) fill up the whole window and a square to the left top corner where the occasional 64 X 64 image can be loaded. How can this be done?
I already know how to make the JFrame a set size, its the image loading I need help with.
This is a simple example for adding the background image in a JFrame:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class BackgroundImageJFrame extends JFrame
{
JButton b1;
JLabel l1;
public BackgroundImageJFrame()
{
setTitle("Background Color for JFrame");
setSize(400,400);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
/*
One way
-----------------
setLayout(new BorderLayout());
JLabel background=new JLabel(new ImageIcon("C:\\Users\\Computer\\Downloads\\colorful design.png"));
add(background);
background.setLayout(new FlowLayout());
l1=new JLabel("Here is a button");
b1=new JButton("I am a button");
background.add(l1);
background.add(b1);
*/
// Another way
setLayout(new BorderLayout());
setContentPane(new JLabel(new ImageIcon("C:\\Users\\Computer\\Downloads\\colorful design.png")));
setLayout(new FlowLayout());
l1=new JLabel("Here is a button");
b1=new JButton("I am a button");
add(l1);
add(b1);
// Just for refresh :) Not optional!
setSize(399,399);
setSize(400,400);
}
public static void main(String args[])
{
new BackgroundImageJFrame();
}
}
Click here for more info
The best way to load an image is through the ImageIO API
BufferedImage img = ImageIO.read(new File("/path/to/some/image"));
There are a number of ways you can render an image to the screen.
You could use a JLabel. This is the simplest method if you don't want to modify the image in anyway...
JLabel background = new JLabel(new ImageIcon(img));
Then simply add it to your window as you see fit. If you need to add components to it, then you can simply set the label's layout manager to whatever you need and add your components.
If, however, you need something more sophisticated, need to change the image somehow or want to apply additional effects, you may need to use custom painting.
First cavert: Don't ever paint directly to a top level container (like JFrame). Top level containers aren't double buffered, so you may end up with some flashing between repaints, other objects live on the window, so changing it's paint process is troublesome and can cause other issues and frames have borders which are rendered inside the viewable area of the window...
Instead, create a custom component, extending from something like JPanel. Override it's paintComponent method and render your output to it, for example...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, this);
}
Take a look at Performing Custom Painting and 2D Graphics for more details
I used a very similar method to #bott, but I modified it a little bit to make there be no need to resize the image:
BufferedImage img = null;
try {
img = ImageIO.read(new File("image.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
Image dimg = img.getScaledInstance(800, 508, Image.SCALE_SMOOTH);
ImageIcon imageIcon = new ImageIcon(dimg);
setContentPane(new JLabel(imageIcon));
Works every time. You can also get the width and height of the jFrame and use that in place of the 800 and 508 respectively.
You can do:
setContentPane(new JLabel(new ImageIcon("resources/taverna.jpg")));
At first line of the Jframe class constructor, that works fine for me

Jframe with canvas and Jpanel layout

I'm just beginning on making a GUI for a lwjgl engine. I have a canvas on the left hand side and I want to have a JPanel on the right for previewing textures. However as you can see, the image is barely visible. I've tried different Borderlayouts, trying to resize etc.. However I think I'm just doing something fundamentally wrong.
My panel class
public class Panel extends JPanel {
BufferedImage image;
public Panel(){
try {
image = ImageIO.read(new
File("C:/Users/tom/Desktop/raj/Jtest/src/AWT/house.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void paintComponent(Graphics g){
// super.paint(g);
g.drawImage(image,0, 0, null);
}
and here is how I'm trying to implement it.
public static void main(String[] args)
{
Panel panel = new Panel();
UIManager.setLookAndFeel("com.jtattoo.plaf.hifi.HiFiLookAndFeel");
JFrame frame = new JFrame("World Editor");
frame.setLayout(new BorderLayout());
final Canvas canvas = new Canvas();
button1.setSize(100, 100);
button1.setLocation(600, 10);
button1.setText("Test");
canvas.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e)
{ canvas.setSize(800, 600);
newCanvasSize.set(canvas.getSize());
}
});
frame.setBackground(Color.black);
frame.add(button1);
frame.add(panel,BorderLayout.EAST);
frame.getContentPane().add(canvas,BorderLayout.CENTER);
try {
Display.setParent(canvas);
Display.setVSyncEnabled(true);
frame.setPreferredSize(new Dimension(1600, 1400));
frame.setMinimumSize(new Dimension(800, 600));
frame.pack();
frame.setVisible(true);
Display.create();
etc...
the setup should of been like this http://i.imgur.com/Zitizdx.png
ePanel panel = new ePanel(0, 0);
UIManager.setLookAndFeel("com.jtattoo.plaf.hifi.HiFiLookAndFeel");
JFrame frame = new JFrame("World Editor");
frame.setLayout(new BorderLayout());
canvas = new Canvas();
canvas.setSize(1200, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
button1.setSize(100, 100);
button1.setText("TEST");
frame.add(button1);
frame.add(canvas,BorderLayout.WEST);
frame.add(panel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Do you already tried to set the image for a background label and resize it? Something like this:
http://www.java2s.com/Code/Java/Swing-JFC/Labelbackgroundiconalign.htm
Don't use a Canvas. That is an AWT class and you should not mix AWT components in a Swing application. I'm not sure what the point of the Canvas is, but you should probably be using a JPanel.
Don't call you class "Panel". There is an AWT class with that name already. Class names should be more descriptive.
In fact, don't even create a custom class. Just use a JLabel with an ImageIcon to display the image. I'm guessing the problem is that you didn't override the getPreferredSize() method of the "Panel" class so the size is (10, 10) by default which is the size the panel will have because you are using a FlowLayout. So either use a JLabel (easy solution) or implement the getPreferredSize() method to reflect the size of the image.
Set a GridLayout to the JFrame new GridLayout(0, 2)
http://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html
That way, the JFrame has left and right side. Then create and add two JPanels to the Jframe. Do not forget resize the panels and the frame.
After that, create a label, set to it an icon image, resize it and add it to the right panel.

Adding JScrollPane to JPanel

I'm trying to add a JScrollPane to an JPanel from a separate class. And thanks to some questions, which were asked so far, I could help myself create them. But my problem is still a little bit special.
I want to display an image on a JPanel and if the image is to large for the panel, I want to add scrollbars. But the scrollbars won't appear.
(When I set the ScrollPaneConstants to ****_SCROLLBAR_ALWAYS the frame of the bar appears, but without the bars to scroll).
I guess i have to connect the imagesize with the bars, so that they appear?
Some pieces of my code:
MainWindow
public class Deconvolutioner extends JFrame
{
Draw z;
Picturearea picturearea;
class Draw extends JPanel
{
public void paint(Graphics g)
{
}
}
public Deconvolutioner()
{
setTitle("Deconvolutioner");
setLocation(30,1);
setSize(1300,730);
super.setFont(new Font("Arial",Font.BOLD,11));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
FlowLayout flow = new FlowLayout(FlowLayout.CENTER);
this.setLayout(flow);
picturearea = new Picturearea();
picturearea.setLayout(new GridBagLayout());
JScrollPane scrollPane = new JScrollPane(picturearea,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scrollPane.setPreferredSize(new Dimension(1000, 664));
getContentPane().add(scrollPane, flow); // add scrollpane to frame
add(z = new Draw());
setVisible(true);
}
}
JPanel Class
public class Picturearea extends JPanel
{
BufferedImage image;
int panelWidth, panelHeight, imageWidth, imageHeight;
public Picturearea()
{
setBackground(new Color(210,210,210));
setBorder(LineBorder.createBlackLineBorder());
setVisible(true);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
public void setPicture(BufferedImage picture)
{
try
{
image = picture;
}
catch (Exception e)
{
System.err.println("Some IOException accured (did you set the right path?): ");
System.err.println(e.getMessage());
}
repaint();
}
}
Thanks for your time.
The problem is that the JScrollPane has no way to know if it should display scroll bars or not, since the Picturearea it contains doesn't tell anything about its preferred size (or rather, it returns the preferred size based on its layout and on the components it contains. But since it doesn't contain any component, the returned preferred size is probably (0, 0)).
I would simply use a JLabel instead of the custom Picturearea class. A JLabel can display an image just fine, and it returns the appropriate Dimension when asked for its preferred size.
You can create a JLabel first and then add the Label to JPanel picturearea before creating instance for JScrollPane .
Have a try and it will work.
Example code is as follows:
JLabel imageLabel = new JLabel(new ImageIcon("d:\\099.jpg"));
picturearea.add(imageLabel);**
JScrollPane scrollPane = new JScrollPane(picturearea,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);

Categories