Java Graphics on a null layout - java

My end game for this panel is that I have an img icon be able to move around the screen and when they land on one of my what are currently buttons the new panel opens up and you get a mini game, i.e. true/false, maze, or word find.
Where I am currently at...
I made a basic null layout and put buttons as place holders where the players icon will go to to open the next panel.
I was working on putting a simple rectangle on the screen that would use arrow keyboard listener to move around. I watched tutorials online about creating this as well as searched this data base.
My current code still shows my null layout with with my map img background and buttons with img icons on those buttons. It will not show my rectangle.
Yes I am a student and this is a project from school, my hope is that you give me guidance in the right direction for the 3 main things I am trying to do here.
A. Get rectangle on screen and move it.
B. Get image icon on rectangle.
C. Where should I start with looking into making it so when the object that moves hits a certain spot JLable,Jbutton,Janything I can't think of how to bring up my new panel that I already have made.
Thank you for any help you all can provide.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class map extends JPanel implements ActionListener, KeyListener{
Timer t = new Timer(5,this);
int x = 0, y = 0, velX = 0, velY = 0;
JButton mapButton, worldCampusB, universityParkB, fayetteB, erieB, yorkB,
hazeltonB;
JLabel background;
ImageIcon img;
public map(){
t.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
setBackground(new Color(9, 49, 98));
setLayout(new BorderLayout());
ImageIcon oldmain = new ImageIcon("images/oldmain.jpg");
ImageIcon hazelton = new ImageIcon("images/hazelton.jpeg");
ImageIcon york = new ImageIcon("images/york.jpg");
ImageIcon erie = new ImageIcon("images/erie.jpg");
ImageIcon fayette = new ImageIcon("images/fayette.jpg");
ImageIcon worldcampus = new ImageIcon("images/worldcampus.png");
background = new JLabel(new ImageIcon("images/pennmap.jpg"));
add (background);
background.setLayout(null);
mapButton = new JButton("Map Menu: Click to return to main menu.");
mapButton.setBounds(new Rectangle(300,20,300,50));
worldCampusB = new JButton("World Campus");
worldCampusB.setIcon(worldcampus);
universityParkB = new JButton("University Park");
universityParkB.setIcon(oldmain);
fayetteB = new JButton("Fayette");
fayetteB.setIcon(fayette);
erieB = new JButton ("Erie");
erieB.setIcon(erie);
yorkB = new JButton ("York");
yorkB.setIcon(york);
hazeltonB = new JButton ("Hazelton");
hazeltonB.setIcon(hazelton);
background.add(mapButton);
background.add(worldCampusB);
background.add(universityParkB);
background.add(fayetteB);
background.add(erieB);
background.add(yorkB);
background.add(hazeltonB);
//adjusted the button locations on the map - jpk5816
worldCampusB.setBounds(new Rectangle (750,20,195,150));
worldCampusB.setHorizontalTextPosition(JButton.CENTER);
worldCampusB.setVerticalTextPosition(JButton.BOTTOM);
universityParkB.setBounds(new Rectangle(380,250,175,140));
universityParkB.setHorizontalTextPosition(JButton.CENTER);
universityParkB.setVerticalTextPosition(JButton.BOTTOM);
fayetteB.setBounds(new Rectangle(40,445,200,150));
fayetteB.setHorizontalTextPosition(JButton.CENTER);
fayetteB.setVerticalTextPosition(JButton.BOTTOM);
erieB.setBounds(new Rectangle(50,100,175,170));
erieB.setHorizontalTextPosition(JButton.CENTER);
erieB.setVerticalTextPosition(JButton.BOTTOM);
yorkB.setBounds(new Rectangle(625,460,185,130));
yorkB.setHorizontalTextPosition(JButton.CENTER);
yorkB.setVerticalTextPosition(JButton.BOTTOM);
hazeltonB.setBounds(new Rectangle(690,190,170,140));
hazeltonB.setHorizontalTextPosition(JButton.CENTER);
hazeltonB.setVerticalTextPosition(JButton.BOTTOM);
}
public void paintCompent(Graphics g){
super.paintComponent(g);
g.setColor(new Color(9, 49, 98));
g.fillRect(x, y, 50, 30);
}
public void actionPerformed(ActionEvent e){
repaint();
x += velX;
y += velY;
}
public void up(){
velY = -1;
velX = 0;
}
public void down(){
velY = 1;
velX = 0;
}
public void left(){
velX = -1;
velY = 0;
}
public void right(){
velX = 1;
velY = 0;
}
public void keyPressed(KeyEvent e){
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP){
up();
}
if (code == KeyEvent.VK_DOWN){
down();
}
if (code == KeyEvent.VK_LEFT){
left();
}
if (code == KeyEvent.VK_RIGHT){
right();
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e){}
}

Your JLabel's ImageIcon is being added to the drawing JPanel, the this or map JPanel (should be re-named "Map"), so that none of the drawing within map will display. But why do this? Why use a JLabel with ImageIcon as a background image when you're already overriding map's paintComponent? A better solution is to get rid of the background JLabel and simply draw that image within the paintComponent method of map, and then draw the rectangle after that.
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(backgroundImg, 0, 0, this); // draw image
g.setColor(new Color(9, 49, 98));
g.fillRect(x, y, 50, 30);
}
// rename this to Map so that it complies with Java standards
public class Map extends JPanel implements ActionListener, KeyListener {
private static String IMAGE_PATH = "images/pennmap.jpg";
// ..... other code here
// JLabel background; // **** get rid of this ****
// ImageIcon img;
private BufferedImage backgroundImg;
// constructor needs to be re-named
public Map(){
backgroundImg = ImageIO.read(new File(IMAGE_PATH)); // read in image. Better to use resources though
// .... code here
// background = new JLabel(new ImageIcon("images/pennmap.jpg")); // again get rid of
// add (background); // get rid of
// .... code here
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(backgroundImg, 0, 0, this); // draw image
g.setColor(new Color(9, 49, 98));
g.fillRect(x, y, 50, 30);
}
// .....
}

Found a way to draw the image that isn't the odd idea for a beginner in the other answer.
in myJPanel
public class myJPanel extends JPanel implements ActionListener {
ImageIcon img; //declare
public myJPanel(){
super();
setBackground(Color.white);
setLayout (new BorderLayout());
credits = new credits();
instructions = new instructions();
characterTheme = new characterTheme();
img = new ImageIcon("images/pennmap.jpg");//grab from images foler.
in map.java which is where I wanted the img drawn.
public class map extends JPanel {
ImageIcon img;
public map (ImageIcon img){
this.img = img;
Dimension size = new Dimension(getWidth(),getHeight());
setPreferredSize(size);
setMinimumSize(size);
setMaximumSize(size);
setSize(size);
setLayout(null);
}
public void paintComponent(Graphics g){
g.drawImage(img.getImage(), 0, 0, null);
}
There was much more to the question but it appears there isn't much interest in it so I will close it at this. As this was my first hurdle in this mini project of making this game.

Related

Scaling graphics with AffineTransform

I am making a GUI with Swing that uses an AffineTransform to scale Graphics2D objects painted on a JInternalFrame. The problem is that it is buggy in the current state and I can't figure out why.
Why isn't my code scaling properly? Why do the graphics "jump" to the top of the panel on a resize?
Here is my self contained example:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.util.*;
public class MainPanel extends JFrame implements ActionListener{
private static final double version = 1.0;
private JDesktopPane desktop;
public static RFInternalFrame frame;
private java.util.List<Point> POINT_LIST = Arrays.asList(
//Top Row
new Point(50, 30),
new Point(70, 30),
new Point(90, 30),
new Point(110, 30),
new Point(130, 30),
new Point(150, 30),
new Point(170, 30),
new Point(190, 30),
new Point(210, 30),
new Point(230, 30),
//Circle of Radios
new Point(140, 60),
new Point(120, 80),
new Point(100, 100),
new Point(100, 120),
new Point(120, 140),
new Point(140, 160),
new Point(160, 140),
new Point(180, 120),
new Point(180, 100),
new Point(160, 80));
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
JFrame frame = new MainPanel();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(false);
frame.setVisible(true);
}
public MainPanel() {
super("MainPanel " + version);
//Make the big window be indented 50 pixels from each edge
//of the screen.
int inset = 50;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(inset, inset,
screenSize.width - inset * 7,
screenSize.height - inset * 4);
//Set up the GUI.
desktop = new JDesktopPane(); //a specialized layered pane
desktop.setBackground(Color.DARK_GRAY);
createRFFrame(); //create first RFFrame
createScenarioFrame(); //create ScenarioFrame
setContentPane(desktop);
setJMenuBar(createMenuBar());
//Make dragging a little faster but perhaps uglier.
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
}
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
//Set up the lone menu.
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_D);
menuBar.add(menu);
//Set up the first menu item.
JMenuItem menuItem = new JMenuItem("Add Panel");
menuItem.setMnemonic(KeyEvent.VK_N);
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_N, ActionEvent.ALT_MASK));
menuItem.setActionCommand("new");
menuItem.addActionListener(this);
menu.add(menuItem);
//Set up the second menu item.
menuItem = new JMenuItem("Quit");
menuItem.setMnemonic(KeyEvent.VK_Q);
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_Q, ActionEvent.ALT_MASK));
menuItem.setActionCommand("quit");
menuItem.addActionListener(this);
menu.add(menuItem);
return menuBar;
}
//React to menu selections.
public void actionPerformed(ActionEvent e) {
if ("new".equals(e.getActionCommand())) { //new
createRFFrame();
} else {
//quit
quit();
}
}
/*
* ActivateAllAction activates all radios on the panel, essentially changes the color
* of each ellipse from INACTIVE to ACTIVE
*/
private class ActivateAllAction extends AbstractAction {
public ActivateAllAction(String name) {
super(name);
int mnemonic = (int) name.charAt(1);
putValue(MNEMONIC_KEY, mnemonic);
}
/*
* This will find the selected tab and extract the DrawEllipses instance from it
* Then for the actionPerformed it will call activateAll() from DrawEllipses
*/
#Override
public void actionPerformed(ActionEvent e) {
Component comp = desktop.getSelectedFrame();
if (comp instanceof DrawEllipses){
DrawEllipses desktop = (DrawEllipses) comp;
desktop.activateAll();
}
}
}
/*
* DeactivateAllAction deactivates all radios on the panel, essentially changes the color
* of each ellipse from ACTIVE to INACTIVE
*/
private class DeactivateAllAction extends AbstractAction {
public DeactivateAllAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
/*
* This will find the selected tab and extract the DrawPanel2 instance from it
* Then for the actionPerformed it will call activateAll() from DrawEllipses
*/
#Override
public void actionPerformed(ActionEvent e) {
Component comp = desktop.getSelectedFrame();
if (comp instanceof DrawEllipses){
DrawEllipses desktop = (DrawEllipses) comp;
desktop.deactivateAll();
}
}
}
/*
* Define a JPanel that will hold the activate and deactivate all JButtons
*/
protected JPanel btnPanel() {
JPanel btnPanel = new JPanel();
btnPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder());
//Set the layout of the frame to a grid bag layout
btnPanel.setLayout(new GridBagLayout());
//Creates constraints variable to hold values to be applied to each aspect of the layout
GridBagConstraints c = new GridBagConstraints();
//Column 1
c.gridx = 0;
btnPanel.add(new JButton(new ActivateAllAction("Activate All")));
//Column 2
c.gridx = 1;
btnPanel.add(new JButton(new DeactivateAllAction("Deactivate All")));
return btnPanel;
}
//not used currently
protected JPanel drawPanel() {
JPanel drawPanel = new JPanel();
drawPanel.setBorder(BorderFactory.createLoweredSoftBevelBorder());
DrawEllipses drawEllipses = new DrawEllipses(POINT_LIST);
drawPanel.add(drawEllipses);
return drawPanel;
}
//Create a new internal frame.
protected void createRFFrame() {
RFInternalFrame iframe = new RFInternalFrame();
iframe.setLayout(new BorderLayout());
DrawEllipses drawEllipses = new DrawEllipses(POINT_LIST);
iframe.add(drawEllipses);
iframe.add(btnPanel(), BorderLayout.SOUTH);
iframe.setVisible(true);
desktop.add(iframe);
try {
iframe.setSelected(true);
} catch (java.beans.PropertyVetoException e) {}
}
protected void createScenarioFrame() {
ScenarioInternalFrame frame = new ScenarioInternalFrame();
frame.setLayout(new BorderLayout());
frame.setVisible(true);
desktop.add(frame);
try {
frame.setSelected(true);
} catch (java.beans.PropertyVetoException e) {}
}
//Quit the application.
protected void quit() {
System.exit(0);
}
}
#SuppressWarnings("serial")
class DrawEllipses extends JPanel {
private double translateX; //
private double translateY; //
protected static double scale; //
private static final int OVAL_WIDTH = 15;
private static final Color INACTIVE_COLOR = Color.RED;
private static final Color ACTIVE_COLOR = Color.green;
private java.util.List<Point> points; //
private java.util.List<Ellipse2D> ellipses = new ArrayList<>();
private Map<Ellipse2D, Color> ellipseColorMap = new HashMap<>();
public DrawEllipses(java.util.List<Point> points) {
this.points = points; //
translateX = 0; //
translateY = 0; //
scale = 1; //
setOpaque(true); //
setDoubleBuffered(true); //
for (Point p : points) {
int x = p.x - OVAL_WIDTH / 2;
int y = p.y - OVAL_WIDTH / 2;
int w = OVAL_WIDTH;
int h = OVAL_WIDTH;
Ellipse2D ellipse = new Ellipse2D.Double(x, y, w, h);
ellipses.add(ellipse);
ellipseColorMap.put(ellipse, INACTIVE_COLOR);
}
MyMouseAdapter mListener = new MyMouseAdapter();
addMouseListener(mListener);
addMouseMotionListener(mListener);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
AffineTransform tx = new AffineTransform(); //
tx.translate(translateX, translateY); //
tx.scale(scale, scale); //
Graphics2D g2 = (Graphics2D) g;
g2.setTransform(tx);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Ellipse2D ellipse : ellipses) {
g2.setColor(ellipseColorMap.get(ellipse));
g2.fill(ellipse);
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
for (Ellipse2D ellipse : ellipses) {
if (ellipse.contains(e.getPoint())) {
Color c = ellipseColorMap.get(ellipse);
c = (c == INACTIVE_COLOR) ? ACTIVE_COLOR : INACTIVE_COLOR;
ellipseColorMap.put(ellipse, c);
}
}
repaint();
}
}
//Used for button click action to change all ellipses to ACTIVE_COLOR
public void activateAll(){
for (Ellipse2D ellipse : ellipses){
ellipseColorMap.put(ellipse, ACTIVE_COLOR);
}
repaint();
}
//Used for button click action to change all ellipses to INACTIVE_COLOR
public void deactivateAll(){
for (Ellipse2D ellipse : ellipses){
ellipseColorMap.put(ellipse, INACTIVE_COLOR);
}
repaint();
}
}
class RFInternalFrame extends JInternalFrame implements ComponentListener {
protected static double scale = 1; //
static int openFrameCount = 0;
static final int xOffset = 300, yOffset = 0;
public RFInternalFrame() {
super("RF Panel #" + (++openFrameCount),
true, //resizable
true, //closable
true, //maximizable
true);//iconifiable
setSize(300, 300);
setMinimumSize(new Dimension(300, 300));
addComponentListener(this);
if (openFrameCount == 1) {
setLocation(0,0);
}
else if (openFrameCount <= 4) {
//Set the window's location.
setLocation(xOffset * (openFrameCount - 1), yOffset * (openFrameCount - 1));
}
else if (openFrameCount == 5) {
setLocation(xOffset - 300, yOffset + 300);
}
else if (openFrameCount == 6) {
setLocation(xOffset + 600, yOffset + 300);
}
}
#Override
public void componentResized(ComponentEvent e) {
String str = "";
if (getWidth() < 300) {
str = "0." + getWidth();
} else {
str = "1." + (getWidth() - 300);
System.out.println(getWidth() - 300);
}
double dou = Double.parseDouble(str);
MainPanel.frame.scale = dou;
repaint();
}
#Override
public void componentMoved(ComponentEvent componentEvent) {
}
#Override
public void componentShown(ComponentEvent componentEvent) {
}
#Override
public void componentHidden(ComponentEvent componentEvent) {
}
}
class ScenarioInternalFrame extends JInternalFrame {
static int openFrameCount = 0;
static final int xOffset = 300, yOffset = 300;
public ScenarioInternalFrame() {
super("Test Scenario" + (++openFrameCount),
true, //resizable
true, //closable
true, //maximizable
true);//iconifiable
//...Create the GUI and put it in the window...
//...Then set the window size or call pack...
setSize(600, 300);
//Set the window's location.
setLocation(xOffset, yOffset);
}
}
As I understand it, the Graphics object already contains a transform that does a translate to account for the height of the title bar of the internal frame. When you replace the transform you lose this translation so your code is painted at the top of the frame under the title bar.
Don't change properties of the Graphics object passed to the paintComponent() method. Instead create a Graphics2D object you can customize.
When you create a new transform you need to apply the existing transform first before adding new transforms.
The basic structure would be something like:
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g.create();
AffineTransform tx = new AffineTransform(); //
tx.concatenate( g2.getTransform() );
tx.scale(...);
g2.setTransform(tx);
// do custom painting
g2.dispose(); // release Graphics resources
This will just help the painting. You still have several problems (which I can't solve):
Your scale value is never getting updated. You should be adding the ComponentListener to the DrawEllipse panel. You might want to create a setScale() method in the panel that you invoked to set the scale when the panel is resized.
Once you do paint the circles scaled, you MouseListener won't work. The location of all the circles will be different because they have been scaled. You might be able to scale each circle as you iterate through the list of circles.
Also, when you have a question post a proper SSCCE that demonstrates the problem. You have a simple question about using a transform on a panel. So create a frame with a panel and paint a couple of circles on the panel to test the concept.
All the other code is irrelevant to the problem. The menu items are irrelevant, the second internal frame is irrelevant. The MouseListener clicking code is irrelevant. We don't have time to read through 100's of lines of code to understand the question.
Edit:
I changed the order of the code. The tx.scale(...) method must be invoked before setting the transform to the Graphics object.
I my experience, painting on Swing will be done with double buffer. Means that you create the drawing buffer (ie. ImageBuffer). you apply all your drawing logic to the Graphics of the drawing buffer, including transformation, and then finally, draw your buffer into the component's graphics.
This is how I solve your problem...
class DrawEllipses extends JComponent { // I change from JPanel to JComponent, this might not be necessary though...
...
...
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// create the drawing buffer.
BufferedImage bi = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics big = bi.getGraphics();
// prepare transform
AffineTransform tx = new AffineTransform(); //
tx.translate(translateX, translateY); //
tx.scale(scale, scale); //
// get the buffer graphics and paint the background white.
Graphics2D g2 = (Graphics2D) big;
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, this.getWidth(), this.getHeight());
// apply drawing logic to the Graphics of the buffer
g2.setTransform(tx);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for (Ellipse2D ellipse : ellipses) {
g2.setColor(ellipseColorMap.get(ellipse));
g2.fill(ellipse);
}
// finally, draw the buffer to the component graphics.
g.drawImage(bi, 0, 0, null);
}
Try it... hope it works and helps.

Add moving objects to JFrame

I'm creating a java game. In the game there are a hero and a bubble. The hero is supposed to move when I press the arrow keys and the bubble is supposed to have continuous diagonal movement. When I add the hero or the bubble directly into to the JFrame separately I get the desired behavior, but when I add them both I just get a very small square! I tried to add them to the same JPanel and after add that JPanel to the JFrame but it is not working. Probably I have to define some type of layout to the JPanels.
What am I doing wrong?
Code:
public class Pang {
public static void main(String[] args) {
JFrame f=new JFrame();
JPanel gamePanel=new JPanel();
gamePanel.setPreferredSize(new Dimension(800, 600));
DrawHero d=new DrawHero();
DrawBubble bubble=new DrawBubble();
gamePanel.add(d);
gamePanel.add(bubble);
f.add(gamePanel);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
}
}
public class DrawHero extends JPanel implements ActionListener, KeyListener {
Timer myTimer = new Timer(5, this);
int x = 0, y = 0, dx = 0, dy = 0, step = 10;
private transient Image imageHero = null;
public DrawHero() {
myTimer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
imageHero = getHeroImage();
g2.drawImage(imageHero, x, y, 40, 40, null);
}
public Image getHeroImage() {
Image image = null;
image = getImage("hero.png");
return image;
}
public Image getImage(String path) {
Image tempImage = null;
try {
URL heroiURL = DrawHero.class.getResource(path);
tempImage = Toolkit.getDefaultToolkit().getImage(heroiURL);
} catch (Exception e) {
System.out.println("Error loading hero image! - "
+ e.getMessage());
}
return tempImage;
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void moveUp() {
y = y - step;
}
public void moveDown() {
y = y + step;
}
public void moveLeft() {
x = x - step;
}
public void moveRight() {
x = x + step;
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP) {
moveUp();
}
if (keyCode == KeyEvent.VK_DOWN) {
moveDown();
}
if (keyCode == KeyEvent.VK_LEFT) {
moveLeft();
}
if (keyCode == KeyEvent.VK_RIGHT) {
moveRight();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
public class DrawBubble extends JPanel implements ActionListener, KeyListener {
Timer myTimer = new Timer(5, this);
int x = 100, y = 200, dx = 0, dy = 0, step = 10;
private transient Image imageHero = null;
public DrawBubble() {
myTimer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 40, 40));
}
public void actionPerformed(ActionEvent e) {
x=x+dx;
y=y+dy;
repaint();
}
public void moveBubble() {
dy=2;
dx=2;
}
public void keyPressed(KeyEvent e) {
moveBubble();
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
I recommend that neither the DrawHero nor DrawBubble (which should be called Hero nor Bubble respectively) should extend any JComponent. Instead each should simply know how to draw itself to a Graphics object passed to it, when requested to do so.
Then a single GameField or PlayingArea class should keep references to all the Bubble objects and the Hero and draw call the draw(Graphics) method of those objects.
Using this approach it is not necessary to worry about layouts within the GameField component (they become irrelevant).
That is the basic strategy I pursue for rendering the stationary objects in this answer to [Collision detection with complex shapes.
When I add the hero or the bubble directly into to the JFrame separately I get the desired behavior, but when I add them both i just get a very small square!
The default layout manager for a JFrame is a BorderLayout. When you use add(component) without a constraint the component goes to the CENTER. Only one component can be added to the CENTER, so only the last one added is displayed.
I tried to add them to the same JPanel and after add that JPanel to the JFrame but it is not working.
The default layout manager for a JPanel is the FlowLayout which respects the preferred size of component. The problem is you don't override the getPreferredSize() method so the size is (0, 0) and there is nothing to paint.
Probably I have to define some type of layout to the JPanels.
Actually since you want random motion you need to use a null layout on the panel and then use the setSize() and setLocation() method of your components to position the components.
Then when you do this the custom painting should always be done at (0, 0) instead of (x, y) since the location will control where the component is painted on the panel.

Drawing on an Image

So I have a program that is basically like paint but made in Java and can only draw a few colours. By default the background of the program is white, but what I'd like to do is try to load an image and then be able to draw on top of that image. I can load the image but fro some reason it wont show the lines when I try drawing on it. Here is the code.
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Paint {
public static void main(String[] args) {
PaintWindow frame = new PaintWindow();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
}
}
class PaintWindow extends JFrame {
public PaintWindow() {
setTitle("JavShot Edit");
setSize(668, 600);
setLocationRelativeTo(null);
panel = new JPanel();
drawPad = new PadDraw();
panel.setPreferredSize(new Dimension(75, 68));
//Creates a new container
Container content = this.getContentPane();
content.setLayout(new BorderLayout());
//sets the panel to the left, padDraw in the center
content.add(panel, BorderLayout.WEST);
content.add(drawPad, BorderLayout.CENTER);
//add the color buttons:
makeColorButton(Color.BLUE);
makeColorButton(Color.MAGENTA);
makeColorButton(Color.RED);
makeColorButton(Color.GREEN);
makeColorButton(Color.BLACK);
makeColorButton(Color.WHITE);
//creates the clear button
JButton clearButton = new JButton("Clear");
clearButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
drawPad.clear();
}
});
panel.add(clearButton);
}
/*
* makes a button that changes the color
* #param color the color used for the button
*/
public void makeColorButton(final Color color) {
JButton tempButton = new JButton();
tempButton.setBackground(color);
tempButton.setPreferredSize(new Dimension(16, 16));
panel.add(tempButton);
tempButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
drawPad.changeColor(color);
}
});
}
private JPanel panel;
private PadDraw drawPad;
}
class PadDraw extends JComponent {
//this is gonna be your image that you draw on
Image image;
//this is what we'll be using to draw on
Graphics2D graphics2D;
//these are gonna hold our mouse coordinates
int currentX, currentY, oldX, oldY;
public PadDraw() {
setDoubleBuffered(false);
addMouseListener(new MouseAdapter() {
//if the mouse is pressed it sets the oldX & oldY
//coordinates as the mouses x & y coordinates
public void mousePressed(MouseEvent e) {
oldX = e.getX();
oldY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter() {
//while the mouse is dragged it sets currentX & currentY as the mouses x and y
//then it draws a line at the coordinates
//it repaints it and sets oldX and oldY as currentX and currentY
public void mouseDragged(MouseEvent e) {
currentX = e.getX();
currentY = e.getY();
graphics2D.drawLine(oldX, oldY, currentX, currentY);
graphics2D.drawLine(oldX + 1, oldY + 1, currentX + 1, currentY + 1);
repaint();
oldX = currentX;
oldY = currentY;
}
});
}
//this is the painting bit
//if it has nothing on it then
//it creates an image the size of the window
//sets the value of Graphics as the image
//sets the rendering
//runs the clear() method
//then it draws the image
public void paintComponent(Graphics g) {
try {
image = ImageIO.read(new File("C:\\Users\\user\\Desktop\\Untitled.png"));
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
} catch (IOException e) { }
if(image == null) {
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
clear();
}
g.drawImage(image, 0, 0, null);
}
//this is the clear
//it sets the colors as white
//then it fills the window with white
//thin it sets the color back to black
public void clear() {
graphics2D.setPaint(Color.white);
graphics2D.fillRect(0, 0, getSize().width, getSize().height);
graphics2D.setPaint(Color.black);
repaint();
}
public void changeColor(Color theColor) {
graphics2D.setPaint(theColor);
repaint();
}
}
I load the image here:
image = ImageIO.read(new File("C:\\Users\\user\\Desktop\\Untitled.png"));
graphics2D = (Graphics2D)image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
} catch (IOException e) { }
Does anyone know what the problem is?
Painting is a destructive process. That is, each time paintComponent is called, you are expected to repaint what ever it is you need to displayed the screen, entirely from scratch.
There are (at least) two immediate issues with your approach
You are not calling super.paintComponent, this will effect the way in which the paint process updates the screen, this VERY important as you have extended from JComponent which is transparent by default and may compromise the ability for the framework to function correctly (leaving nasty paint artifacts all over the place) - also remember, Graphics is a shared resource. All the other components that are to be painted will share this resource, meaning that you could end up with what ever was painted before you being left on the screen.
You are re-loading your image EVERY time paintComponent is called. This means, that what ever you painted to graphics2D is going to be lost.
I wouldn't bother setDoubleBuffered(false) as this will effect the way in which the component is updated and could produce undesirable results.
I would add each point you want to draw to a List of some kind and paint this list within the paintComponent method.
Don't load resources within any paintXxx method. These should be prepared before hand.
I can see that you are "trying" to perform some kind of double buffering, but this isn't really how it should be done. You are going little from it other then problems. Start with a simple solution first.

Why doesn't my text color change to white again?

The picture's worth a thousand words.
I used a JLabel to create my GUI after adding the gradient background.
I used setPaint(gr) to change the color to the required gradient and then used setPaint(Color.white) again to change the color to white.
And then I use the setupGUI() to create the buttons n all you see.
However they are in gray and not white.
How do I make it white again
public class ScreenRecorder extends JFrame{
public ScreenRecorder(){
setupGUI();
this.getContentPane().add(b);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
this.pack();
}
/*This method is used to add components into each other, setting layout, etc*/
public void setupGUI(){
play.setPreferredSize(new Dimension(24,24));
Box controls = Box.createHorizontalBox();
controls.add(play);
controls.add(Box.createHorizontalStrut(10));
controls.add(timerLabel);
controls.add(Box.createHorizontalStrut(200));
controls.add(locationLabel);
b.add(controls);
}
/* Creating the gradient background */
protected class Background extends JPanel{
#Override
protected void paintComponent(Graphics g){
Graphics2D g2D = (Graphics2D) g;
int w = this.getWidth();
int h = this.getHeight();
Color color1 = Color.black;
Color color2 = Color.DARK_GRAY.brighter();
GradientPaint gr = new GradientPaint(0,0,color1,0,w/2,color2);
g2D.setPaint(gr); //Color changes to the gradient color
g2D.fillRect(0, 0, w, h);
g2D.setPaint(Color.white); //Color changes to white for JLabel, but doesn't actually change
}
}
/*Creating the combined Play and Pause button using AbstractAction
* The displayed icon must change from that of play to pause on click and vice versa*/
protected class PlayAction extends AbstractAction{
public PlayAction(){
this.putValue(AbstractAction.LARGE_ICON_KEY, playIcon);
this.putValue(SHORT_DESCRIPTION, "Click to Record Video");
}
#Override
public void actionPerformed(ActionEvent e){
if(isPlay == true){
isPlay = false;
play.getAction().putValue(LARGE_ICON_KEY, pauseIcon);
play.getAction().putValue(SHORT_DESCRIPTION,"Click to Pause Recording");
ScreenRecorder.this.setState(JFrame.ICONIFIED);
play.repaint();
}else{
isPlay = true;
play.getAction().putValue(LARGE_ICON_KEY, playIcon);
play.getAction().putValue(SHORT_DESCRIPTION,"Click to Start Recording");
play.repaint();
}
}
boolean isPlay = true; //true represents recorder is ready, false means it is currently recording
Icon playIcon = (Icon) new ImageIcon("src/images/play.png");
Icon pauseIcon = (Icon) new ImageIcon("src/images/pause.png");
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
new ScreenRecorder();
}
});
}
Background b = new Background();
JButton play = new JButton(new PlayAction());
JLabel timerLabel = new JLabel("00:00",JLabel.CENTER);
JLabel locationLabel = new JLabel("Into: ",JLabel.LEFT);
}
import java.awt.*;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class JavaGui129 extends JFrame{
public JavaGui129(){
setupGUI();
this.getContentPane().add(b);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setResizable(false);
this.pack();
}
/*This method is used to add components into each other, setting layout, etc*/
public void setupGUI(){
//play.setPreferredSize(new Dimension(24,24));
Box controls = Box.createHorizontalBox();
controls.add(play);
controls.add(Box.createHorizontalStrut(10));
// Red letter day..
timerLabel.setForeground(Color.RED);
controls.add(timerLabel);
controls.add(Box.createHorizontalStrut(200));
locationLabel.setForeground(Color.GREEN);
controls.add(locationLabel);
b.add(controls);
}
/* Creating the gradient background */
protected class Background extends JPanel{
#Override
protected void paintComponent(Graphics g){
// very important!
super.paintComponent(g);
Graphics2D g2D = (Graphics2D) g;
int w = this.getWidth();
int h = this.getHeight();
Color color1 = Color.black;
Color color2 = Color.DARK_GRAY.brighter();
GradientPaint gr = new GradientPaint(0,0,color1,0,w/2,color2);
g2D.setPaint(gr); //Color changes to the gradient color
g2D.fillRect(0, 0, w, h);
// irrelevant now
//g2D.setPaint(Color.white); //Color changes to white for JLabel, but doesn't actually change
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(400,100));
}
}
/*Creating the combined Play and Pause button using AbstractAction
* The displayed icon must change from that of play to pause on click and vice versa*/
protected class PlayAction extends AbstractAction{
public PlayAction(){
this.putValue(AbstractAction.LARGE_ICON_KEY, playIcon);
this.putValue(SHORT_DESCRIPTION, "Click to Record Video");
}
#Override
public void actionPerformed(ActionEvent e){
if(isPlay == true){
isPlay = false;
play.getAction().putValue(LARGE_ICON_KEY, pauseIcon);
play.getAction().putValue(SHORT_DESCRIPTION,"Click to Pause Recording");
JavaGui129.this.setState(JFrame.ICONIFIED);
play.repaint();
}else{
isPlay = true;
play.getAction().putValue(LARGE_ICON_KEY, playIcon);
play.getAction().putValue(SHORT_DESCRIPTION,"Click to Start Recording");
play.repaint();
}
}
boolean isPlay = true; //true represents recorder is ready, false means it is currently recording
Icon playIcon = (Icon) new ImageIcon("src/images/play.png");
Icon pauseIcon = (Icon) new ImageIcon("src/images/pause.png");
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
new JavaGui129();
}
});
}
Background b = new Background();
JButton play = new JButton(new PlayAction());
JLabel timerLabel = new JLabel("00:00",JLabel.CENTER);
JLabel locationLabel = new JLabel("Into: ",JLabel.LEFT);
}
Try
setColor(Color.white);
as well
The Graphics class defines only the setColor method to control the color to be painted. Since the Java 2D API extends the Color object to implement the new Paint interface, the existing setColor method is now a convenience method for setting the current Paint attribute to a Color object. setColor(c) is equivalent to setPaint(c).

Paint a JPanel to a BufferedImage or Print it without rendering it to screen first

Picture this... A program GUI JFrame that is split in 2, EAST and WEST. The first JPanel is just a print preview screen. The EAST side of the JFrame is where the user can create a 1 2 or 3 size image. The user clicks the "Add" button and the defined image on the right goes to the panel on the left. So if the user clicks "Add" 3 times with different size images, then the panel uses FlowLayout to organize the added panel images added on the left.
When you run this code, you can see a sorta idea of what I want. Really what would be nice is to create all this off-screen and call it MainPanel. Then have printPreview extend MainPanel and scale it down for screen view. And have the Printable method paint the MainPanel into the print method which would be a correct size.
So my question...
-Can you copy or paint a JPanel before it is rendered on the screen?
-Is there a better way to do what I want, I FlowLayout solves what I want amazingly, so a JPanel seems to be the answer unless there is something I do not know of.
Ok now that that is pictured. I have built some code that is about as SSCCE as I can get.
Guys I have tried asking this question at New To Java forums and they just do not respond, I am not double posting on purpose, I completely rewrote this from scratch.
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.print.*;
import java.awt.event.*;
public class PrintGrid extends JFrame {
Paper paper = new Paper();
PrintGrid() {
super("Check out this grid panel");
setSize(672, 750);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(paper);
setVisible(true);
} // end PrintGrid constructor
// **************************
// ****** PAPER CLASS *******
// **************************
private class Paper extends JPanel {
final int PAPER_X = 672, PAPER_Y = 975, UNIT = 12, DPI = 72;
X1 x1a = new X1(), x1b = new X1(), x1c = new X1();
X2 x2a = new X2(), x2b = new X2(), x2c = new X2();
X3 x3a = new X3(), x3b = new X3(), x3c = new X3();
Paper() {
setPreferredSize(new Dimension(PAPER_X, PAPER_Y));
setBackground(Color.GRAY);
setLayout(new FlowLayout(FlowLayout.LEADING));
//Users will manually add different sizes to this sheet.
add(x1a);
add(x2a);
add(x3a);
add(x1b);
add(x1c);
add(x2b);
add(x3b);
}
// ******* Parent Class for GridUnits *******
abstract class GridUnit extends JPanel {
MouseListen ml = new MouseListen();
float alpha = 1.0f;
GridUnit() {
this.addMouseListener(ml);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(Color.BLACK);
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(makeComposite(alpha));
g.setColor(Color.WHITE);
g.drawRect(0, 0, this.getWidth()-1, this.getHeight()-1);
g.setColor(Color.darkGray);
g.fillRect(15, 15, this.getWidth()-30, this.getHeight()-30);
} // end paintComponent.
private AlphaComposite makeComposite(float alpha) {
int type = AlphaComposite.SRC_OVER;
return(AlphaComposite.getInstance(type, alpha));
}
void click() {
setVisible(false);
}
void entered() {
alpha = 0.8f;
repaint();
}
void exited() {
alpha = 1.0f;
repaint();
}
class MouseListen extends MouseAdapter {
public void mouseEntered(MouseEvent event) {
entered();
}
public void mouseExited(MouseEvent event) {
exited();
}
public void mousePressed(MouseEvent event) {
click();
}
}
} // end GridUnit class
class X1 extends GridUnit {
X1() {
setPreferredSize(new Dimension(UNIT*13, UNIT*18));
}
} // end X1 Class
class X2 extends GridUnit {
X2() {
setPreferredSize(new Dimension(UNIT*26, UNIT*18));
}
} // end X1 Class
class X3 extends GridUnit {
X3() {
setPreferredSize(new Dimension(UNIT*39, UNIT*18));
}
} // end X1 Class
} // end Paper class.
public static void main(String[] args) {
new PrintGrid();
} // end main method.
} // end PrintGrid class.
It's quite trivial to paint any Java component to an offscreen image, from which you can do as you please, including copying a portion or scaled image to a final target.
Subclass JComponent and override void paintComponent(Graphics g). Paint to a BufferedImage, then copy the image to the target component. Off the top of my head, something like:
void paintComponent(Graphics g) {
BufferedImage img=new BufferedImage(getWidth(),getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics2D gph=(Graphics2D)img.getGraphics();
// paint to gph here
gph.dispose();
g.drawImage(img); // paints the contents of img to the component's graphics context.
}

Categories

Resources