So, I've recently started learning Java, and I am really enjoying it despite the several issues and things that I have not yet understood, it makes me keep going on with it. So, considering that it is my first ever programming language, bear with me on any "noob" mistakes I make.
So, I created a fullscreen window using JFrame:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main extends JFrame {
public static void main(String[] args) {
//Window
JFrame mainWindow = new JFrame("Day One");
mainWindow.setExtendedState(JFrame.MAXIMIZED_BOTH);
mainWindow.setUndecorated(true);
mainWindow.setVisible(true);
//End Window
}
}
And then I tried to add a background image to the window by adding this:
mainWindow.setLayout(new BorderLayout());
mainWindow.setContentPane(new JLabel(new ImageIcon("C:\\Users\\Recordings\\Desktop\\Day One\\Images\\Main-Background-Image.png")));
mainWindow.setLayout(new FlowLayout());
I found this code here but it isn't working at all. In this website there are two different ways of making it but I have tried both of them and none works.
I have also searched here, in stackoverflow, for similar questions, but all of them were either unanswered or answered with the same example as mine.
I really hope I have been clear enough, thank you very much for your time
EDIT:
As suggested, I have separated the long single statement:
mainWindow.setContentPane(new JLabel(new ImageIcon("C:\\Users\\Recordings\\Desktop\\Day One\\Images\\Main-Background-Image.png")));
Into three more easier debugged statements:
ImageIcon image = new ImageIcon("C:\\Users\\Recordings\\Desktop\\Day One\\Images\\Main-Background-Image.png");
JLabel label = new JLabel(image);
mainWindow.setContentPane(label);
Just a few tips
Its usually best to put a panfel within a frame and then add components to that. Makes for good containment when swing classes get a bit bigger.
Its better to create a resource folder for your projects. Create one in the source of your project e.g. where the src and bin folders are located for your project and name it "resources".
When creating and image icon its good practice to surround with a try catch so you can give appropriate errors and locate easily, or even handle the error at runtime.
With all that being said, here is your code with a little extra. It creates a panel to hold the jlabel(image) and it adds that panel to the frame. It creates an image icon with a quick method, all you have to do is pass in the file name. This method assumes you have created the folder in your project directory called resources and placed your image in there.
public static void main(String[] args) {
//Window
JFrame mainWindow = new JFrame("Day One");
mainWindow.setExtendedState(JFrame.MAXIMIZED_BOTH);
mainWindow.setUndecorated(true);
//Create image
JLabel imageHolder = new JLabel();
imageHolder.setIcon(makeImageIcon("example.png"));
//Add image to panel, add panel to frame
JPanel panel = new JPanel();
panel.add(imageHolder);
mainWindow.add(panel);
mainWindow.setVisible(true);
}
//Creates imageicont from filename
public static ImageIcon makeImageIcon(String filename) {
BufferedImage myPicture = null;
try {
myPicture = ImageIO.read(new File("resources/" + filename));
} catch (IOException e) {
e.printStackTrace();
}
return new ImageIcon(myPicture);
}
Hope this helps
Related
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.
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);
}
I hope everyone is doing alright this fine day.
I'm learning swing and I was confused by how to reference an image. I understand that I should use a JLabel and then add that JLabel to the Frame using this.add();, but even looking at the oracle documentation here:
https://docs.oracle.com/javase/6/docs/api/javax/swing/ImageIcon.html
It is still unclear how to reference a file without giving the entire path like
C:\Users\someUser\eclipse-workspace\andSoOn.png
And I can't do that. I have to send my work to my teacher once I'm done, and the code won't reference the file like it does on my system. I tried several things, and I ended up making a new folder in the src in eclipse called ImageAssets and moving the files there, but nothing seems to work. Here is what it looks like
Here is an example of my attempt to display an image from within the package.
import java.awt.*;
import javax.swing.*;
public class Hangman extends JFrame
{
JButton playGameButton,
OptionsButton;
private ImageIcon hangman7;
private JLabel mainLabel;
public static void main(String[] args)
{
new Hangman();
}
public Hangman()
{
this.setSize(1000,800);
this.setLocationRelativeTo(null);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle("Hangman");
this.setResizable(false);
playGameButton = new JButton("Start Game");
OptionsButton = new JButton("Options");
//hangman7 = new ImageIcon(getClass().getResource("Images\\ hangman7.png"));//just an attempt at something
mainLabel = new JLabel();
mainLabel.setIcon(new ImageIcon("hangman7.png"));
JPanel somePanel = new JPanel();
somePanel.setLayout(new BorderLayout());
somePanel.add(playGameButton, BorderLayout.WEST);
somePanel.add(OptionsButton, BorderLayout.EAST);
somePanel.add(mainLabel, BorderLayout.CENTER);
this.add(somePanel);
this.validate();
}
Thank you so much for taking the time to help me. I tried to be very detailed; if anything is unclear please ask.
In your case, you want let the class loader find the resource, like this:
mainLabel.setIcon(
new ImageIcon(getClass().getResource("/ImageAssets/hangman7.png")));
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'm doing a project where i need some custom swing components. So far I have made a new button with a series of images (the Java Metal look doesn't fit with my UI at all). Ive implemented MouseListener on this new component and this is where my problem arises. My widget changes image on hover, click etc except my MouseListener picks up mouse entry into a the entire GridLayout container instead of into the image. So I have an image of about 200*100 and the surrounding container is about 400*200 and the mouseEntered method is fired when it enters that GridLayout section (even blank space parts of it) instead of over the image. How can I make it so that it is only fired when I hover over the image? Ive tried setting size and bounds and other attributes to no avail.
EDIT: Here's a demonstration of my issue. As you can see (sort of, colors are very similar) the bottom right button is highlighted just by entering its section of the GridlLayout. I only want it highlighted when I'm over the image actual, not the GridLayout section.
I Won't add the MouseListener methods because they just involve switching the displayed image.
public customWidget()
{
this.setLayout(new FlowLayout());
try {
imageDef=ImageIO.read(new File("/home/x101/Desktop/buttonDef.png"));
imageClick=ImageIO.read(new File("/home/x101/Desktop/buttonClick.png"));
imageHover=ImageIO.read(new File("/home/x101/Desktop/buttonHover.png"));
current=imageDef;
} catch (IOException e)
{
e.printStackTrace();
}
this.addMouseListener(this);
}
protected void paintComponent(Graphics g)
{
super.paintComponents(g);
g.drawImage(current, 0, 0, current.getWidth(), current.getHeight(), null);
}
EDIT: added code section
As an alternative, consider the The Button API, which includes the method setRolloverIcon() "to make the button display the specified icon when the cursor passes over it."
Addendum: For example,
import java.net.MalformedURLException;
import java.net.URL;
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 ButtonIconTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
private static void createAndShowGui() {
String base = "http://download.oracle.com/"
+ "javase/tutorial/uiswing/examples/components/"
+ "RadioButtonDemoProject/src/components/images/";
ImageIcon dog = null;
ImageIcon pig = null;
try {
dog = new ImageIcon(new URL(base + "Dog.gif"));
pig = new ImageIcon(new URL(base + "Pig.gif"));
} catch (MalformedURLException ex) {
ex.printStackTrace(System.err);
return;
}
JFrame frame = new JFrame("Rollover Test");
JPanel panel = new JPanel();
panel.add(new JLabel(dog));
panel.add(new JLabel(pig));
JButton button = new JButton(dog);
button.setRolloverIcon(pig);
panel.add(button);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
I assume your image contains ONLY 4 'customWidget' objects (in a 2x2 grid).
Your code is working as I would expect. Your MouseListener methods are responding to MouseEvents for 'customWidget' (not the image drawn in 'customWidget'), which is sized to take up 1/4 of the image, so they will respond when it enters the enlarged area. The error is actually in your Test program, because you are allowing the custom button widget to be larger than the image.
If you want a Test program that provides an image similar to yours, you should create a larger grid (say 4x4), and then only place your buttons in every other grid node. Place an empty component into the gaps.
Although I won't answer to your particular question, I hope this helps:
If the components just look wrong maybe you should reuse Swing components and just write a custom Look&Feel or theme.
It would certainly help ensuring the look of the application is consistent and at least you are using the right tool for the task you want to accomplish.
As a sidenote, be aware that Java comes with multiple Look&feels, including Look&Feels made to mimic the native OS theme.
See: http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html