java panel with png background - java

i found this link.. LINK what i want is there's a JPanel that has a background and another JPanel with half the size of the first JPanel but with an image that is transparent and with a face or a ball at the middle.. :) just like the screenshot from the link.. is that possible to code in java? :) im just thinking it like for web programming. just a sort of DIV's to have that but i dont know in java.. :) sorry for bad english.. :D i have this as a background..
package waterKing;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
#SuppressWarnings("serial")
public class Main extends JFrame {
MainData data = new MainData();
public static void main(String[] args) {
Main frmMain = new Main();
frmMain.setExtendedState(Frame.MAXIMIZED_BOTH);
frmMain.setVisible(true);
}
public Main() {
data.tk = getToolkit();
data.d = data.tk.getScreenSize();
data.jP = new JPanel() {
protected void paintComponent(Graphics g) {
data.e = getSize();
data.iI = new ImageIcon("images/mainBG.png").getImage();
g.drawImage(data.iI,0, 0, data.d.width, data.d.height, null);
super.paintComponent(g);
}
};
data.jP.setOpaque(false);
data.jSp = new JScrollPane(data.jP);
data.jB = new JButton("EXIT");
data.jB.setBounds(10,10,200,40);
data.jB.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
data.jP.setLayout(null);
data.jP.add(data.jB);
this.setTitle("Water King Inventory System");
this.setUndecorated(true);
this.getContentPane();
this.add(data.jSp);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
}
}
i dont know how to add another JPanel to show in the middle with this background

i dont know how to add another JPanel to show in the middle with this background
Its just like adding components to a panel. You need to use a layout manager and then the component will be positioned properly based on the rules of the layout manager. In your case you can set the layout manager of the background panel to be a BorderLayout. Then you can add a JLabel with the appropriate Icon to the center of the BorderLayout.
You will need to set the preferred size (or override the getPreferredSize() method of your panel since you add it to a scroll pane. Scrollbars will only appear when the preferred size of the panel is greater than the size of the scroll pane.
You should not be reading the image in your paintComponent() method since this method is called multiple times.
You should not be using the "screen size" to determine the width/height of the image because the frame will contain a border. You need to use the size of the panel.
Get rid of all the setBounds() code. Learn to use layout managers.
For a general purpose background panel that takes into account most of the suggestions made here check out Background Panel.

Related

why is importing a font breaking other parts of code?

Modifiers.java:
package game;
import java.awt.*;
import java.io.*;
import javax.swing.*;
public class Modifiers extends Data{
public static void setupJcomponents(){
frame.setUndecorated(true);
frame.setSize(MW,MH);
frame.setResizable(false);
frame.setVisible(true);
frame.setLayout(null);
for(int btn=0; btn<4; btn++) {
Buttons[btn] = new JPanel();
Buttons[btn].setBounds(btn*100,0,100,100);
Buttons[btn].setVisible(true);
Buttons[btn].setBackground(new Color(btn*50,btn*50,btn*50));
frame.getContentPane().add(Buttons[btn]);
}
menuBackground.setBounds(0,0,MW,MH);
menuBackground.setVisible(true);
menuBackground.setBackground(Color.black);
healthIndicator.setText(String.valueOf(healthValue));
healthIndicator.setFont(new Font("Terminal", Font.PLAIN, 100));
healthIndicator.setBounds(600,600,100,100);
healthIndicator.setForeground(Color.blue);
try{
PixelFont = Font.createFont(Font.TRUETYPE_FONT, new File("PixelFont.ttf"));
} catch (IOException e) {
PixelFont = new Font("Terminal", Font.PLAIN, 100);
} catch(FontFormatException e) {
PixelFont = new Font("Terminal", Font.PLAIN, 100);
}
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(PixelFont);
frame.getContentPane().add(healthIndicator);
frame.getContentPane().add(menuBackground);
}
}
Data.java:
package game;
import java.awt.*;
import javax.swing.*;
public class Data {
// this is where I will declare and alter all variable that will be used
public static JFrame frame = new JFrame();
public static JLabel healthIndicator = new JLabel();
public static JPanel Buttons[] = new JPanel[5];
public static JPanel menuBackground = new JPanel();
public static final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
public static final int MW = (int) screenSize.getWidth();
public static final int MH = (int) screenSize.getHeight();
public static Font PixelFont;
public static int maxHealth = 100;
public static int healthValue = maxHealth;
}
Frame.java:
package game;
public class Frame {
public static void main(String[] args) {
Modifiers.setupJcomponents();
}
}
whenever i rum Frame.java the menu Background disappears and the text altogether stops showing up. but if the path to the .ttf file is wrong it just skips over the font and uses the default instead. How do i get this font to load properly as well as not cause my background background to disappear? I have tried changing the path to the .ttf file and turning various parts of the code into comments, but even if the font of the health indicator is a default font, these errors will still occur, however if i try removing the try-catch loop then the errors aren't there anymore.
There are all kinds of problems with the code. Not exactly sure why the Fonts is causing an issue, but it has something to do with the overall structure of your code and you aren't using Swing the way it was designed to be used.
whenever i rum Frame.java the menu Background disappears and the text altogether stops showing up
What appears to be directly related to the above question is that the setVisible(true) statement should be executed AFTER all the components have been added to the frame. This will make sure all the components are painted.
Note this will still only work by chance because you happen to add the "background" panel to the frame last. Swing paints components in the reverse order that are added to any given panel.
Regarding other problems.
your painting code only works by chance. You should not be adding all your components directly to the frame. Swing is not designed to paint components in 3 dimensions directly when the components overlap one another. Swing is designed to have a parent child relationship. So that would mean you add your "background" panel to the frame. Then you add a panel containing the buttons to the "background" and you add the "health" component to the background.
Related to above you should NOT be using a null layout. Swing was designed to be used with a layout manager. This will make sure components don't overlap. So in your case you can use a BorderLayout for the "background" panel. Then you can add the "buttons" panel to the BorderLayout.PAGE_Start and the "health" component to the `BorderLayout.PAGE_END. This will ensure that the components are at the top/bottom of the background panel.
Don't set the size of the frame. Instead you use the setExtendedState(JFrame.MAXIMIZED_BOTH) property. The frame will be the size of the screen. The "GamePanel" will be take up all the space of the frame. So there is no need to set or use hardcoded values.
Don't use static variables and method. This indicates poor design. What you should be doing is creating a GamePanel class, which would essentially be your background panel. This class would contain the instance variables needed for the game. It would create the "buttons" panel and the "health" component and add it to itself.
Variable names should NOT start with upper case characters.

Make JScrollPanel dynamically resizable with JPanel drawing

I have a JScrollPanel and a JPanel added to it. I would like to draw to the JPanel and make the scrollbars of the JScrollPane appear whenever the drawing exceeds the size of the panel and be able to scroll the drawing both vertically and horizontally.
I have tried consulting with various forums and the official docs and tried a few things (setting the borders, the preferred size, etc.) but none seems to yield the desired effects.
I have a JFrame (with GridBagLayout, btw.) :
JFrame frame1 = new JFrame("Application");
frame1.setVisible(true);
frame1.setMinimumSize(new Dimension(580,620));
frame1.setResizable(false);
frame1.setLocationRelativeTo(null);
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
The relevant components are :
JPanel panel1 = new JPanel();
JScrollPane scrollPane = new JScrollPane(panel1);
frame1.add(scrollPane, gbc_panel1); //added with layout constraints
JPanel :
panel1.setBackground(Color.BLACK);
panel1.setPreferredSize(new Dimension(500,500));
panel1.setMinimumSize(new Dimension(360,360));
panel1.setMaximumSize(new Dimension(1000,1000));
JScrollPane :
scrollPane.setAutoscrolls(true);
The relevant code from the action event
of a button that does the drawing :
Graphics g;
g = panel1.getGraphics();
panel1.paint(g);
g.setColor(new Color(0,128,0));
/* this is followed by some more code that
does the drawing of a maze with g.drawLine() methods */
The code does the drawing perfectly, I just can't seem to figure it out how to make the scrolling and dynamic resizing happen.
I would appreciate any helpful comments or remarks!
Thank you!
Ultimately rewriting the paint method did the trick as #MadProgrammer suggested. I was just hoping that I could do the painting without having to define my custom JPanel class, but looks like it doesn't work that way.
The custom class looks like this:
class Drawing extends JPanel {
int mazeSize;
public Drawing(JTextField jtf)
{
try {
this.mazeSize = Integer.parseInt(jtf.getText());
}
catch (Exception e)
{
JOptionPane.showMessageDialog(this, "ERROR! Invalid size value!");
}
} // the constructor gets the size of the drawing from a textField
public Dimension getPreferredSize() {
return new Dimension(mazeSize*10,mazeSize*10);
} //getPreferredSize - this method is used by the scroll pane to adjust its own size automatically
public void drawMaze (Graphics g)
{
/* some irrelevant code that does the desired drawing to the panel by calling g.drawLine()*/
} // drawMaze method that does the de facto drawing
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawMaze(g);
}// paintComponent() #Override method - this was the tricky part
}//Drawing JPanel subclass
It is also worth noting (if some noob like myself happens to stumble upon this question), that after instantiating the new JPanel subclass in the action event, I had to add it to the JScrollPanel in the following way, instead of just simply using its add() method:
Drawing drawPanel = new Drawing(textfield1);
scrollPane.getViewport().add(drawPanel);
Again, thanks for the suggestion!
Once finished with the program (a random maze generator that uses a recursive backtracking algorithm), I will make the source code available at my github profile.

How to create a "Game Option/Pause Screen" in Swing?

Background: Making a game in Swing. It is simple turn base game. Not a whole lot going on. Because of this I didn't think I would need to implement a Game Tick. Rather, my thought was when a component got changed or needed to be updated just simply revalidate/repaint that component on the fly rather than repainting the whole screen.
I have a GameJPanel which currently has all the components on it. This JPanel is the one that contains the components that get revalidated/repainted etc.
I figured I could make JLayeredPane that holds GameJPanel and my OptionJPanel. Have a Button on GameJPanel that when pressed causes the OptionJPanel to show on top of it and having its JPanel 50% transparent (so it gives the affect it dims the GameJPanel).
However, once I did this what happened was that the GameJPanel started to replace OptionJPanel components (because of the events... etc; repainting of the components).
So currently I am at a loss on what to do. I'm thinking if I had some sort of game tick I wouldn't be having this issue, however, I am not 100% certain. I'm a little worried if I implemented a gametick that the events in game will cause the GameJPanel components to show through for half a second then get replaced. There are some events that cause components to repaint themselves without manually doing it (like quick example for JLabel setText();)
As an example of what I'm trying to go for.
I have tried with a CardLayout but I couldn't figure out how to have the OptionJPanel be on top of GameJPanel while seeing GameJPanel in the background (I tried setting background color, setOpaque(false)..., tried to limit Option JPanel size but I think the CardLayout stretches it (not 100% sure)) all I got was a gray background when doing so.
I would prefer not to go the CardLayout route because in the future I also plan on placing components on top of the GameJPanel (like someone clicks a button, have another panel on a different layer have a component slide in or out etc).
I use CardLayout a ton with my other components in GameJPanel to swap screens around, but haven't had the need to have the other components behind the one showing to show through.
Any ideas on how to go about this would be great or even example code that shows this.
As noted above, you would use a JDialog, a component that is easy to make (similar to making a JFrame) and easy to place. Simply place it "relative-to" the JFrame, e.g.,
myDialog.setLocationRelativeTo(myJFrame);
... and it will automatically center itself on the JFrame. The tricky part is dimming the underlying JFrame, and for this you would need to use a JGlassPane added to the JFrame's rootpane, one set with a background color that uses an alpha composite value. The tricky part with this is to draw the darker background without causing side effects, and to do this, please read Rob Camick's (StackOverflow user camickr) excellent tutorial on drawing in Swing with alpha composites which you can find here: Java Tips Weblog: Backgrounds with Transparency
An example of such a program is shown here:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
public class DialogEg {
// path to example image used as "game" background
private static final String IMG_PATH = "https://upload.wikimedia.org/"
+ "wikipedia/commons/7/76/Jump_%27n_Bump.png";
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
// get the "game" background image, or exit if fail
BufferedImage img = null;
try {
URL imgUrl = new URL(IMG_PATH);
img = ImageIO.read(imgUrl);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
// pass "game" image into main JPanel so that it will be drawn
DeMainPanel mainPanel = new DeMainPanel(img);
JFrame frame = new JFrame("Dialog Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel); // add main JPanel to JFrame
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
// main JPanel
#SuppressWarnings("serial")
class DeMainPanel extends JPanel {
private BufferedImage img; // background image
// JButton action that shows the JDialog and darkens the glasspane
private PauseAction pauseAction = new PauseAction("Pause");
public DeMainPanel(BufferedImage img) {
super();
this.img = img;
add(new JButton(pauseAction));
}
// draw the "game" background image within the JPanel if not null
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
// size this JPanel to match the image's size
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet() || img == null) {
return super.getPreferredSize();
}
int width = img.getWidth();
int height = img.getHeight();
return new Dimension(width, height);
}
}
// Action / ActionListener for JButton -- shows JDialog and darkens glasspane
#SuppressWarnings("serial")
class PauseAction extends AbstractAction {
private static final int ALPHA = 175; // how much see-thru. 0 to 255
private static final Color GP_BG = new Color(0, 0, 0, ALPHA);
private DeDialogPanel deDialogPanel = new DeDialogPanel(); // jpanel shown in JDialog
public PauseAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
// comp is our JButton
Component comp = (Component) e.getSource();
if (comp == null) {
return;
}
// create our glass pane
JPanel glassPane = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
// magic to make it dark without side-effects
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
};
// more magic below
glassPane.setOpaque(false);
glassPane.setBackground(GP_BG);
// get the rootpane container, here the JFrame, that holds the JButton
RootPaneContainer win = (RootPaneContainer) SwingUtilities.getWindowAncestor(comp);
win.setGlassPane(glassPane); // set the glass pane
glassPane.setVisible(true); // and show the glass pane
// create a *modal* JDialog
JDialog dialog = new JDialog((Window)win, "", ModalityType.APPLICATION_MODAL);
dialog.getContentPane().add(deDialogPanel); // add its JPanel to it
dialog.setUndecorated(true); // give it no borders (if desired)
dialog.pack(); // size it
dialog.setLocationRelativeTo((Window) win); // ** Center it over the JFrame **
dialog.setVisible(true); // display it, pausing the GUI below it
// at this point the dialog is no longer visible, so get rid of glass pane
glassPane.setVisible(false);
}
}
// JPanel shown in the modal JDialog above
#SuppressWarnings("serial")
class DeDialogPanel extends JPanel {
private static final Color BG = new Color(123, 63, 0);
public DeDialogPanel() {
JLabel pausedLabel = new JLabel("PAUSED");
pausedLabel.setForeground(Color.ORANGE);
JPanel pausedPanel = new JPanel();
pausedPanel.setOpaque(false);
pausedPanel.add(pausedLabel);
setBackground(BG);
int eb = 15;
setBorder(BorderFactory.createEmptyBorder(eb, eb, eb, eb));
setLayout(new GridLayout(0, 1, 10, 10));
add(pausedPanel);
add(new JButton(new FooAction("RESUME")));
add(new JButton(new FooAction("RESTART")));
add(new JButton(new FooAction("EXIT TO MAP")));
}
// simple action -- all it does is to make the dialog no longer visible
private class FooAction extends AbstractAction {
public FooAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
Component comp = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(comp);
win.dispose(); // here -- dispose of the JDialog
}
}
}
The GUI looks like this initially:
but then when the dialog shows and the glass pane is darkened, it looks like this:
So after about a month of working on my game I was drawn to this post once again. I implemented part of my game with what DontKnowMuchButGettingBetter's way and also implemented this by just adding the components to the GlassPane so to speak (Made a JPanel, set it to be GlassPane, did whatever on that Panel)...
The later implementation (GlassPane), isn't the best way to go about this because then you can't use the glass pane for other useful things.
I came back to my original idea to use a JLayeredPane. Having different Components on different levels and working off that. My issue before was that when components were getting repainted, the components in the backer layers were over painting the ones in the front layer.
Well I just came across a method called isOptimizedDrawingEnabled()... By making this method always return false for the JLayeredPane I was able to achieve what I wanted.

Adding a jpanel over a jlabel background

I know this question has been asked before but i cant seem to implement any of the other answers to my project. So i have my paint method in my player class here.
public void paintComponent(Graphics g)
{
//makes player(placeholder for real art)
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(x,y,50,30);
}
Then I have my main class here.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* Write a description of class Main here.
*
* #author Richard Zins
* #V01
*/
public class Main extends JFrame
{
public static void main(String[]args)
{
Player p1 = new Player();
Main m = new Main(p1);
}
public Main(Player p1)
{
JFrame ar = new JFrame();
JLabel background = new JLabel(new ImageIcon("/Users/rizins/Desktop/PacManTestBackGround.jpg"));
ar.setTitle("Runner Maze");
ar.setSize(800,600);
ar.add(background);
ar.setVisible(true);
ar.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ar.add(p1);
}
}
Now I cant seem to get my player object to paint over my background any help would be appreciated!
There are a couple of mistakes...
JPanel by default is opaque, so you need to change it to be transparent
JFrame uses a BorderLayout by default, so only one component will be shown at the (default) center position, in this case, the last thing you add.
You should call setVisible last
Instead, set a layout manager for the JLabel and add your player class to it. Instead of adding the JLabel to the frame, you should make the label the contentPane for the frame, for example...
p1.setOpaque(false);
JFrame ar = new JFrame();
ar.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel background = new JLabel(new ImageIcon("/Users/rizins/Desktop/PacManTestBackGround.jpg"));
ar.setTitle("Runner Maze");
ar.setContentPane(background);
ar.setLayout(new BorderLayout());
ar.add(p1);
ar.pack();
ar.setVisible(true);
I should point out that using a JLabel to display a background image like this could cause you problems, as the JLabel only uses the text and icon properties to calculate its preferred size, this could cause some child components to be laid out beyond its visible range.
See How to set a background picture in JPanel for more details and a possible solution
You can make the JPanel transparent by setting the opaque to false. e.g:
panel.setOpaque(false)
Try is if this work for you.
Use a JLayeredPane and add your background at the index 0 (indexed with an Integer not an int). Then you add another JPanel that is not opaque (like in #Bahramdun Adil 's answer) and add your player to that.
This way you can have a background and display your player at the same time.

JFrame position three buttons one below another in the center

So I would like to have three JButtons all on top of each other, but not to large in width or height either. I am not too familiar with Java's layouts, and to be honest I am not too keen on them. Please view the image a code below to explain to me how, thanks.
package com.aqagame.harrykitchener;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Main
{
private JButton playGame, playerNames, exitGame;
public Main()
{
JPanel mainCard = new JPanel(new BorderLayout(8, 8));
playGame = new JButton("Play Game");
playerNames = new JButton("Player Names");
exitGame = new JButton("Exit Game");
mainCard.add(playGame, BorderLayout.NORTH);
mainCard.add(playerNames, BorderLayout.CENTER);
mainCard.add(exitGame, BorderLayout.SOUTH);
JFrame window = new JFrame("Harry's AQA game");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().add(mainCard);
window.setSize(900, 800);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Main();
}
});
}
}
Check out the Java Documentation for the different layout managers. I know you're not familiar with them, which is why you should probably start. Once you get used to them there is no end to their benefits. There is a lot of excellent information in the documentation and I am sure you will learn a lot. Personally, I recommend looking at the Box Layout:
Create JPanel that uses a GridLayout and add all the buttons to the panel. The GridLayout will automactially size the buttons to be the same size.
Set the layout manager of your main window to use a GridBagLayout.
add the panel to the main window using the default GridBagConststraints. Then the panel will automatically be centered both horizontally and vertically.
To not use Box or GridBag, I think a combination such as this may work out:
Have main panel (let's call it A) have a BorderLayout
Create another panel (let's call it B), with a FlowLayout, with constructor aligning components to the center
Create another panel (let's call it C), with a GridLayout, 1 column 3 rows
Add each button to a new JPanel with a FlowLayout (1 JPanel per button, so buttons are wrapped by a FlowLayout), and then add each of those JPanels to C
Add C to B
Add B to A (center position)
I think this should cause buttons to be on top of each other with small amount of padding while not being stretched widthwise and while appearing in the center of the screen.

Categories