Hey Guys I have succesfully made a GUI in java that will scale polygons and circles using a slider. Everything works but I was wondering if there is a way to change the Origin point(Where it scales from). Right now it scales from the corner and I would like it to scale from the middle so I can start it in the middle and it scales out evenly. Also, If anyone could tell me an easy way to replace the Rectangle I have with an Image of some kind so you can scale the Picture up and down would be great! Thank you! Here is my code:
import javax.swing.*;
public class Fred
{
public static void main(String[] args)
{
TheWindow w = new TheWindow();
w.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //X wont close the window with out this line
w.setSize(375,375);
w.setVisible(true);
}
}
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class TheWindow extends JFrame
{
private JSlider slider; //declare slider
private drawRect myPanel; //declare/ create panel
public TheWindow()
{
super("Slider Example"); //make title
myPanel = new drawRect();
myPanel.setBackground(Color.green); //change background color
slider = new JSlider(SwingConstants.VERTICAL, 0, 315, 10);// restrains the slider from scaling square to 0-300 pixels
slider.setMajorTickSpacing(20); //will set tick marks every 10 pixels
slider.setPaintTicks(true); //this actually paints the ticks on the screen
slider.addChangeListener
(
new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
myPanel.setD(slider.getValue()); //Wherever you set the slider, it will pass that value and that will paint on the screen
}
}
);
add(slider, BorderLayout.WEST); //similar to init method, adds slider and panel to GUI
add(myPanel, BorderLayout.CENTER);
}
}
import java.awt.*;
import javax.swing.*;
public class drawRect extends JPanel
{
private int d = 25; //this determines the beginning length of the rect.
public void paintComponent(Graphics g)//paints circle on the screen
{
super.paintComponent(g); //prepares graphic object for drawing
g.fillRect(15,15, d, d); //paints rectangle on screen
//x , y, width, height
}
public void setD(int newD)
{
d = (newD >= 0 ? newD : 10); //if number is less than zero it will use 10 for diameter(compressed if statement)
repaint();
}
public Dimension getPrefferedSize()
{
return new Dimension(200, 200);
}
public Dimension getMinimumSize()
{
return getPrefferedSize();
}
}
Changing the "origin point" so it becomes the center of the "zoom" is basically just the process of subtract half of d from the center point.
So, assuming the the center point is 28 ((25 / 2) + 15), you would simply then subtract d / 2 (25 / 2) from this point, 28 - (25 / 2) = 15 or near enough...
I modified the paintComponent method for testing, so the rectangle is always at the center of the panel, but you can supply arbitrary values in place of the originX and originY
#Override
public void paintComponent(Graphics g)//paints circle on the screen
{
super.paintComponent(g); //prepares graphic object for drawing
int originX = getWidth() / 2;
int originY = getHeight() / 2;
int x = originX - (d / 2);
int y = originY - (d / 2);
System.out.println(x + "x" + y);
g.fillRect(x, y, d, d); //paints rectangle on screen
//x , y, width, height
}
As for scaling an image, you should look at Graphics#drawImage(Image img, int x, int y, int width, int height, ImageObserver observer), beware though, this will scaling the image to the absolute size, it won't keep the image ratio.
A better solution might be to use a double value of between 0 and 1 and multiple the various elements by this value to get the absolute values you want
Related
I am trying to teach myself more about graphics in Java. To do this I'm trying to build a chess game. I've hit my first roadblock at making the board. My thought here is that I would have a extension of JComponent called "Square" that would be my container for both the color of the board square and the piece on that square (if any). To start with I haven't attempted to include any representation of the piece yet, just the square colors. Later on I hope to have an abstract "Pieces" class that is extended by multiple subclasses representing all the different types of pieces, and add those to each Square as applicable.
When I execute the following, I only get one black square in the upper left hand corner.
ChessBoardTest.java
public class ChessBoardTest {
public static void main(String[] args) {
ChessBoard Board = new ChessBoard();
Board.Display();
}
}
ChessBoard.java
public class ChessBoard extends JFrame {
public static final int FRAME_WIDTH = 500;
public static final int FRAME_HEIGHT = 500;
// Declare instance variables
private Square[][] square = new Square[rows][cols];
private final static int rows = 8;
private final static int cols = 8;
public ChessBoard() {
}
public void Display() {
JPanel Board_Layout = new JPanel();
Board_Layout.setLayout(new GridLayout(8,8));
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++)
{
if((i+j) % 2 == 0) {
square[i][j] = new Square(1);
Board_Layout.add(square[i][j]);
} else {
square[i][j] = new Square(0);
Board_Layout.add(square[i][j]);
}
}
}
setTitle("Chess Mod");
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(Board_Layout);
setVisible(true);
}
public void messageBox(String pMessage) {
JOptionPane.showMessageDialog(this, pMessage, "Message", JOptionPane.PLAIN_MESSAGE);
}
}
Square.java
public class Square extends JComponent {
private int color;
public Square(int c) {
this.color=c;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (this.color == 1) {
g.setColor(new Color(0,0,0));
} else {
g.setColor(new Color(255,255,255));
}
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
}
}
I only get one black square in the upper left hand corner.
That's mainly because of the following call:
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
getX() returns the horizontal pixel offset/location of the Component which is invoked upon, relative to the Container that contains that Component. getY() accordingly returns the vertical pixel offset/location of the Component which is invoked upon, relative to the Container that contains the Component.
getWidth() and getHeight() return the size of the Component.
So imagine that the Component at row with index 2 and column with index 3, will have its coordinates at about x == 3 * w / 8 and y == 2 * h / 8 where w and h is the size (width and height respectively) of the parent Container (ie the Board_Layout panel). Let's assume that Board_Layout has a size of 300x300 when you show the graphical user interface... This means that the Square at the location I mentioned will only paint the region which starts at x == 112 and y == 75 and expands at one 8th of the width (and height) of Board_Layout (because there are 8 rows and 8 columns in the grid). But the size of the Square itself is also at one 8th of the width (and height) of Board_Layout, ie about 37x37. So the painted region which starts and expands from the location 112,75 will not be shown at all (because it lies completely outside the Square's size).
Only the top left Square will have some paint on it because its bounds in the parent happen to intersect the drawn region.
To fix this, the location given at the Graphics object should be relative to each Square and not its parent Board_Layout. For example:
g.fillRect(0, 0, getWidth(), getHeight());
I'm a noob programmer, and I'm working on a little project that involves a 2D grid of 1000 x 1000 boolean values that change based on an instruction pattern. "After x instructions, how many values in the grid are true?" That kind of thing.
I want to put a little spin on it and render the values as a grid of pixels which are black if their corresponding values are false and white if they're true and that animates in real time as instructions are processed, but I'm pretty lost -- I've never dabbled with 2D graphics in Java. I've read through Oracle's tutorial, which helped, but the way I'm doing things is sufficiently different from its demo that I still feel lost.
My most immediate problem is that I can't even seem to initialize a grid of 1000 x 1000 black pixels using a BufferedImage. Running my code yields a very tiny window with nothing (grayness) in it. Can anyone tell me what I'm doing wrong and suggest how to proceed? My code follows:
import java.awt.image.BufferedImage;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PixelGrid extends JPanel {
private BufferedImage grid;
// Ctor initializing a grid of binary (black or white) pixels
public PixelGrid(int width, int height) {
grid = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
}
/**
* Fill an area with a given color
* #param color 0 for black; 1 for white
* #param x1 Starting x coordinate
* #param y1 Starting y coordinate
* #param x2 Ending x coordinate
* #param y2 Ending y coordinate
*/
public void toggleBlock(int color, int x1, int y1, int x2, int y2) {
if (color == 0) {
color = Color.BLACK.getRGB();
}
else {
color = Color.WHITE.getRGB();
}
for (int x = x1; x <= x2; x++) {
for (int y = y1; y <= y2; y++) {
grid.setRGB(x, y, color);
}
}
}
// Clear the grid (set all pixels to black)
public void clear() {
toggleBlock(0, 0, 0, grid.getWidth() - 1, grid.getHeight() - 1);
}
public static void main(String[] args) {
int width = 1000;
int height = 1000;
PixelGrid aGrid = new PixelGrid(width, height);
JFrame window = new JFrame("A Wild Pixel Grid Appears!");
window.add(aGrid); // Incorporates the pixel grid into the window
window.pack(); // Resizes the window to fit its content
window.setVisible(true); // Makes the window visible
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Note that it doesn't yet deal at all with an actual 2D array of booleans or instruction processing; I'm pretty sure I can handle that on my own, but, for now, I'm just trying to understand how to set up the graphical component.
Your code creates a BufferedImage, but then doesn't do anything with it (graphically). A few options:
Option 1: Override paintComponent of the PixelGrid class and draw the image to the JPanel
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(grid, 0, 0, this);
}
Option 2: Use a JLabel and ImageIcon
JLabel label = new JLabel(new ImageIcon(grid));
add(label);
In either case, you will have to call repaint on the Component every time the BufferedImage is changed
//some code
grid.setRGB(x, y, color);
//some more code
repaint();//or label.repaint() if Option 2
I'm writing a program taken from the TV show, THE OFFICE, when they're sitting in the conference room and watching the bouncing DVD logo on the screen try to hit the corner. The square is supposed to change color when it hits an edge.
However, I'm running into a few issues.
Issue one: The Square sometimes bounces off an edge. Other times it sinks, and I can't figure out why.
Issue two: I'm not sure how to change the color of the square when it hits the edge.
Issue three: I'm trying to learn how to make a JFRAME fullscreen. And not just fullscreen on my screen but on anyone's.
THE CODE HAS BEEN POSTED TO AN ONLINE IDE FOR EASIER READING. That can be found HERE
Otherwise if you're too busy for that link. Here it is posted below.
import java.util.Random;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class BouncingMischievousSquare extends JPanel implements ActionListener {
private static final int SQUARE_SIZE = 40;
private static final int SPEED_OF_SQUARE = 6;
private int xPosit, yPosit;
private int xSpeed, ySpeed;
BouncingMischievousSquare(){
//speed direction
xSpeed = SPEED_OF_SQUARE;
ySpeed = -SPEED_OF_SQUARE;
//a timer for repaint
//http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html
Timer timer = new Timer(100, this);
timer.start();
}
public void actionPerformed(ActionEvent e){
//Screensize
int width = getWidth();
int height = getHeight();
xPosit += xSpeed;
yPosit += ySpeed;
//test xAxis
if(xPosit < 0){
xPosit = 0;
xSpeed = SPEED_OF_SQUARE;
}
else if(xPosit > width - SQUARE_SIZE){
xPosit = width - SQUARE_SIZE;
xSpeed = -SPEED_OF_SQUARE;
}
if(yPosit < 0){
yPosit = 0;
ySpeed = SPEED_OF_SQUARE;
}
else if(yPosit > height - SQUARE_SIZE){
xPosit = height - SQUARE_SIZE;
xSpeed = -SPEED_OF_SQUARE;
}
//ask the computer gods to redraw the square
repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(xPosit, yPosit, SQUARE_SIZE, SQUARE_SIZE );
}
}
MAIN CLASS
import javax.swing.*;
public class MischievousMain {
public static void main(String[] args) {
JFrame frame = new JFrame("Bouncing Cube");
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// mischievous square input
frame.add(new BouncingMischievousSquare());
frame.setVisible(true);
}
}
Anyways, Thanks for taking the time to read through my code. It's appreciated. I'm really interested in different ways to go about this.
Issue one: The Square sometimes bounces off an edge. Other times it
sinks, and I can't figure out why.
You'll hate yourself for this, but
} else if (yPosit > height - SQUARE_SIZE) {
xPosit = height - SQUARE_SIZE;
xSpeed = -SPEED_OF_SQUARE;
}
Should be...
} else if (yPosit > height - SQUARE_SIZE) {
yPosit = height - SQUARE_SIZE;
ySpeed = -SPEED_OF_SQUARE;
}
You were using xPosyit and xSpeed instead of yPosyit and ySpeed...
Issue two: I'm not sure how to change the color of the square when it
hits the edge.
Basically, whenever you detect a edge collision and change direction, simple change the panel's foreground color to something else...
This might require you to have a list of colors from which you can randomly pick or simply randomly generate the color
Then in your paintComponent method, simple use g.setColor(getForeground()) before you fill the rect...
...ps...
To make life easier, you could just write a method that either generates a random color or sets the foreground to a random color, for example...
protected void randomiseColor() {
int red = (int) (Math.round(Math.random() * 255));
int green = (int) (Math.round(Math.random() * 255));
int blue = (int) (Math.round(Math.random() * 255));
setForeground(new Color(red, green, blue));
}
Issue three: I'm trying to learn how to make a JFRAME fullscreen. And
not just fullscreen on my screen but on anyone's.
Take a look at Full-Screen Exclusive Mode API
I'm making a simple Kakuro application in Java Swing and I have used JButtons as cells. I've done everything from generating the grid (setBackground(Color.BLACK) and setBackground(Color.WHITE)) to filling with unique numbers.
But the problem is, I don't know how to paint the "clues" at the ends of JButtons. What I want is similar to:
Sometimes the numbers may appear on only 3 sides, 2 sides or even 1 side.
I thought of setting background images, but its not possible as the numbers are sums of dynamically generated numbers (the grid is dynamic).
So any idea how to get this kind of JButton? Or if its not possible, what other options do I have?
Thanks a lot in advance (I'm really stuck).
very simple and confortable way is add JLabels to the JButton by using BorderLayout,
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class FourLabelsInButton {
private JFrame frame;
private JButton myButton1;
private JLabel myButton1_Label_N;
private JLabel myButton1_Label_E;
private JLabel myButton1_Label_W;
private JLabel myButton1_Label_S = new JLabel();
public FourLabelsInButton() {
myButton1_Label_N = new JLabel("45");
myButton1_Label_N.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_N.setForeground(Color.red);
myButton1_Label_E = new JLabel("1");
myButton1_Label_E.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_E.setForeground(Color.red);
myButton1_Label_W = new JLabel("9");
myButton1_Label_W.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_W.setForeground(Color.red);
myButton1_Label_S = new JLabel("21");
myButton1_Label_S.setHorizontalAlignment(JLabel.CENTER);
myButton1_Label_S.setForeground(Color.red);
myButton1 = new JButton();
myButton1.setBackground(Color.black);
myButton1.setLayout(new BorderLayout());
myButton1.add(myButton1_Label_N, BorderLayout.NORTH);
myButton1.add(myButton1_Label_E, BorderLayout.EAST);
myButton1.add(myButton1_Label_W, BorderLayout.WEST);
myButton1.add(myButton1_Label_S, BorderLayout.SOUTH);
frame = new JFrame();
frame.add(myButton1);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
FourLabelsInButton ggg = new FourLabelsInButton();
}
});
}
}
I thought of setting background images, but its not possible as the numbers are sums of dynamically generated numbers (the grid is dynamic).
The images for the buttons can also be generated dynamically.
You may also use a custom component. For this case the painting can be implemented quite straightforward:
class KakuroComponent extends JComponent {
private final int[] numbers;
public KakuroComponent(int... numbers) {
this.numbers = numbers;
}
#Override
public void paintComponent(Graphics g) {
int w = getWidth();
int h = getWidth();
g.setColor(Color.black);
g.fillRect(0, 0, w, h);
g.setColor(Color.white);
g.drawLine(0, 0, w, h);
g.drawLine(w - 1, 0, 0, h - 1);
if (numbers[0] > 0) // if there is a top number
drawStringCentered(g, String.valueOf(numbers[0]), w / 2, h / 6);
if (numbers[1] > 0) // if there is a left number
drawStringCentered(g, String.valueOf(numbers[1]), w / 6, h / 2);
if (numbers[2] > 0) // if there is a right number
drawStringCentered(g, String.valueOf(numbers[2]), w * 5 / 6, h / 2);
if (numbers[3] > 0) // if there is a bottom number
drawStringCentered(g, String.valueOf(numbers[3]), w / 2, h * 5 / 6);
}
void drawStringCentered(Graphics g, String s, int x, int y) {
Rectangle2D bounds = g.getFontMetrics().getStringBounds(s, g);
g.drawString(s, (int) (x - bounds.getCenterX()), (int) (y - bounds.getCenterY()));
}
}
There shouldn't be any reason you can't simply draw anything you want in the JButton by overwriting the paint() method.
public class KakuroSquare extends JButton
{
/* ... */
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
/* Your paint logic. */
}
}
im trying to make a swing app that draws a function's graph(simple for now ex. x+2)
but i'm having problems to make mathematical coordinates of my points depending on screen coordinates .
I want it to simply draw a line that goes from P1(0,1) to P2(1,2) inside my graph.
here is my code :
import java.awt.*;
import javax.swing.*;
public class Graph extends JPanel {
protected void paintComponent(Graphics g) {
int YP1,YP2;
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
int h = getHeight();
int w = getWidth();
// Draw axeX.
g2.draw(new Line2D.Double(0, h/2, w, h/2)); //to make axisX in the middle
// Draw axeY.
g2.draw(new Line2D.Double(w/2,h,w/2,0));//to make axisY in the middle of the panel
//line between P1(0,1) and P2(1,2) to draw function x+1
Point2D P1 = new Point2D.Double(w/2,(h/2)+1);
Point2D P2 = new Point2D.Double((w/2)+1,(h/2)+2);
g2.draw(new Line2D.Double(P1,P2));
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new Graphe());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
thanks.
import java.awt.*;
import javax.swing.*;
public class Graph extends JPanel {
private static final int UNIT = 20;
protected void paintComponent(Graphics g) {
int YP1,YP2;
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
int h = getHeight();
int w = getWidth();
// Draw axeX.
g2.draw(new Line2D.Double(0, h/2, w, h/2)); //to make axisX in the middle
// Draw axeY.
g2.draw(new Line2D.Double(w/2,h,w/2,0));//to make axisY in the middle of the panel
//line between P1(0,1) and P2(1,2) to draw function x+1
Point2D P1 = new Point2D.Double(w/2,(h/2)+ UNIT);
Point2D P2 = new Point2D.Double((w/2)+ UNIT,(h/2)+ 2*UNIT); //considering 20 = 1 unit in your syste,
g2.draw(new Line2D.Double(P1,P2));
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new Graphe());
f.setSize(400,400);
f.setLocation(200,200);
f.setVisible(true);
}
}
Tryout this code read comments to get the solution
The center of your coordinate system (0,0) is painted at (w/2, h/2). The missing part is the scale, in other words: how many pixels make one unit on the x axis and y axis.
So usually you multiply your unit value by the scaling factor (like 10, if you want 10 pixel per unit) and add the offset of the axis from the left or lower boundary. The annoying part is the (0,0) on screen coordinates is the upper left corner and height counts from top to bottom (reversed y axis). That makes it a bit more complicated:
xOnScreenPos = (xUnit * xScale) + xScaleOffset;
yOnScreenPos = -(yUnit * yScale) + yScaleOffset;