I hope the title wasn´t too confusing.
First off, I am still a beginner, I only started learning java a few months ago and didn´t start working with graphic components until a few weeks ago. Here is my problem:
I got a JFrame as a container and then a Canvas "canvas" to store BufferedImages and JPanel "bPanel" to hold three JButtons. For some reason, even though I used bPanel.setOpaque(false) and/or bPanel.setBackground(new Color(0, 0, 0, 0) the JPanel would still block the Canvas, no matter which one I add first and which one I add second, no matter if I add the Canvas onto the JFrame or the JPanel.
I looked around the internet for hours and tried at least 5 different solutions that did not work. For some reason, I can´t get loading images through a JPanel to work, probably because my display class is not extending anything.
Anyway, let´s continue:
Here is the code I have (yes I know I could go for Display extends JFrame but that doesn´t solve the problem, I already tried that).
public class Display {
private Game game;
private JFrame frame;
private Canvas canvas;
private JPanel bPanel;
private String title;
private int width, height;
private JButton stand, draw, reset;
private Icon drawIMG, standIMG, resetIMG;
private int bwidth, bheight;
public Display(String title, int width, int height) {
this.title = title;
this.width = width;
this.height = height;
createDisplay();
}
private void createDisplay() {
frame = new JFrame(title);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(width, height));
canvas.setMaximumSize(new Dimension(width, height));
canvas.setMinimumSize(new Dimension(width, height));
canvas.setFocusable(false);
bPanel = new JPanel();
bPanel.setSize(width, height);
bPanel.setPreferredSize(new Dimension(width, height));
//bPanel.setOpaque(false);
bPanel.setBackground(new Color(0, 0, 0, 0));
bPanel.setLayout(null);
drawIMG = new ImageIcon(this.getClass().getResource("/textures/button_draw.png"));
standIMG = new ImageIcon(this.getClass().getResource("/textures/button_stand.png"));
resetIMG = new ImageIcon(this.getClass().getResource("/textures/button_reset.png"));
draw = new JButton(drawIMG);
stand = new JButton(standIMG);
reset = new JButton(resetIMG);
draw.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent drawClicked) {
if (game.getPhase() == 1)
game.playerDraw();
}
});
stand.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent standClicked) {
if (game.getPhase() == 1)
{
game.setPhase(2);
removeButtons();
}
}
});
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent resetClicked) {
game.reset();
}
});
bwidth = 300;
bheight = 100;
//bPanel.add(new JLabel(new ImageIcon(getClass().getResource("/textures/background.png"))), BorderLayout.CENTER);
addButton(draw);
addButton(stand);
addButton(reset);
draw.setBounds(100, ((height/2)-(bheight/2)), bwidth, bheight);
stand.setBounds(((width-100)-bwidth), ((height/2)-(bheight/2)), bwidth, bheight);
reset.setBounds(((width/2)-40), (height-120), 80, 80);
frame.add(canvas);
frame.add(bPanel);
frame.pack();
}
public void showImage(String path) {
JLabel jl = new JLabel();
jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
frame.add(jl);
frame.repaint();
}
public void setGame(Game game) {
this.game = game;
}
public void addButton(JButton button) {
bPanel.add(button);
bPanel.setLayout(null);
}
public void showButtons() {
draw.setVisible(true);
stand.setVisible(true);
}
public void removeButtons() {
draw.setVisible(false);
stand.setVisible(false);
}
public void removePanel(JPanel panel) {
frame.remove(panel);
}
public Canvas getCanvas() {
return canvas;
}
public JFrame getFrame() {
return frame;
}
public JPanel getBPanel() {
return bPanel;
}
}
In this try of mine for example the picture was only displayed after the JButton "stand" was pressed:
public void showImage(String path) {
JLabel jl = new JLabel();
jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
frame.add(jl);
frame.repaint();
}
I am pretty desperate bc I spent many hours trying to figure out a solution to load graphics in.
Thanks for help in advance :D
Several issues:
Don't use a null layout. Swing was designed to be using with layout managers.
The default layout manager for a JFrame is a BorderLayout. If you don't specify a constraint, the component is added to the CENTER. Only one component can be displayed in the CENTER. So you can't just keep adding components to the frame. You need to have a parent/child hierarchy.
Don't use a Canvas. That is an AWT component. If you want to do custom painting in Swing you can use the JPanel
So your code might be something like:
//addButton(draw);
//addButton(stand);
//addButton(reset);
bPanel(draw);
bPanel(stand);
bPanel(reset);
The default layout manager for a JPanel is a FlowLayout. So the buttons will be added from left to right and centered on the panel.
//frame.add(bPanel);
frame.add(bPanel, BorderLayout.PAGE_START);
Now all the buttons will be added at the top of the frame.
//private Canvas canvas;
private JPanel canvas;
….
//canvas = new Canvas();
canvas = new JPanel(new BorderLayout());
…
//frame.add(canvas);
frame.add(canvas, BorderLayout.CENTER);
Now the "canvas" will be added to the CENTER of the BorderLayout of the frame, which means it will take up all the space not used by the button panel.
public void showImage(String path) {
JLabel jl = new JLabel();
jl.setIcon(new javax.swing.ImageIcon(getClass().getResource(path)));
frame.add(jl);
frame.repaint();
}
You can't add the image directly to the frame because you have already added other components to the frame. Instead use:
//frame.add(jl);
//frame.repaint();
canvas.add(jl);
canvas.repaint();
So the image is added to the canvas which is added to the frame so you have a parent/child hierarchy.
//draw.setBounds(100, ((height/2)-(bheight/2)), bwidth, bheight);
//stand.setBounds(((width-100)-bwidth), ((height/2)-(bheight/2)), bwidth, bheight);
//reset.setBounds(((width/2)-40), (height-120), 80, 80);
Above code is not needed, since it is the job of the layout manager to set the size and location of each component based on the rules of the layout manager.
So basically you need to start over and learn some Swing basics. Maybe the Swing tutorial will help. There are demos of how to use each of the layout managers.
Related
The following class creates a window/frame.
public class Window {
private int width, height;
private JFrame frame;
private Canvas canvas;
private String title;
private JButton button;
private JPanel panel;
public Window(String title){
System.out.println("Initialization Window...");
this.title = title;
width = Reference.width;
height = Reference.height;
button = new JButton("cool button");
CreateWindow();
}
private void CreateWindow(){
frame = new JFrame(title);
frame.setSize(width, height);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
panel = new JPanel();
panel.add(button);
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(width, height));
canvas.setMaximumSize(new Dimension(width, height));
canvas.setMinimumSize(new Dimension(width, height));
canvas.setFocusable(false);
frame.add(canvas);
frame.add(panel);//my problem is in this line
frame.pack();
}
i added to the frame canvas and jpanel when i run it. the size of frame is set to very small a size of a button that i have made. but removing "frame.add(panel) will make it back to normal size. did i miss something?
in case why im using jpanel and canvas. well im using canvas because i use bufferstategy for the drawing graphic, and i need jpanel to add buttons and other things too.
When you add two components in a default fashion to any container that uses BorderLayout, such as a JFrame's, both are added by default in the BorderLayout.CENTER postion and the second component covers the first, and so here the JPanel covers the Canvas, and since the Canvas is not displayed, its preferred size is ignored.
You will instead want to figure out exactly where you want components relative to each other, specifically the JPanel, the Canvas and how they're placed in the JFrame, and then use the layout managers to their advantage rather than fighting the layout manager as your code currently does.
whatever you do, avoid the null layout like the plague.
It's usually a bad idea to mix AWT and Swing components. Are you absolutely positive that you need to use Canvas? JPanels are double buffered by default and that usually smooths out any animation if that's your goal.
I must say, It would have been simpler if you had just extended JFrame unless you want to extend something else.
You need to understand that for code readability and reuseability, you need to follow conventional Java rules and best practices.
#Hovercraft Full Of Eels has explained all you need above. All I do here is to set you right by example so there is no need duplicating what he has said.
FlowLayout may be the easiest and simplest layout manager in Java but it is not that very powerful compared to say GridLayout or GrdiBagLayout.
Here is the code:
public class Window extends JFrame {
private int width, height;
private Canvas canvas;
private String title;
private JButton button;
private JPanel panel;
public Window(String title){
super( title );
System.out.println("Initialization Window...");
this.title = title;
setLayout( new FlowLayout() );
//width = Reference.width;
//height = Reference.height;
button = new JButton("cool button");
createWindow();
}
private void createWindow(){
setSize(width, height);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setVisible(true);
panel = new JPanel();
panel.add(button);
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(200, 200));
canvas.setMaximumSize(new Dimension(400, 400));
canvas.setMinimumSize(new Dimension(200, 200));
canvas.setFocusable(false);
add(canvas);
add(panel);//my problem is in this line
pack();
}
}
i've gone about setting the background Image of my JFrame but now my components are (I assume) stuck behind it. I've tried reading about top level containers but I just can't get my head around it T_T. Any one have any ideas ? Maybe I need to find another way to set the background image ? Thank you for any help. :
#SuppressWarnings("serial")
public class CopyOfMainMenu extends JFrame {
//Running the GUI
public static void main(String[] args) throws IOException {
CopyOfMainMenu gui2 = new CopyOfMainMenu();
gui2.mainPanel();
}
public void thepanel () throws IOException {
// GridBagLayout/Constraint
GridBagConstraints gridbagc = new GridBagConstraints();
gbc.insets = new Insets(15, 15, 15, 15);
JFrame frame = new JFrame();
JPanel panel = new JPanel(new GridBagLayout());
// Creating JButtons/Icons
panel.add(buttonTwo, gbc); //SCOREBOARD
panel.add(buttonThree, gbc); //INSTRUCTIONS
// JButton size's
button.setPreferredSize(new Dimension(400, 35))
buttonTwo.setContentAreaFilled(false);
buttonThree.setBorder(BorderFactory.createEmptyBorder());
buttonThree.setContentAreaFilled(false);
}
}
Again, thanks in advance for any help.
You never add the panel anywhere (if you did, it would paint over the image). However, it's possible to use a JLabel as the container:
JComponent panel = new JLabel(new ImageIcon(ImageIO.read(new File("res/FinalBG.png"))));
panel.setLayout(new GridBagLayout());
...
// continue adding the components as before
...
frame.add(panel);
(or set the label as the content pane, which works just as well).
Inside the JFrame, override the paint method and draw your image using the Graphics object:
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(image, width, height, null);
}
First of all, sorry for the vague title I don't know how to word the question in a sentence.
I have a simple programme that slides one JPanel into view as another gets pushed out, when a button is clicked.
If the first JPanel's width is set as getWidth() then the JPanel will not move when the button is clicked, however if I change the width to getWidth() - 1 it works perfectly fine!?!
A simple example is shown below
public class SlidingJPanel extends JFrame{
public JPanel panel = new JPanel();
public JPanel panel2 = new JPanel();
public JLabel label = new JLabel(" SUCCESS!!!!!!!");
public JButton button = new JButton("TESTING");
public class MyJPanel extends JPanel implements ActionListener{
public int x = 0;
public int delay = 70;
final Timer timer = new Timer(delay,this);
public MyJPanel(){};
public void paintComponent(Graphics g)
{
super.paintComponent(g);
button.setBounds(10, 20, 100, 50);
button.addActionListener(this);
panel.setBorder(BorderFactory.createLineBorder(Color.black));
panel.setBounds(x, 0, getWidth(), getHeight());
panel.add(button);
panel2.setBorder(BorderFactory.createLineBorder(Color.blue));
panel2.setBounds(x - getWidth(), 0, getWidth(), getHeight());
panel2.add(label);
add(panel);
add(panel2);
}
#Override
public void actionPerformed(ActionEvent arg0) {
timer.addActionListener(move);
timer.start();
}
ActionListener move = new ActionListener(){
public void actionPerformed(ActionEvent e){
repaint();
x++;
}
};
}
public static void main(String args [])
{
new SlidingJPanel();
}
SlidingJPanel()
{
Container container = getContentPane();
MyJPanel panel = new MyJPanel();
container.add(panel);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(500,500);
setTitle("JPanel Draw Rect Animation");
setVisible(true);
}
}
ignore any coding conventions I may have ignored or missed this is just a rough draft.
Hope someone can help :)
The paintComponent() method is for painting only! There is no need for you to override this method.
You should NOT be:
updating the property of components (ie. bounds, border)
adding components to a container
If you want to animate a component then when the timer fires you can use setLocation(...) or setSize() or setBounds(). The component will automatically be repainted.
I don't know if fixing this will solve your problem, but the current approach is wrong.
I'm working with JFrames in Java, specifically with absolutely positioned elements that need to overlap. I understand that to overlay components, one should make a JPanel (with setOpacity(false);), and position it with either setBounds(x,y,x2,y2); or setPosition(x,y) & setSize(x,y). Unfortunately the panels act like CSS's inline-divs; they take up only the needed amount of room on their line, and do not stack.
This is the code I have so far, but it doesn't seem to act like I'd imagine it would:
class Login extends JFrame {
private JPanel backgroundpanel;
private JPanel panel;
private JPanel panel2;
private JTextField usernameBox;
private JPasswordField passwordBox;
private JButton button;
private int height = 319;
private int width = 452;
private ImageIcon ii = new ImageIcon("special-window-BG.png");
private JLabel image;
public Login() {
setLayout(null);
setTitle("Login");
setSize(width,height);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
buildPanel();
add(backgroundpanel);
setVisible(true);
}
private void buildPanel() {
usernameBox = new JTextField(20);
passwordBox = new JPasswordField(20);
button = new JButton("Login");
image = new JLabel(ii);
backgroundpanel = new JPanel();
panel = new JPanel();
panel2 = new JPanel();
backgroundpanel.add(panel);
backgroundpanel.add(panel2);
backgroundpanel.add(image);
panel.setBackground(Color.red);
panel.setBounds(0, 0, 10, 10);
panel.setOpaque(false);
panel2.setBackground(Color.blue);
panel2.setBounds(0, 0, 10, 10);
panel2.setOpaque(false);
panel.add(passwordBox);
panel2.add(button);
backgroundpanel.setOpaque(false);
backgroundpanel.isOptimizedDrawingEnabled();
backgroundpanel.setBounds(0, 0, width, height);
...cot'd, however unnecessary.
So basically, I'd like to know how to absolutely position JPanels (or JComponents, if that's simpler) over a JPanel with a background-image.
Thanks for taking a look at this question, I've spent far too much time on this method; the commented-out code extends nearly 500 lines passed what I posted, so I have nowhere else to turn to. The image below shows a crude illustration of what I'm trying to accomplish, I'm not sure if I'actually come close to getting it yet, because sometimes the JComponents seem to disappear as if they're behind the background image, however I'd like to find the simple solution that's most likely right in front of my eyes!
http://i.stack.imgur.com/revz8.jpg
I'd like to find the simple solution that's most likely right in front of my eyes!
Something like this?
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class LoginPanel extends JPanel {
private static final long serialVersionUID = 1L;
BufferedImage image;
LoginPanel(BufferedImage image) {
super(new GridBagLayout());
this.image = image;
JPanel controls = new JPanel(new BorderLayout(15,35));
controls.setOpaque(false);
controls.setBorder(new EmptyBorder(110,0,0,0));
JPanel fields = new JPanel(new GridLayout(0,1,30,30));
fields.setOpaque(false);
controls.add(fields, BorderLayout.CENTER);
fields.add(new JTextField(20));
fields.add(new JPasswordField(20));
JPanel button = new JPanel(new GridBagLayout());
button.setOpaque(false);
controls.add(button, BorderLayout.PAGE_END);
button.add(new JButton("Log In"));
Dimension prefSize = new Dimension(image.getWidth(),image.getHeight());
setPreferredSize(prefSize);
add(controls);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
public static void main(String[] args) throws Exception {
URL url = new URL("http://i.stack.imgur.com/revz8.jpg");
final BufferedImage image = ImageIO.read(url);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
LoginPanel p = new LoginPanel(image);
JOptionPane.showMessageDialog(null, p);
}
});
}
}
You're setting setLayout(null) on your JFrame but not on the "backgroundpanel" (which layout is default set to FlowLayout).
You shouldn't set layout of your Login frame - because it is default set to BorderLayout - and it's ok (you want the "backgroundpanel" to grow to match the parent).
Instead setLayout(null) on your JPanel - "backgroundpanel" - to which you add your arbitrary positioned panels.
I am writing a simple application in Java that does some particle simulation on a bunch of sheep (don't ask). For this I want a window with a JPanel for graphics (which will be resizable with a simple combobox that contains some standard resolutions) and some other elements like buttons to start and pause the simulation etc.
My question: I'm using the JFrame.pack method to pack everything nicely together using a borderLayout. But for some reason the JPanel is packed wrong, it seems like the packing ignores it, so the window is resized to fit the size of only the two buttons that I have now. What am I doing wrong?
This is the code so far (bit of a newbie, so no comments on my dumbness if there is any ;)):
public class Window {
public Sheepness sheepness;
public ButtonPanel buttonPanel;
public PaintPanel paintPanel;
public JFrame frame;
public Window(Sheepness sheepness, int width, int height) {
this.sheepness = sheepness;
frame = new JFrame("Sheepness simulation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//frame.setSize(width, height);
BorderLayout frameLayout = new BorderLayout();
JPanel background = new JPanel(frameLayout);
background.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
buttonPanel = new ButtonPanel(this);
background.add(BorderLayout.SOUTH, buttonPanel.buttonBox);
paintPanel = new PaintPanel(this);
paintPanel.setSize(600, 600);
background.add(BorderLayout.CENTER, paintPanel);
frame.getContentPane().add(background);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
public class PaintPanel extends JPanel {
public Window window;
public PaintPanel(Window window) {
this.window = window;
}
#Override
public void paintComponent(Graphics g) {
g.setColor(Color.blue);
g.fillRect(0, 0, 300, 200);
}
}
public class ButtonPanel {
public Window window;
public Box buttonBox;
public JButton startButton;
public JButton resetButton;
public ButtonPanel(Window window) {
this.window = window;
buttonBox = new Box(BoxLayout.X_AXIS);
startButton = new JButton("Start");
startButton.addActionListener(new startButtonListener());
buttonBox.add(startButton);
resetButton = new JButton("Reset");
resetButton.addActionListener(new resetButtonListener());
buttonBox.add(resetButton);
}
}
Try:
paintPanel.setPreferredSize(600, 600);
As Window.pack() sizes to the preferred sizes of its subcomponents and JPanel gets its preferred size from its child components (in your case there are none).