Dynamic scale Sierpinski Triangle - java

For class I have been asked to make a Sierpinski Triangle drawer which will dynamically rescale as the user changes the window size, by recursively subdividing a square region of the panel until int is 1x1 pixel, then coloring that pixel. I think that I'm nearly there, but since my understanding of object oriented programming is fuzzy at best, I'm not entirely clear about how to actually draw the individual pixels. The paintComponent method is what will be called each time the window is resized correct? as such i need it to call sierMaker and create the triangle, but if sierMaker then calls paintsComponent to draw the pixels wont it enter an infinite loop? I have no doubt that I'm missing something obvious here, would appreciate some help with figuring out what my error(s) are though. Be merciful to a newbie?
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
public class Triangle extends JPanel {
public int getsize(){
int wi = this.getWidth();
int he = this.getHeight();
int size = 0;
if (wi <= he) {
size = wi;
} else {
size = he; }
return size;
}
public void sierMaker(int x, int y, int side) {
//if is 1x1, draw it, else subdivide(WIP)
if (side == 1) {
//create rectangle object (x,y,side,side), and pass it to paintComponent. This is where I need help.
} else {
//was too large, break into 3 portions and check again
sierMaker(x/2, y, side/2);
sierMaker(x,y/2,side/2);
sierMaker(x/2,y/2,side/2);
}
}
//paintComponent method to draw individual pixels once input sqare is subdived into small enough portions by recursion
public void paintComponent(Graphics g) {
sierMaker(0,0,getsize());
}
public static void main(String[] args) {
//set initial size of panel to monitor resolution
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
//initalize JFrame
JFrame display = new JFrame();
display.setTitle("Sierpinski Triangles");
display.setBounds(0,0,screenSize.width, screenSize.height);
display.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Triangle panel = new Triangle();
display.add(panel);
display.setVisible(true);
}
}

Related

Adding multiple circles to a JFrame? (Java)

I am trying to draw circles to JFrame with different positions, in this case in a grid-like pattern.
I don't seem to have trouble drawing a single circle with an x,y position, however, when I try to draw multiple circles with different positions the other circles' positions come out obscured.
In the code below, I have two arrays: XPlacements and YPlacements that contain different X and Y positions to form a grid. For each X position there should be circles created at that X position with varying Y positions (vice versa).
When I only make the below code draw one circle, where XPlacements = {10} YPlacements = {100}, it draws a circle that appears to be at some (10,100) from the top left. Similarly when I add multiple X positions but a single Y position nothing seems to be obscured. However, when I add multiple Y positions, every descending row of circles seems to be more and more pushed to the right.
When I run it, it obscures like this: http://imgur.com/HHjhvPD
I can't seem to make it less obscured by changing the values of the JFrame. All the JFrame circle tutorials I can find only deal with 1 circle, and I don't have any issues when I use 1 circle (or only 1 row of circles).
Does anyone know why the code below isn't producing a grid like pattern?
Thanks.
public class Circle extends Canvas {
int XPos;
int YPos;
public void SetPosition(int x, int y) {
this.XPos = x;
this.YPos = y;
repaint();
}
public void paint(Graphics g) {
System.out.println("Filling oval with position ("+XPos+","+YPos+")");
g.fillOval(XPos, YPos, 15, 15);
}
}
public class MainFile extends JFrame {
static int[] XPlacements = {10,20,30};
static int[] YPlacements = {100,200,300};
static Circle[] Circles = new Circle[1000];
static int Circle_Count = 0;
public static void main(String[] args) {
JFrame frame = new JFrame("Grid of circles");
frame.setLayout(new GridLayout(1,1));
frame.setSize(800, 800);
for(int x=0;x<XPlacements.length;x++) {
for(int y=0;y<YPlacements.length;y++) {
System.out.println("Creating new circle "+Circle_Count+" with position "+XPlacements[x]+","+YPlacements[y]);
Circles[Circle_Count] = new Circle();
Circles[Circle_Count].SetPosition(XPlacements[x],YPlacements[y]);
frame.add(Circles[Circle_Count]);
Circle_Count++;
}
}
frame.setVisible(true);
}
}
First of all this is a Swing application so custom painting should be done by overriding paintComponent() of a JPanel. A Canvas is an AWT component that should not be used in a Swing application.
If you want to draw on a component then the custom painting is always done relative to offset (0, 0). So in your case the code would be:
//g.fillOval(XPos, YPos, 15, 15);
g.fillOval(0, 0, 15, 15);
Then you need to override the getPreferredSize() method of your class to set the size of the component:
#Override
public Dimension getPreferredSize()
{
return new Dimension(15, 15);
}
Read the section from the Swing tutorial on Custom Painting for more informations and working examples.
Now the layout manager has information about the component and can position each component on the panel:
So the code to add the Circles to the frame would be something like:
frame.setLayout( new GridLayout(3, 3, 50, 50) );
for (int i = 0; i < 9; i++)
{
frame.add( new Circle() );
}
This will create a 3x3 grid with a gap of 50 pixels between each component.

Simple way to provide a scrollable image view (waveform) in Java without using ImageIcon?

Is there a Java-only way to show larger pictures in a JScrollPane? I don't want to reinvent the wheel and I'm already struggling at showing 32768x400 images using the ImageIcon in a JLabel trick because there seem to be limits regarding the ImageIcon that are platform dependent. Ubuntu 16.10 won't show any ImageIcon of the size 32768x400, though it shows smaller ones. Win10 shows them all.... and there is not even any error output of any sorts, which is terrible because I just wasted time searching for the problem.
So is there any easy solution to this that does not require me to reinvent the wheel?
In particular, I want to display waveforms, ie. an array of floats, so there is actually no need to have an overall image at all.
I believe this shows how to do what you want. Note how the Graph component has a width of 65535. This could be further optimized by only drawing the visible part of the graph as you scroll, but it's fairly fast as it is.
import java.awt.*;
import javax.swing.*;
import java.util.function.Function;
class Graph extends JComponent {
private Function<Double, Double> fun;
public Graph(Function<Double, Double> fun) {
this.fun = fun;
setPreferredSize(new Dimension(65535, 300));
}
public void paintComponent(Graphics g) {
// clear background
g.setColor(Color.white);
Rectangle bounds = getBounds();
int w = bounds.width;
int h = bounds.height;
g.fillRect(bounds.x, bounds.y, w, h);
// draw the graph
int prevx = 0;
int prevy = fun.apply((double)prevx).intValue();
g.setColor(Color.black);
for (int i=1; i<w; i++) {
int y = fun.apply((double)i).intValue();
g.drawLine(prevx, prevy, i, y);
prevx = i;
prevy = y;
}
}
}
public class Wf {
public static void main(String[] args) {
JFrame f = new JFrame();
// we're going to draw A sine wave for the width of the
// whole Graph component
Graph graph = new Graph(x -> Math.sin(x/(2*Math.PI))*100+200);
JScrollPane jsp = new JScrollPane(graph);
f.setContentPane(jsp);
f.setSize(800, 600);
f.setVisible(true);
}
}

Animating a Grid of Pixels in Java

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

Java JPanel Scaling

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

Java Challenge on A Gradient Color Canvas

This is probably an elementary question. However, I have completed reading the 9th Chapter of Java Programming for the Absolute Beginner and have approached the Challenges section. I cannot quite get the progam to show a gradient from dark to light.
The question asks:
"Create a Canvas that paints a gradient that's dark on one side and slowly gets lighter
as it moves to the other side."
I have looked at the Java Challenge on Creating a Canvas page (which I asked about before) and got a better understanding of creating a color gradient canvas, however, I am still having great difficulty.
I think that my main problem is how to get the gray colors in between as the program shows a completely black square or when run with just the first for loop, a completely white square. I THINK THAT MY FOR LOOPS ARE PROBLEMATIC AND DO NOT CORRECTLY IDENTIFY THE VARIABLES.
An answer to this question can potentially aid many new Java programmers in understanding Graphics and Canvas.
I do not know JFrame, Swing, Points, JPanels, BufferedImage, or GradientPaint.
Thank you very much for your time and cooperation reagrding this matter.
HERE IS THE CODE:
import java.awt.*;
public class RandomColorSquare extends GUIFrame {
Canvas slight;
public final static int MIN = 0,
MAX = 225;
public RandomColorSquare(int r, int g, int b) {
super("Random Color Square");
r = r >= MIN && r <= MAX ? r : MIN;
g = g >= MIN && g <= MAX ? g : MIN;
b = r >= MIN && b <= MAX ? b : MIN;
slight = new Canvas();
slight.setBackground(new Color(r,g, b));
slight.setSize(200, 150);
add(slight, BorderLayout.CENTER);
for(r=0; r<225; r++) {
Color c = slight.getBackground().brighter();
slight.setBackground(c);
}
for (g=0; g<225; g++) {
Color d = slight.getBackground().darker();
slight.setBackground(d);
}
for (b=0; b<225; b++) {
Color e = slight.getBackground().darker();
slight.setBackground(e);
}
pack();
setVisible(true);
}
public static void main(String args[]) {
if (args.length != 3) {
new RandomColorSquare(0, 0, 0);
}
else {
new RandomColorSquare(Integer.parseInt(args[0]), Integer.parseInt(args[1]),
Integer.parseInt(args[2]));
}
}
}
First of all, as I mentioned in the comment, when you setBackground you are changing the background of the Canvas, not adding to it. So whatever you set it to last is what you see. In your case, that is the darkest form of blue, which is just black. If you comment out the last two loops, you get a white background (the brightest red).
However. Using only what you know this is the best I can come up with. It involves creating your own custom Canvas, which I called CustomCanvas. In there, you can override the paint method and keep drawing progressively lighter filled rectangles across the screen. Here's a small sample to help you understand what I mean:
class CustomeCanvas extends Canvas{
public void paint(Graphics g){
Color background = new Color(30,30,120); //Set this accordingly
for(int i=0;i<getWidth();i++){
g.setColor(background);
background = getBrighter(background);
g.fillRect(i,0, 1, getHeight());
}
}
private Color getBrighter(Color c) {
int r = c.getRed();
int g = c.getGreen();
int b = c.getBlue();
if(r< MAX) r+=1;
if(g< MAX) g+=1;
if(b< MAX) b+=1;
return new Color(r,g,b);
}
}
Which produces this background:
I still recommend reading about GradientPaint which makes this process a lot easier and nicer.
You can override paint() in your Canvas in a manner similar to how this example does for Panel. In your implementation, use drawImage() to render a BufferedImage in which you've used setRGB() to construct your gradient.
Addendum: The example below illustrates the approach by creating a random image. You can create a gradient similarly.
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
/** #see https://stackoverflow.com/a/14096121/230513 */
public class AWTImage {
public static void main(String[] args) throws IOException {
Frame frame = new Frame();
frame.add(new ImageCanvas());
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
frame.pack();
frame.setVisible(true);
}
private static class ImageCanvas extends Canvas {
private static final Random r = new Random();
private BufferedImage image;
public ImageCanvas() {
image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
for (int row = 0; row < image.getHeight(); row++) {
for (int col = 0; col < image.getWidth(); col++) {
image.setRGB(col, row, r.nextInt());
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(), image.getHeight());
}
#Override
public void paint(Graphics g) {
g.drawImage(image, 0, 0, this);
}
}
}

Categories

Resources