I'm sure, this is something like a super stupid standard problem, but I spent hours searching and trying to get this fixed, but it just won't work... I just can't find my mistake here...
I'm trying to build a simple program that prints something on a JComponent. The paintComponent()-Method refers to some variables and I want the JComponent ONLY to repaint, if i say so! But it always repaints whenever i change the variables...
Heres the code of my 2 classes:
import java.awt.Dimension;
import javax.swing.*;
public class SimplePaint extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private PaintingCanvas pc;
public SimplePaint() {
super("SimplePaint");
this.pc = new PaintingCanvas();
this.pc.setPreferredSize(new Dimension(800, 600));
this.add(pc);
this.setResizable(false);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setVisible(true);
this.setLocationRelativeTo(null);
}
public static void main(String[] args) {
SimplePaint sp = new SimplePaint();
sp.pc.setxStart(50);
sp.pc.setyStart(60);
sp.pc.setxEnd(140);
sp.pc.setyEnd(300);
}
}
and
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.*;
public class PaintingCanvas extends JComponent {
/**
*
*/
private static final long serialVersionUID = 1L;
private int xStart, yStart;
private int xEnd, yEnd;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.fillRect(xStart, yStart, xEnd, yEnd);
}
/**
* #param xStart the xStart to set
*/
public void setxStart(int xStart) {
this.xStart = xStart;
}
/**
* #param yStart the yStart to set
*/
public void setyStart(int yStart) {
this.yStart = yStart;
}
/**
* #param xEnd the xEnd to set
*/
public void setxEnd(int xEnd) {
this.xEnd = xEnd;
}
/**
* #param yEnd the yEnd to set
*/
public void setyEnd(int yEnd) {
this.yEnd = yEnd;
}
}
What it displays: The Canvas with a rectangle (50, 60, 140, 300)...
What is should display: The blank canvas, and if i then put sp.pc.repaint() or something like that in the main method, it should repaint and therefore show the rectangle...
You cannot make any assumption on when and how many times paintComponent will be called. When making the frame visible, it wille be invoked. If you maximize your frame also, etc... There are many situations when paintComponent will be invoked.
The solution is pretty easy:
Add a flag (boolean drawRectangle = false;) on your PaintingCanvas class
In paintComponent check the value of the flag and draw (or not) the rectangle accordingly
When you want the rectangle to appear, toggle the value of the flag
Related
I am currently making a tile based game. Everything so far is working fine. However, I want the player to be able to add objects, like stone or wood to the screen when he/she presses the mouse button. I attempted this myself but it is not working. Here is what I have done, but is not working:
This is my KeyInput class, where all the keyboard and mouse events take place.
public static ArrayList<StoneTile> sTile = new ArrayList<StoneTile>();
public KeyInput(Handler handler) {
this.handler = handler;
}
public void tick(LinkedList<Square> object) {}
public void mousePressed(MouseEvent e){
int mx = e.getX();
int my = e.getY();
System.out.println("Pressed (X,Y): " + mx + " " + my);
sTile.add(new StoneTile(1,mx,my));
if(sTile.add(new StoneTile(1,mx,my))){
System.out.println("ADDED");
}
}
public void mouseReleased(MouseEvent e){
System.out.println("Released");
}
Here is my StoneTile class, this is what I want to add to screen:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.LinkedList;
public class StoneTile extends Tile {
Textures tex;
public StoneTile(int id,int x,int y) {
super(Textures.stoneArray[0], id);
Tile.x = x;
Tile.y = y;
}
public static void main(String[] args) {
}
public Rectangle getBounds(){
return new Rectangle(x,y,Tile.TILEWIDTH,Tile.TILEHEIGHT);
}
}
The Textures.stoneArray[0] is simply the image that I want to add to the screen.
The Tile.(instance variable, like x, y, TILEWIDTH, and TILEHEIGHT) is simply a Tile class that contains all the render methods for the tiles (grass, stone, etc). If anything is unclear I will clarify or if you need any code provided, then I will add it in.
Note - The ArrayList was just an idea that I had in mind, if there are more efficient ways of doing this or any better ideas, I am open to all of them.
Here is where I set the MouseListener. I set it in an init() method and then called in a run() method (last line):
private void init() {
BufferedImageLoader loader = new BufferedImageLoader();
level = loader.loadImage("level.png");
world = new worldLoader("res/worlds/world1.txt");
handler = new Handler();
WIDTH = getWidth();
HEIGHT = getHeight();
cam = new Camera(handler, Game.WIDTH / 2, Game.HEIGHT / 2);
setWIDTH(getWidth());
setHEIGHT(getHeight());
tex = new Textures();
//backGround = loader.loadImage("/background.jpg");
handler.addObject(new Coin(100, 100, handler, ObjectId.Coin));
handler.addObject(new newStoneTile(20,20,ObjectId.newStoneTile));
handler.addObject(new player_Square(100,100, handler, ObjectId.player_Square));
//handler.addObject(new OneUp(300, 150, handler, ObjectId.OneUp));
this.addKeyListener(new KeyInput(handler));
this.addMouseListener(new KeyInput(handler));
}
jcomponent, is this what you meant?
public class Window {
private static final long serialVersionUID = -6482107329548182911L;
static final int DimensionX = 600;
static final int DimensionY = 600;
public Window(int w, int h, String title, Game game) {
game.setPreferredSize(new Dimension(w, h));
game.setMaximumSize(new Dimension(w, h));
game.setMinimumSize(new Dimension(w, h));
JFrame frame = new JFrame();
frame.add(game);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
}
Perhaps the best way to try and answer this question is to give a small example.
Essentially what needs to happen is the following (assuming my understanding of the problem is correct):
User clicks on the JComponent/JPanel to determine where to place a Tile. This will cause a MouseEvent that needs to be listened for and handled.
The JComponent/JPanel needs a MouseListener implementation which will create a new Tile object and add it to the List of the Tile objects. Once this is complete the JComponent/JPanel needs to know to repaint(). You do not override repaint() but rather paintComponent(Graphics g), which will be called by repaint() (eventually).
The paintComponent(Graphics g) method will iterate over the List of Tile objects, drawing them to the JComponent/JPanel using the Graphics context for the component.
To illustrate this I have simplified your problem. Note this isn't the best way to solve the problem since the Model (game logic) and the GUI should be separated, ideally using Model View Controller / Observer pattern.
First and most importantly is the GamePanel class, which extends JPanel. It's sole role in this example is to display the game graphically and handle mouse clicks. i.e. handling the list of tasks noted above.
GamePanel
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
public class GamePanel extends JPanel {
private List<Tile> tiles; // Stores the Tile objects to be displayed
/**
* Sole constructor for GamePanel.
*
* #param width the width of the game panel
* #param height the height of the game panel
*/
public GamePanel(int width, int height) {
tiles = new ArrayList<>();
setPreferredSize(new Dimension(width, height));
// Implement mouse events for when the JPanel is 'clicked', only using the
// mouse released operation in this case.
addMouseListener(new MouseListener() {
#Override
public void mouseReleased(MouseEvent e) {
// On mouse release, add a StoneTile (in this case) to the tiles List
tiles.add(new StoneTile(e.getX(), e.getY()));
// Repaint the JPanel, calling paint, paintComponent, etc.
repaint();
}
#Override
public void mouseClicked(MouseEvent e) {
// Do nothing
}
#Override
public void mousePressed(MouseEvent e) {
// Do nothing
}
#Override
public void mouseEntered(MouseEvent e) {
// Do nothing
}
#Override
public void mouseExited(MouseEvent e) {
// Do nothing
}
});
}
/**
* Draws the Tiles to the Game Panel.
*
* #param g the Graphics context in which to paint
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // Make sure you do this
// For this example, using black as the color to draw
g.setColor(Color.BLACK);
// Iterate over the tile list and draw them to the JPanel
for (Tile tile : tiles) {
Rectangle tileRect = tile.getBounds();
g.fillRect(tileRect.x, tileRect.y, tileRect.width, tileRect.height);
}
}
}
Second is the GameFrame, which extends JFrame. This is just a basic JFrame which adds a GamePanel object. I've also included the main method which will ensure the GUI is initialized on the Event Dispatch Thread.
GameFrame
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GameFrame extends JFrame {
private static final String TITLE = "Tile Game"; // Game Frame Window Title
private final JPanel gamePanel;
/**
* Sole constructor for GameFrame.
*
* #param width the width of the game in pixels
* #param height the height of the game in pixels
*/
public GameFrame(int width, int height) {
gamePanel = new GamePanel(width, height);
}
/**
* Performs final configuration and shows the GameFrame.
*/
public void createAndShow() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle(TITLE);
add(gamePanel);
pack();
setVisible(true);
}
/**
* Entry point for the program.
*
* #param args not used
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
GameFrame gameFrame = new GameFrame(640, 480);
gameFrame.createAndShow();
}
});
}
}
Finally, the other classes used in the example for completeness, Tile and StoneTile. Personally I don't see much benefit from using Rectangle inside the model, but each to their own and I wanted to keep the example somewhat similar to your currently implementation.
Tile
import java.awt.Rectangle;
public abstract class Tile {
private int x, y, width, height;
public Tile(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
public Rectangle getBounds() {
return new Rectangle(x, y, width, height);
}
}
StoneTile
public class StoneTile extends Tile {
public StoneTile(int x, int y) {
super(x, y, 100, 100);
}
}
One final comment. I notice that your sTile ArrayList is static, this should probably not be the case as it belongs to the class rather than a particular instance of the class.
Found this sample code which should produce a drawn line after clicking, but does not show anything or works. Assume all import statements are correct, code gives no errors and I have no idea why it would not work. The line color is red while the background is white so it should show clearly if it works. The mouse listener seems to be correct as well. Any reason why this code will not work?
public class PathPanel extends JPanel {
/**
* The panel width.
*/
public static final int WIDTH = 400;
/**
* The panel height.
*/
public static final int HEIGHT = 400;
/**
* The background color of the panel.
*/
public static final Color BACKGROUND_COLOR = Color.WHITE;
/**
* The color to paint with.
*/
public static final Color FOREGROUND_COLOR = Color.RED;
/**
* The line width.
*/
public static final int LINE_WIDTH = 8;
// Instance Fields
/**
*
*/
private static final long serialVersionUID = -3644129903653409515L;
/**
* The path being created.
*/
private final Path2D myPath;
// OR you could use Path2D.Double instead of GeneralPath
// Constructor
/**
* Constructs a new general path panel.
*/
public PathPanel() {
super();
myPath = new GeneralPath();
myPath.setWindingRule(GeneralPath.WIND_EVEN_ODD);
//myPath = new Path2D.Double();
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setBackground(BACKGROUND_COLOR);
addMouseListener(new MyMouseListener());
}
/**
* Paints the current path.
*
* #param theGraphics The graphics context to use for painting.
*/
#Override
public void paintComponent(final Graphics theGraphics) {
super.paintComponent(theGraphics);
final Graphics2D g2d = (Graphics2D) theGraphics;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setPaint(FOREGROUND_COLOR);
g2d.setStroke(new BasicStroke(LINE_WIDTH));
g2d.draw(myPath);
}
// Main Method
/**
* Creates and displays a GeneralPathPanel.
*
* #param theArgs Command line arguments (ignored).
*/
public static void main(final String... theArgs) {
final PathPanel panel = new PathPanel();
final JFrame frame = new JFrame("GeneralPathPanel Demo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
// Inner Class
/**
* Listens for mouse clicks, to draw on our panel.
*/
private class MyMouseListener extends MouseAdapter {
/**
* Handles a click event.
*
* #param theEvent The event.
*/
#Override
public void mouseClicked(final MouseEvent theEvent) {
if (myPath.getCurrentPoint() == null) {
myPath.moveTo(theEvent.getX(), theEvent.getY());
} else if (theEvent.getClickCount() == 2) {
myPath.closePath();
} else {
myPath.lineTo(theEvent.getX(), theEvent.getY());
}
repaint();
}
}
}
The Sample Code you posted works fine for me. Have you tried to add a System.out.println() in the mouseClicked(final MouseEvent theEvent) Method to check if it is actually called? If it is not called, you could try to change it to mouseReleased.
The imports I used:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
I'm trying to paint a dynamic graph that has a few thousand points. I'm using SwingWorker class that gets the Graphics object as an argument. I initialize the graphics object in the constructor of the SwingWorker class and then call the main graphing function doGraph() in the done() method i.e, after all the calculations are done. I'm having issues with painting, not sure what is going on. The code works if I call doGraph() from the constructor of the SwingWorker class but not when I place it in done().
Any help is greatly appreciated. I have simplified the code for ease of understanding. I`m just trying to paint a rectangle in the doGraph() for simplicity.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.RenderingHints.Key;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
#SuppressWarnings("serial")
public class UIGraph extends JPanel {
private double minX, maxX;
private double minY, maxY;
private SWPaint swPaint; //Swing Worker object
private Graphics2D g2D;
public Key key = RenderingHints.KEY_ANTIALIASING;
public Object obj = RenderingHints.VALUE_ANTIALIAS_ON;
private int labelPadding = 25;
private int padding = 25;
private int padConst = (2 * padding) - labelPadding;
private double xScale;
private double yScale;
/**
* Crate Panel
*/
private void createUI() {
setBackground(new Color(245, 255, 250));
setLayout(new BorderLayout(0, 0));
}
/**
* Constructor
*
*/
public UIGraph() {
createUI();
getMinMax();
}
/**
* Paint Component. Do all the calculations and graphing
*/
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (swPaint != null) {
if (!swPaint.isDone()) { // The swing worker is busy with tasks. Set Visibility to false and return.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
setVisible(false);
}
});
return;
}
}
swPaint = new SWPaint(g); //Create a swing worker class, pass graphics object as argument
swPaint.execute();
}
}
/**
* Get the Min and Max values of Data
*/
private void getMinMax() {
//obtain min and max values
}
/**
* Main method for graphing
*
* #param g2D
*/
private void doGraph() {
xScale = (double) (getWidth() - padConst) / (maxX - minX);
yScale = (double) (getHeight() - padConst) / (maxY - minY);
g2D.setColor(Color.WHITE);
g2D.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding
- labelPadding);
g2D.setColor(Color.BLACK);
}
/**
* Swing Worker to handle Paint
*
*/
public class SWPaint extends SwingWorker<Void, Void> {
/**
* Constructor
*
* #param g
*/
public SWPaint(Graphics g) {
g2D = (Graphics2D) g;
g2D.setRenderingHint(key, obj);
//doGraph() //This works
}
/**
* Do graphing calculations here
*/
#Override
protected Void doInBackground() throws Exception {
// do all calculations here
return null;
}
/*
* The SW is done. Paint the graph. Set Visibility to true
*/
protected void done() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
doGraph(); //This doesn`t work here.
setVisible(true);
}
});
}
}
}
I'm trying to develope an menue with transparent buttons for a game.
My problem was, that the buttons piled up with every time I hovered them.
So I added an MouseListener which executes myJFrame.repaint(); every time I hover them.
The problem is, the repainting so slow, that disturbs the user.
I hope that someone knows a better way.
I'm sorry if there are mistakes, my english is not the best.
public class Hauptmenue extends javax.swing.JFrame implements ActionListener {
private static final long serialVersionUID = 8132389688291883346L;
//Toolkit für das Freie Skalieren des Hauptmenüs
private Toolkit t;
//variablen für das Fenster
private int x, y, width, height;
//variablen für die Köpfe
private int kx, kwidth, kheight;
//Variablen für die Knöpfe im Hauptmenü:
private JButton2 single;
private JButton2 multi;
private JButton2 einstellungen;
private JButton2 info;
private JButton2 ende;
//Hintergrund des Hauptmenüs
Image background;
public Hauptmenue(){
//Bildschirmgröße messen:
t = Toolkit.getDefaultToolkit();
Dimension d = t.getScreenSize();
width = (int)(d.getWidth() * 0.23);
height = (int)(d.getHeight() * 0.5);
x = (int)((d.getWidth() - width) * 0.5);
y = (int)((d.getHeight() - height) * 0.5);
setTitle("Hauptmenü");
setBounds(x, y, width, height);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);
setBackground(null);
//Hintergrnd Bild
//setFocusable(true);
File pfad = new File("res/Images/Hintergrund_1.png");
ImageIcon u = new ImageIcon(pfad.getPath());
background = u.getImage();
//background = background.getScaledInstance(width, height, Image.SCALE_DEFAULT);
//sorgt dafür, dass das Menü keinen Rahmen hat
setUndecorated(true);
//knopfpositionen und Größen berechnen
kwidth = (int)(width * 0.8);
kheight = (int)(height * 0.125);
kx = (int)(width - kwidth) / 2;
//die Knöpfe:
single = new JButton2("Singelplayer");
single.setBounds(kx, (kheight * 1), kwidth, kheight);
single.addActionListener(this);
single.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
public void mouseExited(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
});
add(single);
multi = new JButton2("Multiplayer");
multi.setBounds(kx, (int)(kheight * 2.25), kwidth, kheight);
multi.addActionListener(this);
multi.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
public void mouseExited(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
});
add(multi);
einstellungen = new JButton2("Einstellungen");
einstellungen.setBounds(kx, (int)(kheight * 3.5), kwidth, kheight);
einstellungen.addActionListener(this);
einstellungen.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint(1);
}
public void mouseExited(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint(1);
}
});
add(einstellungen);
info = new JButton2("Info");
info.setBounds(kx, (int)(kheight * 4.75), kwidth, kheight);
info.addActionListener(this);
info.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
public void mouseExited(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
});
add(info);
ende = new JButton2("Beenden");
ende.setBounds(kx, (kheight * 6), kwidth, kheight);
ende.addActionListener(this);
ende.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
public void mouseExited(java.awt.event.MouseEvent evt) {
JFrame frme = (JFrame) info.getParent().getParent().getParent().getParent();
frme.repaint();
}
});
add(ende);
setVisible(true);
}
//der Hintergrund:
//zum Zeichnen des Hintergrundes:
public void paint(Graphics g){
super.paint(g);
Graphics2D f2 = (Graphics2D)g;
f2.drawImage(background, 0, 0, width, height, null);
//Knöpfe in den Vordergrund holen
this.single.paint(this.single.getGraphics());
this.multi.paint(this.multi.getGraphics());
this.einstellungen.paint(this.einstellungen.getGraphics());
this.info.paint(this.info.getGraphics());
this.ende.paint(this.ende.getGraphics());
g.dispose();
}
//Funktionen hinter den Knöpfen:
private void Singleplayer(){
}
private void Multiplayer(){
}
private void Einstellungen(){
new Einstellungsfenster();
}
private void Info(){
new Infofenster();
}
private void Beenden(){
System.exit(0);
}
//Reaktionen auf die Knopfdrücke:
public void actionPerformed (ActionEvent e){
if(e.getSource() == single){
Singleplayer();
}
if(e.getSource() == multi){
Multiplayer();
}
if(e.getSource() == einstellungen){
Einstellungen();
}
if(e.getSource() == info){
Info();
}
if(e.getSource() == ende){
Beenden();
}
}
//Programmstart
public static void main(String[]args){
//das Hauptmenü wird erzeugt
new Hauptmenue();
}}
Also I made a few changes for the JButton:
public class JButton2 extends JButton {
private static final long serialVersionUID = 5193885870007603559L;
public JButton2(){
}
public JButton2(String text){
this.setText(text);
//this.setOpaque(false);
//this.setContentAreaFilled(false);
//this.setBackground(null);
}
#Override
public void paint(Graphics g){
//super.paint(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) 0.8));
super.paint(g2);
g.dispose();
g2.dispose();
}
//#Override
public void repaint(){
//hier passiert nichts
}}
If you are getting artifacts from translucency/transparency, try to call setOpaque(false) on your buttons. It might help you getting the expected result without resorting to call the repaint on the parent component. Swing, behind the courtains, will probably repaint the first opaque parent, but only the region needed.
I'm sorry to say that, but your code fails in so many ways. Your attempts to do repainting is just a workaround for some other issues. If you knew the right hints, the code gets rather easy. But instead explaining all the minor details that went wrong, I just put the entire fixed code here, which contains comments about important things.
Main.java holds the main class. It just opens and configures the main window. (The menu itself is in another class called MainMenu).
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
/**
* Main class
*/
public class Main {
/**
* Create the GUI and show it. For thread safety, this method should be
* invoked from the event-dispatching thread.
*/
private static void createAndShowGUI() {
// Create and set up the window.
JFrame frame = new JFrame("Game");
frame.setUndecorated(true);
// Center on screen
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int width = (int) (d.getWidth() * 0.23);
int height = (int) (d.getHeight() * 0.5);
int x = (int) ((d.getWidth() - width) * 0.5);
int y = (int) ((d.getHeight() - height) * 0.5);
frame.setBounds(x, y, width, height);
// Set the menu bar and add the label to the content pane.
MainMenu menu = new MainMenu();
// We only add components to the content pane, NEVER directly via
// add(...)!!!
frame.getContentPane().add(menu, BorderLayout.CENTER);
// Display the window.
frame.setVisible(true);
}
public static void main(String[] args) {
// Schedule a job for the event-dispatching thread:
// creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
MainMenu.java is the largest file.
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
/**
* Main menu is a JPanel.
*/
public class MainMenu extends JPanel {
private JButton single;
private JButton multi;
private JButton settings;
private JButton info;
private JButton exit;
private BufferedImage background;
public MainMenu() {
super();
// We use a layout manager to do all layouting for us
// So we can lean back and do not have to do odd maths
GridLayout layout = new GridLayout(5, 1);
layout.setVgap(20);
setLayout(layout);
// An empty border to ensure distance form the bounds of the panel
setBorder(new EmptyBorder(50, 30, 50, 30));
single = new AlphaButton("Single", 0.8f);
multi = new AlphaButton("Multi", 0.8f);
settings = new AlphaButton("Settings", 0.8f);
info = new AlphaButton("Info", 0.8f);
exit = new AlphaButton("Exit", 0.8f);
exit.addActionListener(evt -> System.exit(0));
// Add the buttons to this panel.
// It will take care of the rest (repainting etc.)
add(single); add(multi); add(settings); add(info); add(exit);
try {
// load background image
background = ImageIO.read(
getClass().getResource("res/Images/Hintergrund_1.png"));
} catch (IOException e) {
// TODO exception handling
e.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Here, we just draw the background. Nothing else!
// Use this as image observer so repainting occurs if the image changes
// (which doesn't happen here, but we want to do it right).
g.drawImage(background, 0, 0, getWidth(), getHeight(), this);
// DO NOT DISPOSE g - you did not create it!
}
}
Last, but not least, the code for the translucent button:
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JButton;
/**
* Semi-transparent {#link JButton}.
*/
public class AlphaButton extends JButton {
private float alpha;
public AlphaButton(String text, float alpha) {
super(text);
this.alpha = alpha;
// This is important! It tells the painting system that the underlying
// pixels may shine through, so it must always paint the background
// before this component can be painted.
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
Composite old = g2.getComposite(); // remember old composite
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
super.paintComponent(g2);
g2.setComposite(old); // restore old composite
// DO NOT DISPOSE g (or g2) - you did not create it!
}
}
Calling any of the repaint() methods just queues the Component to be repainted at some later time. If you call repaint() multiple times before the Component is actually repainted by the RepaintManager they are simply combined into one repaint operation.
You should try using one of the paintImmediately() methods as these perform the repaint immediately (bet you couldn't guess that from the name).
For additional information read:
Painting in AWT and Swing
Sure,
repaint(x ,y ,width, height);
Would repaint just these boundaries, speeding them up, and omitting unnecessary work.
This has been driving me absolutely crazy. I can't get this rectangle to appear. I'm new to programming and I'm trying to recreate pong in 2D as a learning experience. Here's the code:
package ping;
import javax.swing.*;
public class Pong extends JFrame implements MouseListener {
/**
*
*/
private static final long serialVersionUID = 1L;
/**
* #param args
*/
public Pong(String title) {
this.setTitle(title);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().setBackground(Color.RED);
this.getContentPane().setLayout(null);
this.setSize(500, 500);
Paddles a = new Paddles(), b = new Paddles();
a.setBounds(225, 25, 50, 10); b.setBounds(225, 475, 50, 10);
this.getContentPane().add(a); this.getContentPane().add(b);
a.setVisible(true); b.setVisible(true);
this.getContentPane().addMouseListener(this);
this.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Pong game = new Pong("Java Pong");}
And then the Paddles class:
import java.awt.Graphics;
import java.awt.Color;
import javax.swing.JComponent;
public class Paddles extends JComponent {
/**
*
*/
private static final long serialVersionUID = 1L;
public Paddles() {}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawRect(0,0,0,0);
g.fillRect(0,0,0,0);
System.out.println("paintworks");
System.out.println(Integer.toString(this.getY()));
}
}
Thanks in advance!
You have a zero size rectangle
this is the updated method.
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK);
g.drawRect(this.x,this.y,10,10); // look at the api this command is redundant
g.fillRect(this.x,this.y,10,10); // as fill rect will overdraw it anyway.
System.out.println("paintworks");
System.out.println(Integer.toString(this.getY()));
}
g.drawRect(0,0,0,0);
g.fillRect(0,0,0,0);
Both of these lines indicate to draw something of no size. The final two parameters should indicate the width and height.
See the javadoc for more detail.