How to save a specific part of a JPanel? - java

I am working on a chess game and I would like to let the player choose the board's colors. Therefore I will use this method:
static void createBoard(Graphics g) {
Color bright = new Color(255, 225, 181); //player chooses color
Color dark = new Color(188, 141, 105); //player chooses color
boolean darkTile = false;
for (int y = spaceY; y < (spaceY + BOARDHEIGHT); y += TILESIZE) {
for (int x = spaceX; x < (spaceX + BOARDWIDTH); x += TILESIZE) {
if (darkTile) {
g.setColor(dark);
} else {
g.setColor(bright);
}
g.fillRect(x, y, TILESIZE, TILESIZE);
darkTile = !darkTile;
}
darkTile = !darkTile;
}
BufferedImage overlay;
try {
overlay = ImageIO.read(new File("overlay.png"));
JLabel label = new JLabel(new ImageIcon(overlay));
g.drawImage(overlay, spaceX, spaceY, BOARDWIDTH, BOARDHEIGHT, null);
} catch (IOException e) {}
}
This I would like to save as a BufferedImage, so I don't have to run this method all the time.
So how can I save just this part of my JPanel, without the stuff outside of the chess board? (there will be more painted)

This I would like to save as a BufferedImage,
Don't know that your need to save the BufferedImage to a file. You can just create a BufferedImage to be used by the application when the application starts. You can then recreate the BufferedImage if any of the user colors change.
You can paint directly to a BufferedImage:
BufferedImage image = new BufferedImage(boardSize, boardSize, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
// draw the squares onto board
g2d.dispose();
Now your createBoard() method should probably return the BufferedImage so it can be used by your application.

You put in certain efforts to put up your question, so lets honor that with some thoughts to get you going.
First of all: you have an empty catch block {}. That is bad practice. This simply eats up any error messages you get. That is not helpful. Either allow that exception to bubble up and stop your application; or at least print its contents - so that you understand what happens.
And given your comment: you never now if there will be errors. Especially when doing IO, all sorts of things can go wrong. Please believe me: empty catch blocks are bad practice; and you should not train yourself to accept them.
Second thought: don't go for that yet. As convenient as it might sound; but saving a background picture doesn't add much value at this point.
You don't need to worry about this code; it is executed once when your application comes up.
So, the real answer here: focus on the features you want to implement; and don't get distracted with pre-mature optimizations.

Related

Issue drawing using graphics Java

I am trying to draw an Oval with a for loop iterating through a list of coordinates that each contain an x value and y value. Currently, it does not seem to be drawing anything after I start the program. It draws the first time, but when I try drawing when the program is running, it doesn't seem to be drawing.
Here is the code for drawing:
private void render(){
bs = display.getCanvas().getBufferStrategy();
if(bs == null){
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Draw Here!
DrawGrid(g);
g.fillOval(100, 100, 10, 10);//this seems to draw
for(int i = 0; i < points.size();i++){//this doesn't draw....
System.out.println(points.get(i));
g.drawString(points.get(i).toString(), points.get(i).x*100-5+100, points.get(i).y-5-300);
g.fillOval(points.get(i).x*100-5+100, points.get(i).y-5-300, 10, 10);
}
//End Drawing!
bs.show();
g.dispose();
}
If you need more details, I am using graphics from java.awt library. Also, I have done this in the past, but I don't know why it isn't working this time.
This part is your issue:
points.get(i).x*100-5+100
Specifically x*100
You are drawing off screen. We can see this by breaking it down:
Lets assume that you have a point of x=28.
Lets do the math on that:
For X = 28 you will have the following calc: (28 * 100) - (5 + 100) = 2695
That X point of 2695 looks very large to me. You would need a 4k screen or ultrawide screen to see it.
The solution:
Have a think about why you are using x*100, and reduce it so that the point fits on your screen. Also, if you have a small y point, then it will be in the negatives (Example: 15-5-300 = -290), and will probably draw above your screen and out of sight.

How to move the location of the graphic in JPanel

So I'm creating a game using Javax.swing library for my uni coursework.
I have created a window and I have successfully written code to procedurally generate a game map.
However, I am unable to change the focus of the map. What I mean is that the map is always stuck in one corner of the screen. (IE: Location is set to 0,0, hence the Graphics g (the map) is put in that location going outwards.)
I would like to be able to move the "camera" so that different areas of the map can be viewed by the player.
Bellow I have pasted my method that draws the map onto the screen. Could anyone tell me what I could do to have the camera move at runtime. AKA: to shift the map left or right.
I thought of having a Graphics object that will hold the map, and then I'd only draw a subImage of that Graphics object, but considering how the map will be redrawn every frame (For animation purposes) that just means that I'll have even more graphics to redraw.
The map is 6,400 * 6,400 Pixels
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
try {
for(int x = 0; x < OverworldMap.MAP_X_SIZE; x++){
for(int y = 0; y < OverworldMap.MAP_Y_SIZE; y++){
for(int layer = 0; layer < OverworldMap.MAP_LAYER_SIZE; layer++) {
g.drawImage(OverworldMap.getTileAt(x, y, layer).getSprite(), x * SPRITE_SIZE, y * SPRITE_SIZE, null);
}
}
}
} catch (Exception e) {
LauncherClass.printErrorLog(e);
}
}
The best / easiest way to solve this is to put a JScrollPane around your JPanel, and make the JPanel the size of your image. You don't need to worry about only repainting the right part of your image - Java is pretty smart about only drawing the parts that are on screen. Note that you can show or hide the ScrollBars, but if you hide them you need to add logic to activate scrolling through some other mechanism
You cannot store a Graphics object and use it later. It is only valid for the duration of the paint method to which it is passed.
You can, however, simply offset your painting:
Image sprite = OverworldMap.getTileAt(x, y, layer).getSprite();
g.drawImage(sprite, x * SPRITE_SIZE - playerX, y * SPRITE_SIZE - playerY, this);
(Notice that the last argument to drawImage should be this.)

Image flickering upon being repainted by the mouseDragged method

As the title suggests, my problem is that I want to be able to drag an image.
In this specific case, I want to drag an image from one JPanel (or rather my own subclass) into another (different) subclass of JPanel. Therefore, I added an MouseListener to my JPanel subclass, so that upon clicking a certain area in the panel, an image is chosen to be painted on the JFrame (subclass). Here's some code so you'll understand my problem:
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (x >= 10 && x < 42 && y >= 10 && y < 42) {
image = barracks; //barracks is a predefined image, created in the constructor
dragBuilding = true;
PixelMain.pixelMain.repaint(); //pixelMain is an instance of the JFrame subclass
}
}
//irrelevant code, e.g mouseMoved, ...
public void mouseDragged(MouseEvent e) {
if (dragBuilding) {
//System.out.println("GPanel mouseDragged");
PixelMain.pixelMain.repaint();
}
}
the JFrame subclass only contains the constructor and the following code:
public void paint(Graphics g) { //i would have used paintComponent, but it seems like JFrame does not have this method ...?
super.paint(g);
if (PixelMain.panelOffense.getDragBuilding()) { //panelOffense is an instance of the JPanel subclass, getDragBuilding returns a boolean that depends on whether the mouse is held down at the moment
Graphics2D g2 = (Graphics2D) g;
Rectangle2D tr = new Rectangle2D.Double((int)getMousePosition().getX(), (int)getMousePosition().getY(), 16, 16); //size of the texture
TexturePaint tp = new TexturePaint(PixelMain.panelOffense.getImg(), tr);
g2.setPaint(tp);
Rectangle2D r = (Rectangle2D) new Rectangle((int)getMousePosition().getX(), (int)getMousePosition().getY(), 16, 16); //area to fill with texture
g2.fill(r);
System.out.println("test");
}
}
Before you ask - I did move some code to other classes so it's called less often, but that's not the problem. Even if the paint method only draws a rectangle (directly on Graphics g, not Graphics2D), the rectangle flickers.
If anyone could help me figure out a solution, I'd be very thankful!
Note: I know it's probably not very elegant to draw on a JFrame or a subclass of JFrame, but I personally don't know an alternative.
Note 2: According to google/stackoverflow results or threads that I read, I should use a JPanel, which seems to be double-buffered (whatever that is, I didn't really understand that. but then again, it's almost 11 pm here). Hence, I could probably move all my components to a JPanel to solve the issue, but I wanted to try to solve the problem without doing that.
Note 3: Yes, the code belongs to a (strategy) game I'm writing, but considering that the problem is not really related to game development exclusively, I decided to post it here and not at game development stack exchange.

Processing -- moving image leaving trail

I'm working on trying to make an image move in processing, but the image is leaving a trail. The important part which is tripping me up is that I cannot declare the background in draw(), because I have other functions which place images. Here is the relevant code:
void setup()
{
size(752,500);
background = loadImage("prairie.jpg");
background(background);
noStroke();
animal = loadImage("squirrel.png");
bird = loadImage("bird.gif");
rock = loadImage("rock.png");
cloud = loadImage("cloud.png");
jeep = loadImage("jeep.png");
flower = loadImage("flower.png");
}
float jeepX = 752;
float jeepY = 250;
float size = 100;
void draw()
{
image(jeep,150,350,125,125);
image(jeep,jeepX,jeepY,size,size);
jeepX--;
jeepY = jeepY + .25;
size += .25;
image(jeep,jeepX + 1,jeepY - .25, size -.25, size - .25, 0,0,0,0);
if(jeepY > height)
{
jeepX = 752;
jeepY = 250;
size = 100;
}
}
This is for lab and the TA didn't know how, and I didn't have a chance to ask the professor yet.
If no one knows the answer and/or it has something to do with other functions (which place images), i'll post the relevant code.
For moving objects not to leave a trail, you must first clear the frame before redrawing the picture.(don't forget to reset the background if you don't have one)
As it is, it draws one jeep, then another on top of it.
If you don't want the trail, you got clear the background. If not completely, at least part of it, or redraw every image not supposed to move every frame.
Like this:
Sample Code
PImage bg, still, moving;
void setup() {
while ( bg == null) {// got wait as size depends on this...
println("loading bg image...");
bg = loadImage("http://dc489.4shared.com/img/f9EaWk5w/s3/13757197c08/Black_Background_Metal_Hole_-_.jpg");
}
size(bg.width, bg.height);
still = loadImage("http://www.renderosity.com/mod/bcs/photos/Thumb85619.jpg");
moving = loadImage("https://cdn1.iconfinder.com/data/icons/humano2/128x128/apps/alienblaster.png");
}
void draw() {
background(bg);
image(still, 100, 100);
image(moving, 200, frameCount%height);
}
You need to redraw your background in the 'draw' method. To do this, simply add the following line of code to your 'draw' method:
background(red,green,blue);
You can use the Colour Selector in Processing (found under Tools) to find the correct rgb code for the colour you want.
The reason for this is that the draw method is run 60 times a second, whereas the 'setup' method is only run once when the program is executed. As such, when you move the image, if the background colour is not in the 'draw' method, then it will not be redrawn when the image is moved, thus leaving a trail.

How to treat a shape painted with an algorithm like an object?

Ok dear folks, i've got this question and i don't really know a certain way to solve it.
I'm doing like a "Paint application" in java, i know everything is ready, but I need to paint the shapes with Computer Graphics Algorithms.
So, the thing is, once the shape is painted in the container how could I convert it like sort of an "Object" to be able to select the shape and move it around (I have to move it with another algorithm) I just want to know how could I know that some random point clicked in the screen belongs to an object, knowing that, I would be able to fill it(with algorithm).
I was thinking that having a Point class, and a shape class, if i click on the screen, get the coordinates and look within all the shapes and their points, but this may not be very efficient.
Any ideas guys ?
Thanks for the help.
Here is some of my code:
public class Windows extends JFrame{
private JPanel panel;
private JLabel etiqueta,etiqueta2;
public Windows() {
initcomp();
}
public void initcomp()
{
panel = new JPanel();
panel.setBounds(50, 50, 300, 300);
etiqueta = new JLabel("Circulo Trigonometrico");
etiqueta.setBounds(20, 40, 200, 30);
etiqueta2 = new JLabel("Circulo Bresenham");
etiqueta2.setBounds(150, 110, 200, 30);
panel.setLayout(null);
panel.add(etiqueta);
panel.add(etiqueta2);
panel.setBackground(Color.gray);
this.add(panel);
this.setLayout(null);
this.setVisible(true);
this.setSize(400,400);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(Color.red);
g2d.setStroke(new BasicStroke(2));
dibujarCirculo_bresenham(g2d, 50, 260, 260);
dibujarCirculo_trigonometrico(g2d, 50, 130, 200);
}
/*This functions paints a Circle*/
public void dibujarCirculo_trigonometrico(Graphics g,int R,int xc,int yc)
{
int x,y;
for (int i = 0; i < 180; i++) {
double angulo = Math.toRadians(i);
x = (int) (Math.cos(angulo)*R);
y = (int) (Math.sin(angulo)*R);
g.drawLine(x+xc, y+yc, x+xc, y+yc);
g.drawLine((-x+xc), (-y+yc), (-x+xc), (-y+yc));
}
}
I assume that any image is a valid (isn't constrained to a particular set of shapes). To get an contiguous area with similar properties, try using a flood fill.
To colour in or move a particular shape around, you can use flood fill to determine the set of pixels and manipulate the set accordingly. You can set a tolerance for similar hue, etc so that it's not as rigid as in Paint, and becomes more like the magic selection tool in Photoshop.
There are a couple of approaches to take here depending on what precisely you want.
1) is to have objects, one for each drawn thing on screen, with classes like Circle and Rectangle and Polygon so on. They would define methods like paint (how to draw them on screen), isCLickInsideOf (is a click at this point on screen contained by this shape, given size/position/etc?) and so on. Then, to redraw the screen draw each object, and to test if an object is being clicked on ask each object what it thinks.
2) is, if objects have the property of being uniform in colour, you can grab all pixels that make up a shape when the user clicks on one of the pixels by using a floodfill algorithm. Then you can load these into some kind of data structure, move them around as the user moves the mouse around, etc. Also, if every object is guaranteed to have a unique colour, you can test which object is being clicked on by just looking at colour. (Libraries like OpenGL use a trick like this sometimes to determine what object you have clicked on - drawing each object as a flat colour on a hidden frame and testing what pixel colour under the mouse pointer is)

Categories

Resources