Is there a way to repaint graphics after using super.paint(g)? - java

so I have a question, lets say I create a rectangle in Java using the paint method, after a 100 ms delay I do super.paint(g), this clears the rectangle previously shown, is there a way to make it re appear?
Thanks!
An example of what I'm talking about is down below, what this program is meant to do is whenever I hold down mouse button 1, it creates a rectangle that goes down and than disapears after mouse button 1 is off. The problem is whenever I hold down mouse button 1 again, the rectangle doesn't appear.
First class:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.Timer;
public class RecoilHelper extends JFrame {
static Timer rs;
static int recoil = 540;
static boolean clearRectangle = false;
/**
* Launch the application.
*/
public static void main(String[] args) {
JNativehookRecoilHelp.main(null);
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
RecoilHelper frame = new RecoilHelper();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public RecoilHelper() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
setBounds(0, 0, 1920, 1080);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setUndecorated(true);
setBackground(new Color(1.0f,1.0f,1.0f,0.0f));
setAlwaysOnTop(true);
rs = new Timer(10,(ActionEvent e)->{
repaint();
recoil += 12;
if (recoil>600) {
rs.stop();
}
});
}
public void paint(Graphics g) {
Rectangle r = new Rectangle(960, recoil, 4, 4);
System.out.println(recoil);
super.paintComponents(g);
g.fillRect(
(int)r.getX(),
(int)r.getY(),
(int)r.getWidth(),
(int)r.getHeight()
);
if (clearRectangle) {
super.paint(g);
}
}
}
Second class(tracks mouse button 1 events using JNativehook):
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseInputListener;
public class JNativehookRecoilHelp implements NativeMouseInputListener {
#Override
public void nativeMouseClicked(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void nativeMousePressed(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println("Pressed");
RecoilHelper.recoil = 540;
RecoilHelper.rs.start();
}
#Override
public void nativeMouseReleased(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println("Released");
RecoilHelper.clearRectangle=true;
}
#Override
public void nativeMouseDragged(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void nativeMouseMoved(NativeMouseEvent arg0) {
// TODO Auto-generated method stub
}
public static void main(String[] args) {
GlobalScreen.addNativeMouseListener(new JNativehookRecoilHelp());
LogManager.getLogManager().reset();
// Get the logger for "org.jnativehook" and set the level to off.
Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
logger.setLevel(Level.OFF);
try {
GlobalScreen.registerNativeHook();
}
catch (NativeHookException ex) {
System.exit(1);
}
}
}

Currently you are attempting to override the paint method of the JFrame, this presents two issues, this first is that a JFrame is a heavyweight component (it has a title bar and a number of associated things that you need to consider) so you may have endless issues, the second issue is that you need to override the paintComponent method of the component that you wish to perform custom painting on.
The solution here is to instead place a JPanel inside the JFrame, and override the paintComponent method of the JPanel.
Below is a working example that creates a new rectangle and adds it to the frame every half second but also keeps the existing rectangles by adding them to a list and drawing each one in the list every time it is repainted.
The main class is simple, and simply adds our CustomJpanel to the JFrame:
public class PaintExample extends JFrame
{
private CustomJPanel customJpanel;
public PaintExample()
{
//Create and add the custom panel to the JFrame
setPreferredSize(new Dimension(400, 300));
customJpanel = new CustomJPanel();
getContentPane().add(customJpanel, java.awt.BorderLayout.CENTER);
pack();
}
public static void main(String args[])
{
//Show the JFrame:
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new PaintExample().setVisible(true);
}
});
}
}
And the custom panel class that does our painting:
public class CustomJPanel extends JPanel
{
int x = 0;
int y = 0;
boolean clearRectangle = true;
//This is a list that we use to keep track of all the rectangles to draw/update
ArrayList<Rectangle> rectangleList = new ArrayList<>();
//Start a timer when the panel is created that will update the rectangle location every half second (500ms).
//In your case you would use your recoil timer instead
public CustomJPanel(){
//Create event action
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
add a new rectangle in a different location
x+= 5;
y+= 5;
rectangleList.add(new Rectangle(x,y,10,10));
//Update the panel
repaint();
}
};
//Create and start a repeating event
Timer timer = new Timer(500, taskPerformer);
timer.setRepeats(true);
timer.start();
}
//Here is where it all happens:
#Override
protected void paintComponent(Graphics g)
{
//Call super first to perform normal component painting
super.paintComponent(g);
//Now do your custom painting
if (clearRectangle)
{
//Draw each rectangle in the list
for (Iterator<Rectangle> iterator = rectangleList.iterator(); iterator.hasNext();)
{
Rectangle r = iterator.next();
g.drawRect(r.x, r.y, r.width, r.height);
}
}
}
}
And the window looks like this after a couple so seconds, note how it keeps all previous rectangles:

Related

Using repaint() to draw on JPanel which is added to JFrame

Attempting to draw my rectangle across the screen horizontally in realtime. When I run this I get nothing but the JFrame. I'm not sure what I am missing aside from maybe some type of threading freeze to redraw the shape maybe?
public class ScreenTest extends JFrame {
int rectY = 50;
public ScreenTest()
{
setSize(300,200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private class DrawPanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(80, rectY, 50, 50);
}
}
public void Draw()
{
DrawPanel test = new DrawPanel();
add(test);
while (rectY < 200)
{
rectY = rectY + 10;
test.repaint();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
ScreenTest myWindow = new ScreenTest();
myWindow.Draw();
}
}
Swing is single threaded and not thread safe.
What this means is, you should not perform any kind of long running or blocking operations within the "Event Dispatching Thread", as this will stop the UI from been painted or responding to new events.
It also means you should not update the UI, or any state the UI relies on, from outside the context of the Event Dispatching Thread.
Your code "is" working, but because the while-loop can run so fast, it's completing before the window is realised on the screen (visible and updatable). Swing is also optimised, so all the repaint calls are likely been consolidated into a single repaint pass.
A better solution might to start with Swing `Timer, which acts as a pseudo repeating loop, but which is called on within the context of the Event Dispatching Thread.
Start by taking a look at Concurrency in Swing and How to Use Swing Timers for more details.
Runnable Example
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class ScreenTest extends JFrame {
public ScreenTest() {
setSize(300, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private class DrawPanel extends JPanel {
int rectY = 50;
private Timer timer;
// This is just convince
#Override
public void addNotify() {
super.addNotify();
timer = new Timer(25, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
rectY += 1;
repaint();
}
});
// Otherwise it disappears to fast
timer.setInitialDelay(1000);
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
timer.stop();
timer = null;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(80, rectY, 50, 50);
}
}
public void Draw() {
DrawPanel test = new DrawPanel();
add(test);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ScreenTest myWindow = new ScreenTest();
myWindow.Draw();
}
});
}
}
it is working but is so fast that you can't see it, you need to make the loop which changes the Y coordinate slower with a delay. to solve it i used Thread.sleep() in the while loop:
package paquete;
import javax.swing.*;
import java.awt.*;
public class ScreenTest extends JFrame {
int rectY = 50;
public ScreenTest()
{
setSize(300,200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
private class DrawPanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(80, rectY, 50, 50);
}
}
public void Draw() throws InterruptedException {
DrawPanel test = new DrawPanel();
add(test);
while (rectY < 200)
{
rectY = rectY + 10;
Thread.sleep(100);
test.repaint();
}
}
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ScreenTest myWindow = new ScreenTest();
myWindow.Draw();
}
}
i hope this helps you, you can change the duration changing the number inside the argument of Thread.sleep()

MouseListener - MouseClicked

After 2 hours of searching I really can't find out why my code isn't working so I wonder if you could help.
All I want to see is "Clicked" when I press the button. My class MouseInput implements MouseListener and in the method mouseClicked all I got is system.out...("clicked");
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
public class App implements Runnable {
private Display display;
private BufferStrategy bs;
private Graphics g;
private int cubeSide = 150;
private String title;
private int height,width;
private boolean running = false;
private Thread thread;
private MouseInput mouseInput;
public App(String title,int width,int height){
this.height=height;
this.width=width;
this.title=title;
display = new Display(title, width, height);
}
void setBufferStrategy(){
if(display.getCanvas().getBufferStrategy()==null){
display.getCanvas().createBufferStrategy(3);
}
bs = display.getCanvas().getBufferStrategy();
}
void init(){
setBufferStrategy();
mouseInput = new MouseInput();
display.getFrame().addMouseListener(mouseInput);
}
public synchronized void start(){
if(running==true)
return;
running=true;
thread = new Thread(this);
thread.start();
}
void render(){
}
#Override
public void run() {
init();
while(running){
render();
}
}
public synchronized void stop(){
}
}
MouseInput Code:
`import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class MouseInput implements MouseListener {
#Override
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
System.out.println("Click");
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}`
And for the Display class:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
public class Display {
private JFrame frame;
private Canvas canvas;
private String title;
private int width,height;
public Display(String title,int width,int height){
this.width = width;
this.height=height;
this.title=title;
CreateDisplay();
}
public void CreateDisplay(){
frame = new JFrame(title);
canvas = new Canvas();
frame.setSize(width,height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setFocusable(false);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
canvas.setPreferredSize(new Dimension(width,height));
canvas.setMaximumSize(new Dimension(width,height));
canvas.setMinimumSize(new Dimension(width,height));
canvas.setBackground(Color.WHITE);
frame.add(canvas);
frame.pack();
}
public Canvas getCanvas(){
return canvas;
}
public JFrame getFrame(){
return frame;
}
}
I think the problem can be in display.getFrame().addMouseListener(mouseInput): I suppose display.getFrame() returns a an instance of a class extending java.awt.Component; according to API reference, addMouseListener
Adds the specified mouse listener to receive mouse events from this component.
I think an event on your button is not an event from the component you registered the listener on: can you try to register the listener on the canvas instance instead of on frame instance? May be the event originated from canvas, not from frame...
First, you can use an inline mouse adapter rather than extending mouse listener and needing a separate file for the mouse code.
Second, if you want to observe the click on your button, add the listener to your button.
yourJButton.addMouseListener( new MouseAdapter()
{
#Override
public void mouseClicked( MouseEvent e )
{
{
//do stuff
}
}
});

Using a listener class to handle all listening

I completed my Java Homework, but it was all mushed into one main class (with a couple of private classes). I'm trying to make my code more elegant by having separate classes to handle things. I'm having trouble having the listener interact with the existing panels.
The main parts I'm looking at are in the Listener.java. The mouse click and action listener. I am able to get the name of the button that was clicked to trigger the listener, which is helpful, but I can't get it to interact with the "DrawBoard" panel that was added to the Panel panel.
I'm wondering what the best way to work this interaction is:
Window.java:
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Window extends JFrame {
/**
*
*/
private static final long serialVersionUID = -8255319694373975038L;
public static void main(String[] args){
new Window();
}
public Window(){
// Adds the custom panel
Panel Panel = new Panel();
this.add(Panel);
// Basic Window Features
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800,800);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
Panel.java:
public class Panel extends JPanel{
public Panel(){
Button testButton = new Button("Test");
DrawBoard drawBoard = new DrawBoard();
Listener listener = new Listener();
this.add(testButton);
this.add(drawBoard);
}
}
Button.java
import java.awt.Dimension;
import javax.swing.JButton;
public class Button extends JButton{
public Button(String name) {
this.setText(name);
this.setName((String) name);
buttonSettings();
}
private void buttonSettings(){
Listener listener = new Listener();
this.addActionListener(listener);
int width = 200;
int height = 50;
Dimension dim = new Dimension(width,height);
this.setPreferredSize(dim);
}
}
DrawBoard.java
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JPanel;
public class DrawBoard extends JPanel{
public DrawBoard(){
DrawBoardSettings();
}
private void DrawBoardSettings(){
int width = 600;
int height = 600;
Dimension dim = new Dimension(width,height);
this.setPreferredSize(dim);
this.setBackground(Color.WHITE);
}
}
Listener.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
public class Listener implements ActionListener, MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
**// Draw a dot at the mouse location of the DrawBoard JPanel that was added by the Panel JPanel that was added by the Window JFrame**
}
#Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void actionPerformed(ActionEvent e) {
String name = ((JComponent) e.getSource()).getName();
**// Draw a rectangle on the DrawBoard JPanel that was added by the Panel JPanel that was added by the Window JFrame**
}
}
Some thoughts here:
Currently you have several instances of that Listener class. That is probably not what you want.
Related to that: your code indicates that your Listener class should draw on some panel. If so ... that Listener somehow needs access to that panel.
One way to get there: you change your constructor to
private final Panel drawingBoard;
public Listener(Panel drawingBoard) {
this.drawingBoard = drawingBoard;
)
and then your actionPerformed() method has something to draw on.
The core thing to understand: you have to create a clear model (in your mind) about which components you have; and how they depend on each other. Because that drives your implementation; for example regarding the order in which you have to create your different objects. Given my example, you would need to first create a Panel object; so that you can then create a Listener for that Panel.
Here is the code for my completed project. I think I made it much cleaner and only called "listener" and "drawBoard" once, which cleared up my problems:
Window.java:
import javax.swing.JFrame;
public class Window extends JFrame {
/**
*
*/
private static final long serialVersionUID = -8255319694373975038L;
// initiates the program
public static void main(String[] args){
new Window();
}
public Window(){
// Adds the custom panel
Panel Panel = new Panel();
this.add(Panel);
// Basic Window Features
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(800,800);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
Panel.java:
import java.awt.FlowLayout;
import java.util.ArrayList;
import javax.swing.JPanel;
public class Panel extends JPanel{
/**
*
*/
private static final long serialVersionUID = 5509155261502497671L;
public Panel(){
// This is the area where stuff will be drawn
DrawBoard drawBoard = new DrawBoard();
// This is the only instance of listener. Buttons now call this variable
Listener listener = new Listener(drawBoard);
// Invisible Overlay allows me to get mouse listener coordinates for drawing
JPanel overlay = new JPanel();
//gets rid of the padding on the invisible overlay layer;
FlowLayout layout = (FlowLayout)overlay.getLayout();
layout.setVgap(0);
layout.setHgap(0);
// The mouse listener is added to the overlay layer rather than the panel to ensure that X,Y coords match the drawboard panel underneath
// I could not add the listener to the drawboard panel because the listener requires the drawboard panel to perform.
overlay.addMouseListener(listener);
overlay.addMouseMotionListener(listener);
overlay.add(drawBoard);
// Buttons that will appear on the top of the panel
ArrayList<Button> TopButtons = new ArrayList<Button>();
TopButtons.add(new Button("Blue", listener));
TopButtons.add(new Button("Green", listener));
TopButtons.add(new Button("Red", listener));
TopButtons.add(new Button("Black", listener));
// Buttons that will appear on the bottom of the pannel
ArrayList<Button> BotButtons = new ArrayList<Button>();
BotButtons.add(new Button("Small", listener));
BotButtons.add(new Button("Medium", listener));
BotButtons.add(new Button("Large", listener));
BotButtons.add(new Button("Clear", listener));
// Using for loops to clean up code a bit.
for (int i = 0; i < TopButtons.size(); i++){
this.add(TopButtons.get(i));
}
// add the overlay rather than the drawboard, to ensure that mouse functions work
this.add(overlay);
for (int i = 0; i < BotButtons.size(); i++){
this.add(BotButtons.get(i));
}
}
}
Button.java
import java.awt.Dimension;
import javax.swing.JButton;
public class Button extends JButton{
/**
*
*/
private static final long serialVersionUID = -819700115106662958L;
private final Listener listener;
public Button(String name, Listener listener) {
this.listener = listener;
this.setText(name);
this.setName((String) name);
buttonSettings();
}
private void buttonSettings(){
this.addActionListener(listener);
int width = 150;
int height = 50;
Dimension dim = new Dimension(width,height);
this.setPreferredSize(dim);
}
}
DrawBoard.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import javax.swing.JPanel;
public class DrawBoard extends JPanel{
/**
*
*/
private static final long serialVersionUID = 1368365222404381200L;
// ArrayList will store all points drawn on the canvas
public ArrayList<Point> points = new ArrayList<Point>();
// Constructor initiates the settings for the board
public DrawBoard(){
DrawBoardSettings();
}
// Painting of the points happens here
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// draws a point for every point in the "points" array.
for (int i = 0; i < points.size(); i++){
Point thisPoint = points.get(i);
g.setColor(thisPoint.color);
g.fillOval(thisPoint.x,thisPoint.y,thisPoint.size,thisPoint.size);
}
}
private void DrawBoardSettings(){
// Sets the preferred window size
int width = 700;
int height = 600;
Dimension dim = new Dimension(width,height);
this.setPreferredSize(dim);
// background color and visibility
this.setBackground(Color.WHITE);
this.setVisible(true);
this.setOpaque(true);
}
}
Listener.java:
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JComponent;
public class Listener implements ActionListener, MouseListener, MouseMotionListener {
private final DrawBoard drawBoard;
//sets default color and size
private Color color;
private int size;
public Listener(DrawBoard drawBoard) {
this.drawBoard = drawBoard;
this.color = Color.BLACK;
this.size = 10;
}
// Contains settings for creating a new point
private void drawPoint(MouseEvent e){
Point point = new Point(e.getX(), e.getY(), this.color, this.size);
drawBoard.points.add(point);
drawBoard.repaint();
}
// Contains settings for all of the buttons
private void setButton(String name){
// Colors
if (name == "Blue"){
this.color = Color.BLUE;
}
if (name == "Red"){
this.color = Color.RED;
}
if (name == "Green"){
this.color = Color.GREEN;
}
if (name == "Black"){
this.color = Color.BLACK;
}
// Sizes
if (name == "Large"){
this.size = 15;
}
if (name == "Medium"){
this.size = 10;
}
if (name == "Small"){
this.size = 5;
}
// Clear
if (name == "Clear"){
drawBoard.points.clear();
drawBoard.repaint();
}
}
// Draws a point when the mouse is pressed down
#Override
public void mousePressed(MouseEvent e) {
drawPoint(e);
}
// Draws a point when the mouse is dragged (at every location it is dragged at)
#Override
public void mouseDragged(MouseEvent e) {
drawPoint(e);
}
// Changes the settings of buttons
#Override
public void actionPerformed(ActionEvent e) {
String name = ((JComponent) e.getSource()).getName();
setButton(name);
}
//Unused Listeners
#Override
public void mouseClicked(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
Point.java
import java.awt.Color;
public class Point {
protected int x, y, size;
protected Color color;
public Point(int x, int y, Color color, int size){
this.x = x;
this.y = y;
this.color = color;
this.size = size;
}
}

How to load two extended JPanel class to one JFrame?

I'm going to make a game with Java, my game will have a menu. the menu is having a background, and 2 JLabel objects. I've make them on separate class, which is passed to one JFrame. And my problem is, I've load 2 of them on a single frame, but one of them always hidden by another.
this is the code:
JFrame class
#SuppressWarnings("serial")
public class Sistem extends JFrame{
private final int lebar=954;
private final int tinggi=540;
private Image bg;
File gbr=new File("res/a.jpg");
public Sistem(){
this.setTitle("Unknown man Unkown power");
this.setSize(new Dimension(lebar,tinggi));
this.setFocusable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setContentPane(new Ngrep());
//this.setContentPane(new Menu());
this.setVisible(true);
//loadfont();
//loadbg();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
new Sistem();
}
});
}
}
background class
#SuppressWarnings("serial")
public class Ngrep extends JPanel{
private int l=954;
private int t=540;
private BufferedImage bg;
File gbr=new File("res/a.jpg");
public Ngrep(){
loadbg();
}
private void loadbg() {
// TODO Auto-generated method stub
try {
bg=ImageIO.read(gbr);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawImage(bg, 0, 0, l, t, null);
}
}
menu class
#SuppressWarnings("serial")
public class Menu extends JPanel implements Runnable,KeyListener{
private int l=954;
private int t=540;
JLabel menu1=new JLabel("MULAI BARU");
JLabel menu2=new JLabel("KELUARRR");
private File fo=new File("res/Mawns.ttf");
JLayeredPane p=new JLayeredPane();
public Menu(){
loadfont();
this.add(menu1);
this.add(menu2);
}
public void loadfont(){
try {
FileInputStream fi=new FileInputStream(fo);
Font f=Font.createFont(Font.TRUETYPE_FONT, fi).deriveFont(Font.TRUETYPE_FONT, 30);
GraphicsEnvironment ge=GraphicsEnvironment.getLocalGraphicsEnvironment();
ge.registerFont(f);
menu1.setFont(f);
menu2.setFont(f);
} catch (Exception ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
p.setLayout(new GridLayout(2, 3));
menu1.setBounds(0, 0, getWidth(), getHeight());
menu2.setBounds(0, 0+menu1.getHeight(), getWidth(), getHeight());
p.add(menu1, 2);
p.add(menu2, 2);
}
}
What I want is the menu is in front of background but background still can be seen. and how to arrange the JLabel that I've created to center down of the screen.
How can I achieve the required layout?
public class Ngrep extends JPanel{
Note that since Ngrep is a JPanel you can add components directly to it, making the Menu class redundant.
Something like seen in this SSCCE.
Note that I ended up making so many changes so fast I could not be bothered explicitly documenting most of them. Look over the code carefully, check it against your original code, check the Java Docs, and if there is any change you do not understand, ask me.
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.URL;
import javax.imageio.ImageIO;
#SuppressWarnings("serial")
public class Sistem extends JFrame {
public Sistem() {
this.setTitle("Unknown man Unkown power");
this.setFocusable(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setContentPane(new Ngrep());
this.setResizable(false);
this.pack();
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Sistem();
}
});
}
}
#SuppressWarnings("serial")
class Ngrep extends JPanel {
private int l = 375;
private int t = 150;
private BufferedImage bg;
JLabel menu1 = new JLabel("MULAI BARU");
JLabel menu2 = new JLabel("KELUARRR");
public Ngrep() {
this.add(menu1);
this.add(menu2);
try {
Font f = new Font(Font.MONOSPACED, Font.ITALIC, 30);
menu1.setFont(f);
menu1.setForeground(Color.RED);
menu2.setFont(f);
menu2.setForeground(Color.RED);
URL url = new URL("http://i.stack.imgur.com/OVOg3.jpg");
bg = ImageIO.read(url);
} catch (Exception ex) {
ex.printStackTrace();
}
setLayout(new GridLayout(2, 3));
add(menu1);
add(menu2);
}
public Dimension getPreferredSize() {
return new Dimension(l, t);
}
/*
* For a JComponent, override paintComponent rather than paint
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// a JPanel IS AN ImageObserver
g.drawImage(bg, 0, 0, getWidth(), getHeight(), this);
}
}
Start by using JFrame#add instead of JFrame#setContentPane, unless you intend to add more components to that (content) pane.
By default JFrame uses a BorderLayout for its LayoutManager. You will need to either change it to something you prefer to use OR add each component to an appropriate position within the BorderLayout
See Laying Out Components Within a Container for more details
solved, because I've found that i use paint() instead of paintComponent().
like this:
#Override
public void paint(Graphics g) {
// TODO Auto-generated method stub
super.paint(g);
g.drawImage(bg, 0, 0, l, t, this);
}
to this :
#Override
public void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponents(g);
g.drawImage(bg, 0, 0, l, t, this);
}

JButton isn't in the right place when a BufferedImage is used in it's container

I'm trying to create a simple game using AWT but I want to have some JButtons aswell to exit/reset the game. The problem is, I want the BufferedImage to be drawn inside the visible frame like so in my container I have this at the end:
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
My problem is, when I add a JButton to that frame, it only detects rollover in space that doesn't take into account the offsetting, but is drawn in a space that does. This is the relevant code (con is the container).
private void addButtons()
{
reset = new JButton("reset");
reset.setBounds(180,460, 75,30);
reset.addActionListener( this );
con.add(reset);
exit = new JButton("exit");
exit.setBounds(290,460, 60,30);
exit.addActionListener( this );
con.add(exit);
con.repaint();
}
The paint method in the Container
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
b.setColor(Color.GRAY);
b.fillRect(0, 0, this.getWidth(), this.getHeight());
b.setColor(Color.BLACK);
b.drawRect(0,0,420,420);
super.paint(b);
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
}
How can I make the button be drawn and detected in the same spot?
here is a screenshot of the problem
As requested:
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class Draw implements ActionListener{
private SnakeFrame frame;
private SnakeCon con;
JButton reset, exit;
private boolean res;
public Draw()
{
frame = new SnakeFrame("Snake");
frame.setResizable(false);
frame.setLayout(null);
frame.setSize(600,600);
frame.setVisible(true);
con = new SnakeCon();
con.setBounds(0,0,600,600);
frame.add(con);
}
private void addButtons()
{
reset = new JButton("reset");
reset.setBounds(180,460, 75,30);
reset.addActionListener( this );
con.add(reset);
exit = new JButton("exit");
exit.setBounds(290,460, 60,30);
exit.addActionListener( this );
con.add(exit);
con.repaint();
}
public void run()
{
addButtons();
res = false;
boolean dead = false;
while(!dead)
{
if( (res) )
dead = true;
if (!dead)
{
try{
Thread.sleep(100);
}
catch (Exception e)
{}
frame.repaint();
}
}
con.removeAll();
}
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == reset)
res = true;
else if (e.getSource() == exit)
System.exit(0);
}
}
--
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeCon extends Container{
private BufferedImage bf;
public SnakeCon()
{
super();
setBounds(0,0,600,600);
}
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
b.setColor(Color.GRAY);
b.fillRect(0, 0, this.getWidth(), this.getHeight());
b.setColor(Color.BLACK);
b.drawRect(0,0,420,420);
super.paint(b);
g.drawImage(bf,getParent().getInsets().left,getParent().getInsets().top,null);
}
public void update(Graphics g)
{
paint(g);
}
}
--
import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.image.*;
import java.awt.event.*;
import java.awt.Color;
public class SnakeFrame extends Frame implements WindowListener{
private BufferedImage bf;
public SnakeFrame(String s)
{
super(s);
addWindowListener( this );
}
public void paint(Graphics g)
{
bf = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics b = bf.getGraphics();
super.paint(b);
g.drawImage(bf,0,0,null);
}
public void update(Graphics g)
{
paint(g);
}
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
public void windowClosed(WindowEvent e) { }
public void windowOpened(WindowEvent e) { }
public void windowIconified(WindowEvent e) { }
public void windowDeiconified(WindowEvent e) { }
public void windowActivated(WindowEvent e) { }
public void windowDeactivated(WindowEvent e) { }
}
--
public class Main {
public static void main(String[] args)
{
boolean never = false;
Draw d = new Draw();
while(!never)
{
d.run();
}
System.exit(0);
}
}
Im not sure exactly what is wrong/what you want (why do you have a loop to constantly drawing buttons and invoking removeAll()? etc but i cant shake the feeling it might be implemented in a more readable/efficient way)...
But here are some suggestions that can only help your code get better:
Dont use null/Absolute Layout choose an appropriate LayoutManager.
Do not override JFrame paint(..), rather add JPanel to JFrame and override paintComponent(Graphics g) of JPanel and do drawing there.(Do not forget to have super.paintComponent(..) as 1st call in overriden paintComponent method. See here for more: Performing Custom Painting
Do not set JFrame visible before adding all components to JFrame
Always create and manipulate Swing components on Event Dispatch Thread like so:
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//create Swing components
}
});
Do not do long running tasks on Event Dispatch Thread rather use Swing Timer/Swing Worker
Do not call setSize(..) on JFrame rather override getPreferredSize() of JPanel and return Dimensions which fit all components (see here for reasoning), than call pack() on JFrame before setting it visible
Dont extend JFrame unnecessarily or Container!
Adding WindowListener for detecting JFrame exit is not worth the lines rather use:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
to exit Swing application when X is pressed.

Categories