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);
}
}
}
Related
I am new to programming and trying to write a graphics program in java that displays ovals of different sizes and colors, however, I am not able to get the program to display the ovals in applet window. Does anyone have any suggestions/input on where I went wrong here? Please see an example of my paint method below:
public void paint(Graphics g)
{
for(int i=0; i<n; i++)
{
x[i] = (int)(600* Math.random() +1);
y[i] = (int)(600* Math.random() +1);
}
int c= (int)(255*Math.random()); //random foreground color
int a= (int)(255*Math.random());
int t= (int)(255*Math.random());
Color f = new Color(c,a,t);//variables have been declared in init
g.setColor(f);
g.fillOval(rand(0, 600), rand(0, 600), r = rand(5, 100), r);
sleep(100);
cnt += 1;
if(cnt >= 500) clearScreen();
else update(g);
}
I modified a recent school project (we were supposed to make a hot air balloon) so excuse the naming of some of the stuff:
import java.awt.*;
import javax.swing.*;
public class Balloon extends JComponent {
public static void main(String args[]){
JFrame frame = new JFrame("balloons");
frame.setSize(200,200);
frame.setVisible(true);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Balloon balloon = new Balloon();
frame.setContentPane(balloon);
}
public void paint(Graphics g){
super.paint(g);
for(int i = 0; i<20; i++){
int c= (int)(255*random()); //random foreground color
int a= (int)(255*random());
int t= (int)(255*random());
g.setColor(new Color(c,a,t));
g.fillOval((int)(200*random()),(int)(200*random()),(int)(30*random()),(int)(30*random()));
}
}
public double random(){
return Math.random();
}
}
Its rather small at the moment so you may want to change around some of the variables... however it does what you asked.
In terms of where you went wrong... it appears you have a loop that put values into two arrays... however I don't see a second array that goes through and draws all the ovals... In my code, I generate all the coordinates, colours, and print it out all at once.
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);
}
}
Hi guys I know this is a common one, but i've searched around quite a bit and can't seem to get my paint method to draw over the components in my JPanel.
My paint method is linked to a button press. It prints out about 1500 data points and their assigned cluster (kmeans)
package eye_pathscanner;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class ReplayData extends JPanel {
// replay type can be parsed as argument into draw() to change paints behaviour
private int ReplayType = 0;
public ArrayList<DataPoint> points;
//Initialise records
public ReplayData()
{
points = new ArrayList<DataPoint>();
}
public void ReplaceData() {
points = new ArrayList<DataPoint>();
}
public void PrintPoints()
{
}
public void addPoint(DataPoint point) {
points.add(point);
}
#Override
public void paintComponent(Graphics g) {
Color black = new Color(0, 0, 0);
Random random = new Random();
final float luminance = 0.9f;
if (ReplayType == 1)
{
super.paintComponent(g);
for (int x = 0; x < kMeans.NUM_CLUSTERS; x++)
{
// Saturation ideal between 0.1 and 0.3
float saturation = (random.nextInt(2000) + 1000) / 10000f;
float hue = random.nextFloat();
Color cluster_colour = Color.getHSBColor(hue, saturation, luminance);
// Randomise the border colour
saturation = (random.nextInt(2000) + 1000) / 10000f;
hue = random.nextFloat();
Color cluster_colour_border = Color.getHSBColor(hue, saturation, luminance);
double centroidx = kMeans.centroids.get(x).getmX();
double centroidy = kMeans.centroids.get(x).getmY();
for (int i = 0; i < kMeans.TOTAL_DATA; i++)
if(kMeans.dataSet.get(i).cluster() == x){
// Set each child data point to a colour so you can see which cluster it belongs too
g.setColor(cluster_colour);
g.fillRect((int)TrackerData.getRecordNumber(i).getEyeX(),(int)TrackerData.getRecordNumber(i).getEyeY(), 3, 3);
g.drawLine((int)kMeans.dataSet.get(i).X(),(int)kMeans.dataSet.get(i).Y(), (int)centroidx, (int)centroidy);
//g.setColor(Color.black);
g.setColor(cluster_colour_border);
g.drawRect((int)TrackerData.getRecordNumber(i).getEyeX(),(int)TrackerData.getRecordNumber(i).getEyeY(), 3, 3);
}
g.setColor(black);
g.fillOval((int)centroidx,(int)centroidy, 15, 15);
}
}
}
// 1 for K-means with different colour cluster groups
// 2 for slow replay
public void draw(int i) {
ReplayType = i;
repaint();
}
}
This code all works great for me, however I lose the image that was drawn beneath the paint after using it. I can maximize the page and the image shows up again but over the paint? (can anyone explain this behavior).
JLabel picture_panel = new JLabel();
picture_panel.setBounds(70, 130, 640, 797);
picture_panel.addMouseListener(this);
BufferedImage img = null;
try
{
img = ImageIO.read(new File("C:/Eyetracker_Images/Random.jpg")); // eventually C:\\ImageTest\\pic2.jpg
ImageIcon icon = new ImageIcon(img);
picture_panel.setIcon(icon);
}
catch (IOException e)
{
e.printStackTrace();
}
Heres where my image is created, and it's called as shown below on one my buttons
replayData.setBounds(0, 0, 802, 977);
frame.getContentPane().add(replayData);
replayData.draw(1);
Any help would be much appreciated, Thanks.
This maybe an artifact of using setBounds(). Moreover, you appear to be using the default layout manager without invoking pack() on the enclosing container.
As you already have a BufferedImage containing the rendered image, simply invoke drawImage() in your implementation of paintComponent(). Examples are seen here, here and here.
Also consider overriding the getPreferredSize() method of ReplayData, as suggested here and here, to establish its dimensions.
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);
}
}
I wrote a checkerboard program (shown below). My problem is that I can't figure out how to center it with resize, and have it resize proportionately.
I added in a short statement. Int resize (shown below) I did something similiar with a previous program regarding a bullseye where I used a radius. I just haven't the slightest clue how to implement that in here.
import java.awt.*;
import javax.swing.JComponent;
public class CheckerboardComponent extends JComponent {
#Override
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.RED);
int s = 12;
int x = s;
int y = s;
// int resize = Math.min(this.getHeight(), this.getWidth()) / 8 ;
for (int i = 0; i < 8; i++) {
// one row
for (int j = 0; j < 8; j++) {
g2.fill(new Rectangle(x, y, 4 * s, 4 * s) );
x += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
x = s;
y += 4 * s;
if(g2.getColor().equals(Color.RED)){
g2.setColor(Color.BLACK);
}else{
g2.setColor(Color.RED);
}
}
}
}
here is a viewer program
import javax.swing.*;
public class CheckersViewer {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(430, 450);
frame.setTitle("Checkerboard");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CheckerboardComponent component = new CheckerboardComponent();
frame.add(component);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Hmm... Here's one idea then, though it probably isn't a good one (I'm also not that good with jComponent and jFrame, so there's probably a better way and a more suited person)
I believe the component object has a built-in method called getSize(). If you can relate the size of the rectangle to the size of the window, then it could be resizable. Obviously there would be more code and arguments, but for example:
public void drawStuff(Component c)
{
...
Dimension size = c.getSize();
double RectWidth = (size.width)*(.05);
...
}
check this out for more complete examples:
http://www.javadocexamples.com/java/awt/Component/getSize().html
And I apologize I can't be of more help.