Set background in a JFrame - java

I waned to put a background in a JFrame, so I searched on YouTube and found a Video, but it didn't work I tried another one and this didn't work either so what is wrong with my code
because all the time i start it is just not there but eclipse dont mark anything wrong.
package Pack;
import javax.swing.*;
public class Gui {
public Gui(){
JLabel background;
Var.jf = new JFrame();
Var.jf.setSize(Var.screenwidth, Var.screenheight);
Var.jf.setTitle("test");
Var.jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Var.jf.setResizable(false);
Var.jf.setVisible(true);
Var.jf.setLocationRelativeTo(null);
Var.jf.setLayout(null);
ImageIcon img = new ImageIcon("Bilder/Testbild");
background = new JLabel("",img,JLabel.CENTER);
background.setBounds(0,0,1000,1000);
Var.jf.add(background);
Var.Buttonxstart = new JButton("Start");
Var.Buttonxstart.setBounds(300,220,400,120);
Var.jf.add(Var.Buttonxstart);
Var.Buttonxclose = new JButton("Exit");
Var.Buttonxclose.setBounds(300,440,400,120);
Var.jf.add(Var.Buttonxclose);
}
}
.
package Pack;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Var {
static JFrame jf;
static int screenheight = 1000;
static int screenwidth = 1000;
static JButton Buttonxstart;
static JButton Buttonxclose;
}

Some points:
code should check if the image is really being loaded - ImageIcon does not throw any Exception if the file is not found. Test if the height or width is -1 or not, example:
if (img.getIconHeigth() == -1) {
throw new FileNotFoundException("image: Bilder/Testbild");
}
or better IMO, use ImageIO.read().
the whole GUI code should run in the EDT (Event Dispatch Thread), see Swing's Threading Policy. . Unable to see if it is, if not, use some code like SwingUtilities.invokeLater(() -> new Gui());
3. it is not recommended to use the null layout manager.Check the Laying Out Components Within a Container tutorial.
Note: I tested the posted code - it's working, if calling new Gui() on the EDT and having an image Testbild in folder Bilder. But for background image I would prefer to override the paintComponent method of a JPanel, to paint the image.

Related

JTextBox and all following JComponents don't show up

I want do design a simple login format and in order to do so I want two JTextFields for Username/Password and a Login Button. The Login button is display as expected but when I add the JTextField, nothing shows in my JFrame. Would be nice if someone could help a beginner out...
Here's my code (I know it's ugly but this is just a "code sketch"):
package bucketlistpackage;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GameFrame extends JFrame {
public GameFrame(String title) {
super(title); //sets title of frame
startFrame(); //sets details of main frame
final Container logincont = getContentPane(); //creates content pane
JFrame loginframe = new JFrame();
usernameField(loginframe);
loginButton(loginframe);
logincont.add(loginframe);
}
private void usernameField(JFrame loginframe) {
JTextField usernameF = new JTextField("Username", 1);
usernameF.setBounds(50, 50, 50, 20);
loginframe.add(usernameF);
usernameF.setVisible(true);
}
private void startFrame() {
this.setSize(1000, 1000);
this.setVisible(true);
}
private void loginButton(Container cont) {
JButton loginB = new loginButton();
loginB.setSize(300, 150);
loginB.setText("Login");
cont.add(loginB);
}
}
The problem lies on how you are adding component to one another in your case.
You are adding a JFrame to a Container, when in all case it should be the other way around.
The other problem is that you are not using Layouts to manage the components positions on the JFrame.
Another problem as well is that you are not refreshing the windows after adding all the stuff on it.
A bit of a resume on how Java works with native UIs:
Java creates a new thread for the UI. So if you open the debugger you will see AWT threads as well as the main threads and others. This means that you have to manage this in a correct way, because after the application starts SWING and the functions you determine for reactions will lay the ground on how it will behave. Your main thread will die, but the visual threads will keep active.
If you are just starting to program I would encourage you to practice a bit more native java language before moving to SWING or AWT. This libraries can be really painful and tricky to use.
The other thing is SWING library follows a hierarchy for the components:
JFrame > JPanels > Components
In your code you have already worked with all of them but in a disorganized way. JFrame is the main application window, where the graphics will be displayed (can also be a Canvas or whatever class you want to use for that matter). JPanels are organizers, you can use different layouts to organize whatever is inside it. And finally the Components are well... everything! A component can be a JTextField, but it can also be a JPanel, or JButton.
The idea with SWING is to create multiple Panels and organize the end components inside them, using the help of the different layouts to see whats the best approach to make them attractive in many different window sizes.
Finally, if you are using Eclipse, there is a plugin called WindowBuilder which might help you. I don't recommend you using it if you are very new to Java since it will make you depend a lot on it instead of learning how to actually code with SWING.
Hope this helps!!!
Btw, to fix the code above I would do something like this:
public GameFrame(String title) {
super(title); //sets title of frame
startFrame(); //sets details of main frame
final Container logincont = getContentPane(); //creates content pane
logincont.setLayout(new BorderLayout());
usernameField(logincont, BorderLayout.NORTH);
loginButton(logincont, BorderLayout.CENTER);
this.revalidate();
this.repaint();
}
private void usernameField(Container loginframe, String direction) {
JTextField usernameF = new JTextField("Username");
// usernameF.setBounds(50, 50, 50, 20);
loginframe.add(usernameF, direction);
usernameF.setVisible(true);
}
private void startFrame() {
this.setSize(1000, 1000);
this.setVisible(true);
}
private void loginButton(Container cont, String direction) {
JButton loginB = new JButton();
loginB.setSize(300, 150);
loginB.setText("Login");
cont.add(loginB, direction);
}

Can you create a seperate method for creating JFrame Sizes?

The previous question that I made was marked as a duplicate and the linked question was not anywhere close to what I need. I'm asking if it's possible to create a method that I can call to set the JFrame size.
So, I'm trying to make a JFrame GUI but I want to create the method outside of the GUI method, as in a GUISize method, and the JFrame works when the GUISize method isn't a method and the code is where the method is called.
This is for an assignment, but, none of it's technically marked. I'm just curious if it's possible to create a GUISize method for my Frame.
I've tried to reference the frame outside the method but can't, I've looked for ways to reference a JFrame outside of the method you build it in, but can't
import java.awt.*;
import javax.swing.*;
public class CQAC {
public static void main(String args[])
{
GUI();
}
public static void GUI()
{
JFrame MainFrame = new JFrame("My First GUI");
MainFrame.setTitle("CQAC");
MainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MainFrame.getContentPane().add(GUISize);
GUISize();
MainFrame.setVisible(true);
}
public static void GUISize()
{
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
int screenHeight = screenSize.height;
int screenWidth = screenSize.width;
GUI.MainFrame.setSize(screenWidth / 2, screenHeight / 2);
GUI.setLocation((screenWidth/4)-8,screenHeight/4);
}
}
The code is supposed to open a blank JFrame that is half the size of the user's screen and placed in the middle of the screen, currently the JFrame doesn't open
Your current code won't compile and I'm not going to all the reasons why. static will make a fool of you quicker than just about anything else, learn to live without it, it has it's purposes and the way you're using really isn't one of them.
Instead. Start by creating a new instance of the class and just its construction phase to build up the elements you need. This way, you get out of the "can not reference non-static, blah, blah, blah" errors.
Instead, make a method whose sole job is to create the main frame, nothing else, have it return this instance.
Next, using the instance of the frame, pass that to your "make it sized" method and folia, you have a working pattern
For example...
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class CQAC {
public static void main(String args[]) {
// Get out of the static context as soon as possible
new CQAC();
}
public CQAC() {
JFrame mainFrame = makeMainFrame();
adaptToCurrentScreen(mainFrame);
mainFrame.setVisible(true);
}
protected JFrame makeMainFrame() {
JFrame mainFrame = new JFrame("My First GUI");
mainFrame.setTitle("CQAC");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return mainFrame;
}
protected void adaptToCurrentScreen(JFrame frame) {
Toolkit kit = Toolkit.getDefaultToolkit();
Dimension screenSize = kit.getScreenSize();
System.out.println(screenSize);
int screenHeight = screenSize.height;
int screenWidth = screenSize.width;
frame.setSize(screenWidth / 2, screenHeight / 2);
//frame.setLocation((screenWidth / 4) - 8, screenHeight / 4);
// And because this is simpler :/
frame.setLocationRelativeTo(null);
}
}
On a side note, getScreenSize this way you return the raw screen size, it won't take into consideration the size of things like the task bar or dock and menu bar on MacOS, which might make you window "look" offset when displayed.
Instead, you should be using the bounds of the GraphicsConfiguration, attached to the GraphicsDevice in the GraphicsEnvironment ... and no, these things can't be easy, for example
You might also want to taking a look at Passing Information to a Method or a Constructor

Why aren't my images being added to my JButtons?

I have a program that consists of four JButtons in a JFrame. I want to add images to the JButtons. The problem is that I can't seem to add them, despite trying multiple methods. When compiled, the output is input == null. The images are stored in the same folder as my .java files, so I can't figure out why they aren't showing up.
Main class:
import java.awt.GridLayout;
import java.awt.Image;
import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class AutoProgram extends JFrame {
private static String[] files = {"workA","programmingA","leisureA","writingA"};
private static JButton[] bIcons = new JButton[4];
private static Image[] bImg = new Image[4];
public AutoProgram() {
super("Automation Project V.1");
JPanel autoIcons = new JPanel();
autoIcons.setLayout(new GridLayout(2,2));
// Initialize the four buttons (w/ images)
for(int i = 0; i < files.length; i++) {
bIcons[i] = new JButton();
try {
bImg[i] = ImageIO.read(getClass().getResource(files[i].toLowerCase() + ".png"));
bIcons[i].setIcon(new ImageIcon(bImg[i]));
} catch (Exception ex) {
System.out.println(ex);
}
autoIcons.add(bIcons[i]);
}
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));;
mainPanel.add(autoIcons);
add(mainPanel);
pack();
}}
Window class:
public class Window {
public static void main(String[] args) {
AutoProgram frame = new AutoProgram();
frame.setSize(315,315);
frame.setLocationRelativeTo(null);
frame.setFocusable(true);
frame.setResizable(true);
frame.setVisible(true);
}
}
Any help would be greatly appreciated. Thanks!
Before going into the answer to your question, please read the following recommendations:
private static JButton[] bIcons = new JButton[4]; Creating static fields could break your program, so be careful when to use them. Not really needed in this case, please read What does the 'static' keyword do in a class?
JFrame is a rigid container which cannot be placed inside others, and you're not changing it's functionallity anywhere in your program, so there's no need to call extends JFrame, it's better to create a JFrame instance then. See: Extends JFrame vs. creating it inside the program for more information about this.
You're correctly calling pack() but later in the code you're calling frame.setSize(315,315); which "destroys" the changes made by pack(), use one or the other, not both, I recommend you to leave pack() call.
You're not placing your program in the Event Dispatch Thread (EDT), you can fix it by changing your main(...) method as follows:
public static void main (String args[]) {
//Java 7 and below
SwingUtilities.invokeLater(new Runnable() {
//Your code here
});
//Java 8 and higher
SwingUtilities.invokeLater(() -> {
//Your code here
});
}
Now, let's go to the solution:
Your code works fine, I think that your errors might come from the following posibilities:
Calling files[i].toLowerCase() (.toLowerCase() method might be breaking your program, Java is case sensitive).
Your images are not PNG but JPG or JPEG (look at the extension carefully)
Your images are damaged

I created my GUI in a GUI class' constructor. How would I access its Frames, Panels etc. from another class?

First of all, this is a more specific question than it seems to be. To start off: I am currently doing a small application with a rather small GUI, so I decided to make a GUI class, and initialize my whole GUI in this constructor.
This would look like this:
public class GUI extends JFrame{
public GUI{
//Initialize GUI here, including its Frames, Panels, Buttons etc.
}
}
How can I now access the GUIs frame etc. from an external class? If I would create an object of the GUI class, I would simply duplicate my GUI window. I did not come across any other ideas than making the frame, panel and so on static.
I'm somewhat lost right now. Also I'm pretty sure that I am not thinking the right way into this case, but I need someone to point me to the right direction. If someone could help me out, I would be very thankful.
First of all, using static is the worst solution possible, even if your GUI class is a singleton (buf if it is, at least it will work fine).
Why don't you simply create getters and/or setters ? And finally, it is usually not normal that external classes need to access the components of another graphic class. You should wonder if your design is the most fitted for your needs.
Here's a simple GUI to change the background color of a JPanel with a JButton. Generally, this is how you construct a Swing GUI.
package com.ggl.testing;
import java.awt.Color;
import java.awt.FlowLayout;
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.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ChangeDemo implements Runnable {
private boolean isYellow;
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new ChangeDemo());
}
#Override
public void run() {
frame = new JFrame("Change Background Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
JPanel namePanel = new JPanel();
JLabel nameLabel = new JLabel(
"Click the button to change the background color");
nameLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
namePanel.add(nameLabel);
mainPanel.add(namePanel);
final JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout());
buttonPanel.setBackground(Color.YELLOW);
isYellow = true;
JButton changeButton = new JButton("Change Color");
changeButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
isYellow = !isYellow;
if (isYellow) buttonPanel.setBackground(Color.YELLOW);
else buttonPanel.setBackground(Color.RED);
}
});
buttonPanel.add(changeButton);
mainPanel.add(buttonPanel);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
You don't access the Swing components of the GUI from other classes. You create other classes to hold the values of the GUI.
Generally, you use the model / view / controller pattern to construct a Swing GUI. That way, you can focus on one part of the GUI at a time.
Take a look at my article, Java Swing File Browser, to see how the MVC pattern works with a typical Swing GUI.
You don't need to make it static or to create a new JFrame object every time.
Have a look at this simple code :
class UseJFrame {
public static void main(String...args) {
Scanner sc = new Scanner(System.in);
JFrame frame = new GUI();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
System.out.println("Press E to exit");
String ip;
while(true) {
System.out.println("Show GUI (Y/N/E)? : ");
ip = sc.nextLine();
if(ip.equalsIgnoreCase("y") {
frame.setVisible(true);
} else if(ip.equalsIgnoreCase("n") {
frame.setVisible(false);
} else { // E or any other input
frame.dispose();
}
}
}
}
Note : Don't make GUI visible through constructor or it will show window at the very starting of creation of JFrame object.
If you want to use the same JFrame object at other places too then pool architecture would be better approach.

JButtons "extending" out of my JFrame

Sorry about my English, and my ignorance in programming, its because I'm new at this , and I'm having problem with Buttons and JFrame, please help me ;)
I'll post the print of the problem, and the codes of my the two classes I have so far, Game and Menu, hope you guys can solve it, I want the buttons to paint inside the gray panel.
Thanks.
Print of my Problem
Print
(GAME CLASS)
package br.com.lexo.dagame;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import javax.swing.JFrame;
import br.com.lexo.dagame.menu.Menu;
public class Game extends Canvas implements Runnable {
private static final long serialVersionUID = 1L;
private static int width = 300;
private static int height = width / 16 * 9;
private static int scale = 3;
private static String title = "Da Game";
private Thread thread;
public JFrame janela;
private Menu menu;
private boolean running = false;
public Game() {
Dimension size = new Dimension(width * scale, height * scale);
setPreferredSize(size);
janela = new JFrame();
menu = new Menu(janela, this);
}
private synchronized void start() {
if (running) return;
running = true;
thread = new Thread(this, "Thread_01");
thread.start();
}
private synchronized void stop() {
if (!running) return;
running = false;
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
g.dispose();
bs.show();
}
public void update() {
}
public void run() {
while (running){
render();
update();
}
stop();
}
public static void main(String[] args) {
Game game = new Game();
game.janela.add(game);
game.janela.setTitle(title);
game.janela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.janela.pack();
game.janela.setLocationRelativeTo(null);
game.janela.setResizable(false);
game.janela.setVisible(true);
game.start();
}
}
(MENU CLASS)
package br.com.lexo.dagame.menu;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import br.com.lexo.dagame.Game;
public class Menu extends Canvas {
private static final long serialVersionUID = 1L;
public boolean inMenu = false;
JButton startGame = new JButton("Começar Jogo");
JButton exitGame = new JButton("Sair do Jogo");
JButton howToPlay = new JButton("Como Jogar");
private Game game;
public Menu(JFrame janela, Game game){
this.inMenu = true;
this.game = game;
game.janela.setLayout(new GridBagLayout());
game.janela.add(startGame);
game.janela.add(exitGame);
game.janela.add(howToPlay);
howToPlay.setEnabled(false);
}
#Override
public void paint(Graphics g) {
super.paint(g);
}
}
I don't know what are you trying to accomplish but you are not adding the components correctly:
Look at:
game.janela.setLayout(new GridBagLayout());
game.janela.add(startGame);
game.janela.add(exitGame);
game.janela.add(howToPlay);
This is incorrect, the add method has two arguments, like this: container.add(component, constraints); your error is not specifying the constraints. The constraints contains all the details to know where in the panel you want to add that component.
For each LayoutManager the Object constraints is diferent. For the GridBagLayout the constraints is a GridBagConstraints object.
However GridBagLayout is a the most difficult layout to use and you don't really need it. I recommend you to look at this visual guide pick a layout and learn it properly. The tutorial for each LayoutManager explains what do you need to put in the constraints parameter.
The call container.add(component) exists because sometimes the LayoutManager does not need extra information (like the BoxLayout), in the other cases it just uses the "default" constraints for the LayoutManager in use, which may not be what you need.
For example the line in your main:
game.janela.add(game);
Is correct, but what it actually does is calling game.janela.add(game, defaultConstraints); where defaultConstraints is the default constraints value for the LayoutManager of the JFrame janela. Because you didn't explicitely specify a layout for the frame it is using the default layout for JFrames: BorderLayout, and the default constraints for the BorderLayout is the constant BorderLayout.CENTER.
So what that line actually does is:
game.janela.add(game, BorderLayout.CENTER);
Which incidentally is what you wanted to do.
To summarize:
Most calls to add must have two parameters: the component and the constraints. Each LayoutManager uses different constraints. You must be aware of what means to not specify the constraints for your LayoutManager. Do not start learning about how to properly use LayoutMangers with the GridBagLayout it's much more complex.
A quick way to somehow paint components to a graphics object is calling the paint method of component class. So in your render method:
g.fillRect(0, 0, getWidth(), getHeight());
menu.startGame.paint(g);
...
But as you'll soon see that everything is painted on the top left as components are laid out as said in the other answer and to get everything working to how you want them to work is a bit more complicated.
Now the following advice is based on my limited knowledge and was quickly put together so there are probably better ways.
About the menu class:
You are extending java.awt.Canvas when I think it would be best to extend a container like javax.swing.JPanel as you want it (I assume) to hold those 3 buttons.
Next would be to set the appropriate layout for this application, which would be null. So instead of:
game.janela.setLayout(new GridBagLayout());
it would now be:
setLayout(null);
This is because you want components (which are those buttons) to be paint on top of another component which is the Game class that extends Canvas and null allows you to do that.
Because the layout is now null, you must specify the bounds of the components which are the x and y coordinates alone with the width and the height otherwise everything will just be 0, 0, 0, 0 and nothing would show up.
So in the Game's constructor
setBounds(0, 0, width * scale, height * scale);
and janela.setPreferredSize(size); instead of setPreferredSize(size);
Back in the Menu class you will have to set the bounds of the buttons like so:
Dimensions sgSize = startGame.getPreferredSize();
startGame.setBounds(50, 50, sgSize.width, sgSize.height);
I am using preferred size to get the optimal width and height of the button that was set in the buttons UI (I think).
and add them to the Menu which is now a JPanel instead of adding them to the JFrame(janela). (add(startGame);) Also, don't forget to add the game to the menu panel.
and it should work like so:
(http://i.imgur.com/7cAopvC.png) (image)
Alternatively you could make your own widget toolkit or custom layout, but I wouldn't recommend that. I had this same problem last year but ended up moving to OpenGL but anyway, I hope this has helped :)

Categories

Resources