I am trying to implement a JPanel (that is added to a JScrollPane). The idea is that on JPanel a series of rectangles will be drawn. One of these rectangles have a different color. The idea is that when the application runs, I should be able to add more of these rectangles(if wanted) or move among the ones that are currently drawn. I have left/right move buttons that will allow me to move among the rectangles. Now the problems is that when I can move among the buttons, but JScrollPane doesn't move when JPanel is being updated. As can be seen in the picture below, suppose I am in the rectangle with value [a], that has the color orange. Now I can move to the left or the right but the JScrollPane stays the same. How can I make JScrollPane move with the rectangles?
The panel screenshot
I have a file (TapeArea) that does all the drawing and a file (TapePanel) that bundles 3 of the TapeArea instances together.
import java.awt.Color;
import javax.swing.Timer;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowListener;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
public class TapeArea extends JPanel {
private final Color BG_COLOR = new Color(200,200,200);
private final Color DEFAULT_CELL_COLOR = Color.white;
private final Color CURRENT_CELL_COLOR = Color.orange;
private final Color CELL_INDEX_COLOR = new Color(0, 130, 0);
private final int FONT_STYLE = Font.BOLD;
private final String FONT_NAME = "Monotype";
private final double INITIAL_OFFSET = -1.5;
int cellWidth = 40;
int cellHeight = 40;
int fontSize = 20;
boolean tapeInit = false;
int leftMostCell = 0, rightMostCell = 0;
double newLeftCellWidth = 0, newRightCellWidth = 0;
boolean newLeftCell = false, newRightCell = false;
Color currentTextColor = Color.black;
double offset = INITIAL_OFFSET;
int origin = 0;
Dimension areaSize;
int filler;
Tape tape;
FlowLayout layout;
int x = 10; //Start Drawing from X=10
int delay = 500; //milliseconds
public TapeArea(Tape t){
tape = t;
layout = new FlowLayout();
setLayout(layout);
setPreferredSize(new Dimension(1200,50));
// ActionListener counter = new ActionListener() {
// public void actionPerformed(ActionEvent evt)
// {
// stepOneTapeCell();
// repaint();
// x++;
// }};
// new Timer(delay, counter).start();
}
public void paintComponent(Graphics g){
int i,drawPos;
int yAlign;
int fontScalingFactor;
int stringWidth, stringHeight;
int index = 0, startAt, cellsToDraw, currentPosition;
int tapeLength;
String symbol;
FontRenderContext DEFAULT_FONT_RENDER_CONTEXT =
new FontRenderContext(null, false, false);
Rectangle2D charBounds;
Graphics2D g2d = (Graphics2D) g;
super.paintComponent(g2d);
if(tape == null)
return;
g2d.setColor(BG_COLOR);
g2d.fillRect(0,0,getWidth(), getHeight());
tapeLength = tape.getSize();
if(areaSize != null)
if(areaSize.width != getSize().width || areaSize.height != getSize().height)
tapeInit = false;
areaSize = getSize();
yAlign = areaSize.height / 2;
cellWidth = getHeight() - 2;
if(cellWidth > 40) {
cellWidth = 40;
}
cellHeight = cellWidth;
fontSize = cellWidth / 2;
if(newLeftCell) {
startAt = 1;
cellsToDraw = tapeLength - 1;
currentPosition = 0;
} else if(newRightCell) {
startAt = 0;
cellsToDraw = tapeLength - 1;
currentPosition = tapeLength - 2;
} else {
startAt = 0;
cellsToDraw = tapeLength;
currentPosition = tape.getCurrentPosition();
}
currentPosition = tape.getCurrentPosition();
//determine the number of cells to left and right on the tape
if(!tapeInit){
for(filler = 0; cellWidth * (1 + 2*filler) <= areaSize.width; filler++);
filler += 2;
leftMostCell = currentPosition - filler;
rightMostCell = leftMostCell + 2*filler;
while(-leftMostCell < rightMostCell - tapeLength - 1 && 0 < rightMostCell - tapeLength - 1) {
leftMostCell--;
rightMostCell--;
}
while(-leftMostCell > rightMostCell - tapeLength + 1 && leftMostCell < 0) {
leftMostCell++;
rightMostCell++;
}
}//end of if(!tapeInit)
if(origin != tape.getOrigin()){
leftMostCell++;
rightMostCell++;
}
origin = tape.getOrigin();
tapeInit = true;
//draw tape cells
for(drawPos = 0, i = leftMostCell; i <= rightMostCell; i++, drawPos++){
//what symbol to be drawn on the cell
if(i >= 0 && i < tapeLength)
symbol = (String) tape.getSymbolAt(i);
else
symbol = tape.getFillSymbol();
//indicate current tape cell by coloring it
if(i == currentPosition)
g2d.setColor(CURRENT_CELL_COLOR);
else
g2d.setColor(DEFAULT_CELL_COLOR);
g2d.fillRect((int)((newLeftCellWidth + drawPos + offset) * cellWidth), yAlign - cellHeight/2,
cellWidth, cellHeight);
g2d.setColor(Color.black);
g2d.drawRoundRect((int)((newLeftCellWidth + drawPos + offset) * cellWidth), yAlign - cellHeight/2,
cellWidth, cellHeight, 10, 10);
//draw symbols on cells
charBounds = g.getFont().getStringBounds(symbol,
DEFAULT_FONT_RENDER_CONTEXT);
stringWidth = (int)Math.ceil(charBounds.getWidth());
stringHeight = (int)Math.ceil(charBounds.getHeight());
//if symbol is multi-character, font may be adjusted so it will fit
fontScalingFactor = (int)Math.ceil((double)stringWidth/(double)cellWidth);
g.setFont(new Font(FONT_NAME, FONT_STYLE, fontSize/fontScalingFactor));
charBounds = g.getFont().getStringBounds(symbol,
DEFAULT_FONT_RENDER_CONTEXT);
stringWidth = (int)Math.ceil(charBounds.getWidth());
stringHeight = (int)Math.ceil(charBounds.getHeight());
if(i == tape.getCurrentPosition()) {
g.setColor(currentTextColor);
}
g.drawString(symbol,
(int)((newLeftCellWidth + drawPos + 0.5 + offset) * cellWidth - (stringWidth/2)),
(int)(yAlign + (stringHeight/4)));
g.setFont(new Font(FONT_NAME, Font.PLAIN, fontSize/(2 * fontScalingFactor)));
g.setColor(CELL_INDEX_COLOR);
g.drawString(Integer.toString(i - origin),
(int)((newLeftCellWidth + drawPos + 0.3 + offset) * cellWidth - (stringWidth/2)),
(int)(yAlign + 0.45 * cellHeight));
index++;
}//end of for() drawing tape cells
}
void setTapeData(String m, Tape p){
p.removeAllTapeData();
p.addDataToTape(m);
}
void stepOneTapeCell(String direction){
switch(direction){
case "L":
if(tape.getCurrentPosition() > tape.getOrigin()){
tape.setCurrentPosition(tape.getCurrentPosition() - 1);
revalidate();
repaint();
}
//tape.shiftLeft();
break;
case "R":
if(tape.getCurrentPosition() < tape.getSize()-1){
tape.setCurrentPosition(tape.getCurrentPosition() + 1);
revalidate();
repaint();
}
// tape.setCurrentPosition(tape.getCurrentPosition() + 1);
// repaint();
// tape.shiftRight();
// repaint();
break;
}
}
}//end of class TapePanel
TapePanel file:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
public class TapePanel extends JPanel implements MyJPanel{
private final int ROWS = 3;
private final int COLS = 1;
private final int TAPE_ORIGINAL_POSITION = 0;
private int NUM_TAPES = 3;
GridLayout layout;
Tape [] tapes;
TapeArea [] tapeArea;
JScrollPane sp1, sp2, sp3;
Border blackLine, border,margin;
TitledBorder title;
public TapePanel(Tape t1, Tape t2, Tape t3){
tapes = new Tape[NUM_TAPES];
tapes[0] = t1;
tapes[1] = t2;
tapes[2] = t3;
initiateComps();
addCompsToLayout();
}
public void initiateComps() {
// TODO Auto-generated method stub
layout = new GridLayout(ROWS,COLS);
setLayout(layout);
blackLine = BorderFactory.createLineBorder(Color.BLACK);
title = BorderFactory.createTitledBorder(blackLine,"Tapes");
title.setTitleJustification(TitledBorder.LEFT);
border = title.getBorder();
margin = new EmptyBorder(15,15,15,15);
title.setBorder(new CompoundBorder(margin,border));
setBorder(title);
tapeArea = new TapeArea[NUM_TAPES];
tapeArea[0] = new TapeArea(tapes[0]);
tapeArea[1] = new TapeArea(tapes[1]);
tapeArea[2] = new TapeArea(tapes[2]);
sp1 = new JScrollPane(tapeArea[0],JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp1.setPreferredSize(new Dimension(200,70));
sp2 = new JScrollPane(tapeArea[1],JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp2.setPreferredSize(new Dimension(200,70));
sp3 = new JScrollPane(tapeArea[2],JScrollPane.VERTICAL_SCROLLBAR_NEVER,JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp3.setPreferredSize(new Dimension(200,70));
//setBorder(new EmptyBorder(20,15,15,15));
}
#Override
protected void paintComponent(Graphics g) {
// TODO Auto-generated method stub
super.paintComponent(g);
}
void repaintTapeArea(){
for(int i = 0; i < NUM_TAPES;i++){
tapeArea[i].revalidate();
tapeArea[i].repaint();
}
}
void resetAllTapes(){
for(int i = 0; i < NUM_TAPES; i++){
tapeArea[i].setTapeData("", tapes[i]);
tapeArea[i].tape.setCurrentPosition(TAPE_ORIGINAL_POSITION);
}
}
void setTapeData(String m, Tape p, int tapeNumber){
tapeArea[tapeNumber].setTapeData(m, p);
}
void stepOneCell(int tapeNumber, String direction){
tapeArea[tapeNumber].stepOneTapeCell(direction);
}
#Override
public void addCompsToLayout() {
// TODO Auto-generated method stub
add(sp1);
add(sp2);
add(sp3);
}
#Override
public void addComponent(Component comp, int zone, int row, int col, int width, int height) {
// TODO Auto-generated method stub
}
public static void main(String [] args){
JFrame f = new JFrame();
f.add(new TapePanel(new Tape("a b c d"),new Tape("a b c d"),new Tape("a b")));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
f.pack();
}
}
Tape is just a simple linkedlist.
I only get 14 rectangles on the screen that I can move over with. If i add more than that, then they will not be visible.
Scrolling only happens when the preferred size of the component added to the scrollpane is greater than the size of the scroll pane.
You need to override the getPreferredSize() method of your custom painting panel to reflect the area covered by each of your rectangles.
So as you move the rectangle to the right or down you may need to adjust the preferred size.
Related
In this exercise, when you enter the name of a city and its population, in the window it must be graphed a bar that represents the population of that city as shown in the figures, the exercise is almost complete but it doesn't work, could someone tell me what I'm doing wrong?, Why is no bar drawn?, the condition that makes the exercise a bit more difficult to me is that the size of the bars and lines must change if the window size changes. The main class can't be modified because is already given.
package Hw02_Statistics;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import hw01_clocknumbers.DigitalNumber;
public class Statistics extends JFrame {
private JLabel city, population, other;
private JTextField tcity, tpopulation;
private JButton add;
private JTable table;
private DefaultTableModel tablem;
private int index=1;
private bar bars;
public Statistics() {
setTitle("Statistics");
setSize(500, 350);
setupWidgets();
seupEvents();
setVisible(true);
}
private void setupWidgets() {
bars = new bar();
city = new JLabel("City",JLabel.LEFT);
population = new JLabel("Population",JLabel.LEFT);
tcity = new JTextField();
other = new JLabel();
tpopulation = new JTextField();
add = new JButton("Add");
tablem = new DefaultTableModel(new Object[] {"Index", "City", "Population"}, 0);
table = new JTable(tablem);
JPanel norte = new JPanel(new GridLayout(5,1));
JPanel sur = new JPanel(new GridLayout(1,2));
add(norte, BorderLayout.NORTH);
add(sur, BorderLayout.CENTER);
norte.add(city);
norte.add(tcity);
norte.add(population);
norte.add(tpopulation);
norte.add(add);
sur.add(new JScrollPane(table));
sur.add(bars);
}
private void seupEvents() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
add.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (!tcity.getText().equals("") && !tpopulation.getText().equals("")) {
Object rowinfo[] = {index, tcity.getText(), tpopulation.getText()};
tablem.addRow(rowinfo);
int n= Integer.parseInt(tpopulation.getText());
bars.setScale(1, index);
tcity.setText("");
tpopulation.setText("");
index++;
}
}
});
}
public static void main(String[] args) {
new Statistics();
}
}
This is the second class I used
package Hw02_Statistics;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JComponent;
import hw01_clocknumbers.DigitalNumber;
public class bar extends JComponent {
private int digit;
private Integer scale=0;
private int index;
private rect rects[];
public bar () {
}
public void paint(Graphics g) {
int w =getWidth();
int h =getHeight();
rects = new rect[4];
rects[index] = new rect(scale, index, w, h);
// System.out.println(w); 243
// System.out.println(h); 183
g.drawLine(w/12, h/9, w/12, 8*h/9);
g.drawLine(w/12, 8*h/9, 12*w/12, 8*h/9);
}
public void setScale(Integer scale, int index) {
this.index=index-1;
this.scale=scale;
repaint();
}
}
And this is the last Class I used, and it is the one that doesn't work
package Hw02_Statistics;
import java.awt.Graphics;
import javax.swing.JComponent;
public class rect extends JComponent{
private int scale;
private int index;
private int w, h;
public rect(int scale, int index, int w, int h) {
this.scale = scale;
this.index= index;
this.w =w;
this.h=h;
}
public void paint(Graphics e) {
e.fillRect(6*w/12+w*index/12,h/9,scale*w/12,scale*7*h/9);
System.out.println("Aaaa");
repaint();
}
}
class bar (which should be called Bar according to java naming conventions) was renamed to Bars and changed to hold and draw all bars:
class Bars extends JComponent {
//collection of bar heights
private final List<Integer> barsValues;
private static final int W = 20; //bar width
public Bars () {
barsValues = new ArrayList<>();
}
//override paintComponent rather than paint
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); //always call super
int w = getWidth();
int h = getHeight();
//use double to avoid rounding errors
double minX = w/12 , maxX = 12*minX, maxY = h/9, minY = 8 * maxY;
double graphHeight = minY - maxY;
//draw axis
g.drawLine((int)minX, (int)maxY, (int)minX, (int)minY);
g.drawLine((int)minX, (int)minY, (int)maxX, (int)minY);
//draw bars
if(barsValues.size() == 0) return;
double x = minX + W ;
int maxHeight = getMaxHeight(); //calculate scale based on max height
double scale = maxHeight > 0 ? graphHeight / getMaxHeight() : 1;
for(int barValue : barsValues){
double barHeight = scale*barValue;
g.fillRect((int)x ,(int)(minY - barHeight), W, (int)barHeight);
x += 2*W;
}
}
//add bar values. valid values should be > 0
void addBar(int height) {
barsValues.add(height);
repaint();
}
//get max height
int getMaxHeight(){
int max = 0;
for (int value : barsValues){
if(value > max) {
max = value;
}
}
return max;
}
}
class rect is not needed.
To test you need to do some minor changes in Statistics:
change private bar bars; to private Bars bars;
Initialize it by bars = new Bars();
and change one line in the action listener from bars.setScale(1, index) to bars.addBar(n);
The complete code can be copy-pasted from here
I'm having a problem with the paintComponent() method of my JButton. I want to program my own Minesweeper game and when I try to repaint my Tiles(which extend JButton) they don't seem to update. Here is my Tile class:
package mineSweeper;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class Tile extends JButton{
/**
*
*/
private static final long serialVersionUID = 5476927382697663397L;
public static final int UNPRESSED = 0;
public static final int PRESSED = 1;
public static final int FLAG = 2;
public static final int BOMB = 3;
public static final int XBOMB = 4;
public static final int HEIGHT = 16;
public static final int WIDTH = 16;
private int paintMode = UNPRESSED;
public Tile(int x, int y){
super();
setBounds(x*WIDTH, y*HEIGHT, WIDTH, HEIGHT);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setMargin(new Insets(0, 0, 0, 0));
setBorder(BorderFactory.createEmptyBorder());
addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
setEnabled(false);
setPaintMode(PRESSED);
repaint();
}
});
}
public void reset(){
setEnabled(true);
setPaintMode(UNPRESSED);
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if (getPaintMode()==UNPRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.setColor(Color.WHITE);
g.drawLine(0, 0, WIDTH-1, 0);
g.drawLine(0, 1, WIDTH-2, 1);
g.drawLine(0, 0, 0, HEIGHT-1);
g.drawLine(1, 0, 1, HEIGHT-2);
g.setColor(Color.GRAY);
g.drawLine(WIDTH, HEIGHT, 1, HEIGHT);
g.drawLine(WIDTH, HEIGHT-1, 2, HEIGHT-1);
g.drawLine(WIDTH, HEIGHT, WIDTH, 1);
g.drawLine(WIDTH-1, HEIGHT, WIDTH-1, 2);
}
if (getPaintMode()==PRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.drawLine(0, 0, WIDTH, 0);
g.drawLine(0, 0, 0, HEIGHT);
}
g.dispose();
}
public int getPaintMode() {
return paintMode;
}
public void setPaintMode(int mode) {
mode = paintMode;
}
}
and the class Board
package mineSweeper;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Board extends JFrame{
/**
*
*/
private static final long serialVersionUID = 2769769568511334271L;
public static Tile[][] tile;
public JPanel panel = new JPanel(null);
public JButton resetButton = new ResetButton("Click here to Reset");
String input;
private static int screenWidth = 400;
private static int screenHeight = 400;
private static final int MAXROWS = 60;
private static final int MAXCOLUMS = 60;
private static final int MINROWS = 2;
private static final int MINCOLUMS = 6;
private static final int RESETBUTTONSIZE = 40;
public Board(){
super("MineSweeper");
askForInputs();
resetButton.setBounds(0, screenHeight, screenWidth, RESETBUTTONSIZE);
tile = new Tile[getColums()][getRows()];
pack();
setSize(screenWidth + getInsets().left + getInsets().right, screenHeight + getInsets().top + getInsets().bottom + RESETBUTTONSIZE);
getContentPane().add(panel);
panel.add(resetButton);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y] = new Tile(x,y);
panel.add(tile[x][y]);
}
}
setVisible(true);
}
private void askForInputs() {
try{
input = JOptionPane.showInputDialog(null, "Enter number of rows ( Maximum " + MAXROWS + " / Minimum " + MINROWS +")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINROWS)){
if (Integer.parseInt(input) > MAXROWS)
screenHeight = MAXROWS * Tile.HEIGHT;
}
else input = String.valueOf(MAXROWS/4);
screenHeight = Integer.parseInt(input) * Tile.HEIGHT;
try{
input = JOptionPane.showInputDialog(null, "Enter number of colums ( Maximum " + MAXCOLUMS + " / Minimum " + MINCOLUMS + ")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINCOLUMS))
{
if (Integer.parseInt(input) > MAXCOLUMS)
screenWidth = MAXCOLUMS * Tile.WIDTH;
}
else input = String.valueOf(MAXCOLUMS/4);
screenWidth = Integer.parseInt(input) * Tile.WIDTH;
}
public static void reset(){
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y].reset();
}
}
}
public static int getScreenWidth() {
return screenWidth;
}
public static void setScreenWidth(int screenWidth) {
Board.screenWidth = screenWidth;
}
public static int getScreenHeight() {
return screenHeight;
}
public static void setScreenHeight(int screenHeight) {
Board.screenHeight = screenHeight;
}
public static int getColums(){
return getScreenWidth() / Tile.WIDTH;
}
public static int getRows(){
return getScreenHeight() / Tile.HEIGHT;
}
public static void main (String args[]){
new Board();
}
}
Don't mind the unused imports.
So my problem is: when I click a Tile I see I clicked it and I can't click it again but it looks the same like before.
What am I doing wrong please help.
There's a number of things pop out at me, but you're main problem is this...
public class Tile extends JButton {
//...
public void setPaintMode(int mode) {
mode = paintMode;
}
}
You never actually assign the current mode to the paintMode variable, the assignment is backwards.
I'd recommend using JFrame#setExtendedState to set the frame MAXIMIZED_BOTH state over the setSize hack you're currently using, it'll at least reduce the amount of code.
I'd also recommend using a GridLayout or GridBagLayout of a null layout any day.
Have you considered using a JToggleButton, it's basically what you're doing now?
I'm trying to create a graphical component that allows me to draw one rectangle on a selected image (the rectangle must be drawn using drag-and-drop operations): the purpose of this component is to get the coordinates and the size of the rectangle drawn; the second goal is to provide a component which can be easily integrated in a graphical user interface.
The authors of this example created a subclass of JLabel in order to draw the image, then they added a MouseInputAdapter to the instance of this subclass in order to deal with the drawing of the rectangle.
I was inspired by that example, with the difference that I have created a subclass of JPanel class: I named it FigurePanel class. Then I made some changes in order to provide the following features:
if the image is larger than the instance of FigurePanel, then the scrollers must appear;
if the image is smaller than the instance of FigurePanel, then this image must be placed in the center of the panel;
while the user draws the rectangle, it should not extend beyond the limits of the image.
Here is the source code of FigurePanel class.
package imageselectionproject;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import javax.swing.event.MouseInputAdapter;
public class FigurePanel extends JPanel
{
private Image backgroundImage = null;
private Rectangle imageLimits = new Rectangle(0, 0, getWidth(), getHeight());
private Rectangle currentRect = null;
private Rectangle rectToDraw = null;
private final Rectangle previousRectDrawn = new Rectangle();
public FigurePanel()
{
setOpaque(true);
SelectionListener listener = new SelectionListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize()
{
return backgroundImage == null ? super.getPreferredSize() : new Dimension(backgroundImage.getWidth(this), backgroundImage.getHeight(this));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g); //paints the background and image
if (backgroundImage != null)
{
g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
}
// If currentRect exists, paint a box on top.
if (currentRect != null)
{
// Draw a rectangle on top of the image.
g.setXORMode(Color.white); // Color of line varies
// depending on image colors
g.drawRect(rectToDraw.x, rectToDraw.y,
rectToDraw.width - 1, rectToDraw.height - 1);
System.out.println(rectToDraw);
}
}
public void setImage(Image image)
{
int x = 0;
int y = 0;
if (image != null)
{
backgroundImage = image;
// The following instructions are used to center the image on the panel.
/*x = (getSize().width - image.getWidth(this)) / 2;
y = (getSize().height - image.getHeight(this)) / 2;
if (x < 0) x = 0;
if (y < 0) y = 0;*/
}
else
{
backgroundImage = null;
}
currentRect = null;
setSize(getPreferredSize());
imageLimits.setBounds(x, y, getWidth(), getHeight());
System.out.println("imageLimits = " + imageLimits);
repaint();
}
private void updateDrawableRect()
{
int x = currentRect.x;
int y = currentRect.y;
int width = currentRect.width;
int height = currentRect.height;
// Make the width and height positive, if necessary.
if (width < 0)
{
width = 0 - width;
x = x - width + 1;
if (x < 0)
{
width += x;
x = 0;
}
}
if (height < 0)
{
height = 0 - height;
y = y - height + 1;
if (y < 0)
{
height += y;
y = 0;
}
}
// The rectangle should not extend beyond the boundaries of the image.
if (x < imageLimits.x)
{
width -= (imageLimits.x - x);
x = imageLimits.x;
}
else if ((x + width) > imageLimits.x + imageLimits.width)
{
width = imageLimits.x + imageLimits.width - x;
}
if (y < imageLimits.y)
{
height -= (imageLimits.y - y);
y = imageLimits.y;
}
if ((y + height) > imageLimits.y + imageLimits.height)
{
height = imageLimits.y + imageLimits.height - y;
}
// Update rectToDraw after saving old value.
if (rectToDraw != null)
{
previousRectDrawn.setBounds(rectToDraw.x, rectToDraw.y,
rectToDraw.width, rectToDraw.height);
rectToDraw.setBounds(x, y, width, height);
}
else
{
rectToDraw = new Rectangle(x, y, width, height);
}
}
private class SelectionListener extends MouseInputAdapter
{
#Override
public void mousePressed(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
updateDrawableRect();
repaint();
}
#Override
public void mouseDragged(MouseEvent e)
{
updateSize(e.getX(), e.getY());
}
#Override
public void mouseReleased(MouseEvent e)
{
updateSize(e.getX(), e.getY());
}
/*
* Update the size of the current rectangle
* and call repaint. Because currentRect
* always has the same origin, translate it
* if the width or height is negative.
*
* For efficiency (though
* that isn't an issue for this program),
* specify the painting region using arguments
* to the repaint() call.
*
*/
void updateSize(int x, int y)
{
currentRect.setSize(x - currentRect.x, y - currentRect.y);
updateDrawableRect();
Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
repaint(totalRepaint.x, totalRepaint.y,
totalRepaint.width, totalRepaint.height);
}
}
}
The method setImage is used to set a new image, so it invokes the method repaint to redraw the graphical component. In the code shown above, I disabled (via comments) instructions to center the image: in this way, the component seems to work properly.
Instead, if I enable such instructions, the image is correctly positioned in the center of the panel when it is smaller than the panel itself, however, I encountered the following problem: suppose that it is currently displayed an image larger than the panel, if the new image that I decide to load is smaller than the currently displayed image, then the new image is not displayed; if I try to reload the new image, then it appears.
Why does this problem occur? How to solve it?
I also created the FigurePanelTest class in order to test the FigurePanel class.
package imageselectionproject;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
public class FigurePanelTest extends JFrame
{
public FigurePanelTest()
{
FigurePanel imagePanel = new FigurePanel();
JScrollPane imageScrollPane = new JScrollPane();
imageScrollPane.setPreferredSize(new Dimension(420, 250));
imageScrollPane.setViewportView(imagePanel);
JButton imageButton = new JButton("Load Image");
imageButton.addActionListener(
new ActionListener()
{
#Override
public void actionPerformed(ActionEvent evt)
{
JFileChooser fc = new JFileChooser();
int returnValue = fc.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
File selectedFile = fc.getSelectedFile();
System.out.println(selectedFile.getName());
try
{
Image image = ImageIO.read(selectedFile.getAbsoluteFile());
imagePanel.setImage(image);
imageScrollPane.getViewport().setViewPosition(new Point(0, 0));
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
);
Container container = getContentPane();
container.setLayout(new FlowLayout());
container.add(imageScrollPane);
container.add(imageButton);
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Here is the main.
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FigurePanelTest().setVisible(true);
}
});
}
For Andrew, a single program:
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.event.MouseInputAdapter;
public class TestDrawPanel {
public static void main(String args[]) {
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new FigurePanelTest().setVisible(true);
}
});
}
}
class FigurePanelTest extends JFrame {
public FigurePanelTest() {
final FigurePanel imagePanel = new FigurePanel();
final JScrollPane imageScrollPane = new JScrollPane();
imageScrollPane.setPreferredSize(new Dimension(420, 250));
imageScrollPane.setViewportView(imagePanel);
JButton imageButton = new JButton("Load Image");
imageButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
JFileChooser fc = new JFileChooser();
int returnValue = fc.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
File selectedFile = fc.getSelectedFile();
System.out.println(selectedFile.getName());
try {
Image image = ImageIO.read(selectedFile.getAbsoluteFile());
imagePanel.setImage(image);
imageScrollPane.getViewport()
.setViewPosition(new Point(0, 0));
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
Container container = getContentPane();
container.setLayout(new FlowLayout());
container.add(imageScrollPane);
container.add(imageButton);
setSize(600, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class FigurePanel extends JPanel {
private Image backgroundImage = null;
private Rectangle imageLimits = new Rectangle(0, 0, getWidth(), getHeight());
private Rectangle currentRect = null;
private Rectangle rectToDraw = null;
private final Rectangle previousRectDrawn = new Rectangle();
public FigurePanel() {
setOpaque(true);
SelectionListener listener = new SelectionListener();
addMouseListener(listener);
addMouseMotionListener(listener);
}
#Override
public Dimension getPreferredSize() {
return backgroundImage == null ? super.getPreferredSize()
: new Dimension(backgroundImage.getWidth(this),
backgroundImage.getHeight(this));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // paints the background and image
if (backgroundImage != null) {
g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
}
// If currentRect exists, paint a box on top.
if (currentRect != null) {
// Draw a rectangle on top of the image.
g.setXORMode(Color.white); // Color of line varies
// depending on image colors
g.drawRect(rectToDraw.x, rectToDraw.y, rectToDraw.width - 1,
rectToDraw.height - 1);
System.out.println(rectToDraw);
}
}
public void setImage(Image image) {
int x = 0;
int y = 0;
if (image != null) {
backgroundImage = image;
// The following instructions are used to center the image on the
// panel.
/*
* x = (getSize().width - image.getWidth(this)) / 2; y =
* (getSize().height - image.getHeight(this)) / 2;
*
* if (x < 0) x = 0; if (y < 0) y = 0;
*/
} else {
backgroundImage = null;
}
currentRect = null;
setSize(getPreferredSize());
imageLimits.setBounds(x, y, getWidth(), getHeight());
System.out.println("imageLimits = " + imageLimits);
repaint();
}
private void updateDrawableRect() {
int x = currentRect.x;
int y = currentRect.y;
int width = currentRect.width;
int height = currentRect.height;
// Make the width and height positive, if necessary.
if (width < 0) {
width = 0 - width;
x = x - width + 1;
if (x < 0) {
width += x;
x = 0;
}
}
if (height < 0) {
height = 0 - height;
y = y - height + 1;
if (y < 0) {
height += y;
y = 0;
}
}
// The rectangle should not extend beyond the boundaries of the image.
if (x < imageLimits.x) {
width -= (imageLimits.x - x);
x = imageLimits.x;
} else if ((x + width) > imageLimits.x + imageLimits.width) {
width = imageLimits.x + imageLimits.width - x;
}
if (y < imageLimits.y) {
height -= (imageLimits.y - y);
y = imageLimits.y;
}
if ((y + height) > imageLimits.y + imageLimits.height) {
height = imageLimits.y + imageLimits.height - y;
}
// Update rectToDraw after saving old value.
if (rectToDraw != null) {
previousRectDrawn.setBounds(rectToDraw.x, rectToDraw.y,
rectToDraw.width, rectToDraw.height);
rectToDraw.setBounds(x, y, width, height);
} else {
rectToDraw = new Rectangle(x, y, width, height);
}
}
private class SelectionListener extends MouseInputAdapter {
#Override
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
currentRect = new Rectangle(x, y, 0, 0);
updateDrawableRect();
repaint();
}
#Override
public void mouseDragged(MouseEvent e) {
updateSize(e.getX(), e.getY());
}
#Override
public void mouseReleased(MouseEvent e) {
updateSize(e.getX(), e.getY());
}
/*
* Update the size of the current rectangle and call repaint. Because
* currentRect always has the same origin, translate it if the width or
* height is negative.
*
* For efficiency (though that isn't an issue for this program), specify
* the painting region using arguments to the repaint() call.
*/
void updateSize(int x, int y) {
currentRect.setSize(x - currentRect.x, y - currentRect.y);
updateDrawableRect();
Rectangle totalRepaint = rectToDraw.union(previousRectDrawn);
repaint(totalRepaint.x, totalRepaint.y, totalRepaint.width,
totalRepaint.height);
}
}
}
The problem is calculating the x and y in the setImage().It's not calculating the center of panel correctly.I'm saying this by checking the values of x and y after loading small and large images many times
However I tried putting the centering the image inside paintComponent and it worked perfectly
if (backgroundImage != null) {
imageLimits.x = (this.getWidth() - backgroundImage.getWidth(this)) / 2;
imageLimits.y = (this.getHeight() - backgroundImage.getHeight(this)) / 2;
g.drawImage(backgroundImage, imageLimits.x, imageLimits.y, this);
}
this is my first Java GUI program, and really only my second java program, so take it easy on me :) My program is a result of a lot of googling and reading java docs. My problem is that I have a sprite sheet of 52 cards, and am attempting to save these cards individually to a Buffered Image array using subImage, and just for testing purposes, display all 52 in a window. The File is in the correct directory I made sure of that. I believe that my problem lies with my use of Jlabels, or simply a foolish mistake. Anyways, here is my class that does the sprite sheet splitting
package gui;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class crdimgs extends JPanel {/**
*
*/
static final long serialVersionUID = 1L;
public final int width = 10;
public final int height = 20;
public int rows = 13;
public int cols = 5;
public BufferedImage image;
File cardimg = new File("Cards.jpg");
BufferedImage cards[];
public void loadsplit(File loadimage){
try{
image = ImageIO.read(loadimage);
} catch(Exception error){
System.out.print("error");
}
cards = new BufferedImage[cols*rows];
}
public crdimgs() {
loadsplit(cardimg);
setLayout(new GridLayout(rows, cols, 1, 1));
int x = 0;
int y = 0;
int subimg = 0;
for( int i = 0; i < rows; i++)
{
JPanel panel = new JPanel();
cards[subimg] = new BufferedImage(width, height, 5);
cards[subimg] = image.getSubimage(x, y, width, height);
panel.add(new JLabel(new ImageIcon(cards[subimg])));
add(panel);
x+=width;
subimg++;
}
y+=height;
x=0;
}
}
}
And my Main class
package gui;
import javax.swing.JFrame;
import java.awt.Color;
public class cards extends JFrame {
private static final long serialVersionUID = 1L;
public cards(){
setTitle("Poker");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1000, 700);
setLocationRelativeTo(null);
this.getContentPane().setBackground(Color.GREEN);
setVisible(true);
setResizable(false);
add(new crdimgs());
}
public static void main(String[] args){
new cards();
}
}
Errors I receive at the moment are:
errorException in thread "main" java.lang.NullPointerException
at gui.crdimgs.<init>(crdimgs.java:53)
at gui.cards.<init>(cards.java:22)
at gui.cards.main(cards.java:28)
Likely your image is null, possibly because you're looking in the wrong place for it, but to find out, check out which line is 53.
Suggestions:
Start small and then build on. Don't try to do complex image manipulation until you first successfully read and show a single image.
Check where Java is looking for the image, because likely it isn't where you think it is. Put System.out.println(System.getProperty("user.dir")); in your code to find out.
Call setVisible(true) after adding all components to the JFrame.
Improve your exception display code by printing the stack trace: error.printStackTrace() (thanks Mad!).
For example:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class PlayingCardTest {
public static void main(String[] args) {
String pathToDeck = "http://www.jfitz.com/cards/classic-playing-cards.png";
try {
final List<ImageIcon> cardImgList = CreateCards.createCardIconList(pathToDeck);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Moving Cards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CardGameTable(cardImgList, frame));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
#SuppressWarnings("serial")
class CardGameTable extends JLayeredPane {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private static final Color BASE_COLOR = new Color(0, 80, 0);
private static final int CARD_COUNT = 20;
private static final int WIDTH_SHOWING = 20;
private JPanel basePane = new JPanel(null);
public CardGameTable(List<ImageIcon> cardImgList, final JFrame frame) {
basePane.setSize(getPreferredSize());
basePane.setBackground(BASE_COLOR);
add(basePane, JLayeredPane.DEFAULT_LAYER);
final MyMouseAdapter myMouseAdapter = new MyMouseAdapter(this, basePane);
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
for (int i = 0; i < CARD_COUNT; i++) {
JLabel card = new JLabel(cardImgList.remove(0));
card.setSize(card.getPreferredSize());
int x = (PREF_W / 2) + WIDTH_SHOWING * (CARD_COUNT - 2 * i) / 2 -
card.getPreferredSize().width / 2;
int y = PREF_H - card.getPreferredSize().height - WIDTH_SHOWING * 2;
card.setLocation(x, y);
basePane.add(card);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
class MyMouseAdapter extends MouseAdapter {
private JLabel selectedCard = null;
private JLayeredPane cardGameTable = null;
private JPanel basePane = null;
private int deltaX = 0;
private int deltaY = 0;
public MyMouseAdapter(JLayeredPane gameTable, JPanel basePane) {
this.cardGameTable = gameTable;
this.basePane = basePane;
}
#Override
public void mousePressed(MouseEvent mEvt) {
Component comp = basePane.getComponentAt(mEvt.getPoint());
if (comp != null && comp instanceof JLabel) {
selectedCard = (JLabel) comp;
basePane.remove(selectedCard);
basePane.revalidate();
basePane.repaint();
cardGameTable.add(selectedCard, JLayeredPane.DRAG_LAYER);
cardGameTable.revalidate();
cardGameTable.repaint();
deltaX = mEvt.getX() - selectedCard.getX();
deltaY = mEvt.getY() - selectedCard.getY();
}
}
#Override
public void mouseReleased(MouseEvent mEvt) {
if (selectedCard != null) {
cardGameTable.remove(selectedCard);
cardGameTable.revalidate();
cardGameTable.repaint();
basePane.add(selectedCard, 0);
basePane.revalidate();
basePane.repaint();
selectedCard = null;
}
}
#Override
public void mouseDragged(MouseEvent mEvt) {
if (selectedCard != null) {
int x = mEvt.getX() - deltaX;
int y = mEvt.getY() - deltaY;
selectedCard.setLocation(x, y);
cardGameTable.revalidate();
cardGameTable.repaint();
}
}
}
class CreateCards {
private static final int SUIT_COUNT = 4;
private static final int RANK_COUNT = 13;
public static List<ImageIcon> createCardIconList(String pathToDeck)
throws MalformedURLException, IOException {
BufferedImage fullDeckImg = ImageIO.read(new URL(pathToDeck));
int width = fullDeckImg.getWidth();
int height = fullDeckImg.getHeight();
List<ImageIcon> iconList = new ArrayList<ImageIcon>();
for (int suit = 0; suit < SUIT_COUNT; suit++) {
for (int rank = 0; rank < RANK_COUNT; rank++) {
int x = (rank * width) / RANK_COUNT;
int y = (suit * height) / SUIT_COUNT;
int w = width / RANK_COUNT;
int h = height / SUIT_COUNT;
BufferedImage cardImg = fullDeckImg.getSubimage(x, y, w, h);
iconList.add(new ImageIcon(cardImg));
}
}
Collections.shuffle(iconList);
return iconList;
}
}
Which shows:
I want to print each digit of pi number as a colored pixel, so, I get an input, with the pi number, then parse it into a list, each node containing a digit (I know, I'll use an array later), but I never get this painted to screen... Can someone help me to see where I'm wrong?
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.MemoryImageSource;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class PiPainter extends JPanel
{
private static final long serialVersionUID = 6416932054834995251L;
private static int pixels[];
private static List<Integer> pi = new ArrayList<Integer>();
private final static int[] color = {
0xFF000000, 0xFF787878, 0xFF008B00, 0xFF00008B, 0xFF008B8B,
0xFF008B00, 0xFFCDCD00, 0xFFFF4500, 0xFF8B0000, 0xFFFF0000
};
public static void readFile(String name)
{
File file = new File(name);
BufferedReader reader = null;
char[] digits;
try
{
reader = new BufferedReader(new FileReader(file));
String text = null;
while((text = reader.readLine()) != null)
{
digits = text.toCharArray();
for(char el : digits)
if(el != ' ')
pi.add(Character.getNumericValue(el));
}
} catch (Exception e)
{
e.printStackTrace();
}
}
public void paint(Graphics gg)
{
// page containing pi number, http://gc3.net84.net/pi.htm
// other source, http://newton.ex.ac.uk/research/qsystems/collabs/pi/pi6.txt
readFile("c:\\pi.txt");
int h = 300;
int w = 300;
int digit;
int i = 0;
pixels = new int[w * h];
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
pixels[i] = color[pi.get(i)];
i++;
}
}
Image art = createImage(new MemoryImageSource(w, h, pixels, 0, w));
gg.drawImage(art, 0, 0, this);
}
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.getContentPane().add(new PiPainter(), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.setVisible(true);
}
}
I'm not familiar with MemoryImageSource. Here's the first 16 300 digits of π, repeated in a BufferedImage and using your color table.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PiRaster extends JPanel {
private static final int W = 30;
private static final int H = 30;
private static List<Integer> pi = new ArrayList<Integer>();
BufferedImage image;
private int[] clut = {
0x000000, 0x787878, 0x008B00, 0x00008B, 0x008B8B,
0x008B00, 0xCDCD00, 0xFF4500, 0x8B0000, 0xFF0000
};
public PiRaster() {
this.setPreferredSize(new Dimension(W * 16, H * 10));
String s = ""
+ "31415926535897932384626433832795028841971693993751"
+ "05820974944592307816406286208998628034825342117067"
+ "98214808651328230664709384460955058223172535940812"
+ "84811174502841027019385211055596446229489549303819"
+ "64428810975665933446128475648233786783165271201909"
+ "14564856692346034861045432664821339360726024914127";
for (int i = 0; i < s.length(); i++) {
pi.add(s.charAt(i) - '0');
}
}
#Override
public void paintComponent(Graphics g) {
if (image == null) {
image = (BufferedImage) createImage(W, H);
int i = 0;
for (int row = 0; row < H; row++) {
for (int col = 0; col < W; col++) {
image.setRGB(col, row, clut[pi.get(i)]);
if (++i == pi.size()) {
i = 0;
}
}
}
}
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PiRaster());
frame.pack();
frame.setVisible(true);
}
});
}
}
#trashgod
Thanks for your answer, I changed it a little bit to achieve what I was looking for ; )
Now you can change the width easily to achieve a better view of the image and fit the contents, and the number don't repeats, making it easy to perceive patterns (if there might be). Oh, and I added about 2~3 lines at the end, to clarify it.
package edu.pi;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PiRaster extends JPanel
{
private static final long serialVersionUID = -1298205187260747210L;
private static int W;
private static int H;
private static List<Integer> pi = new ArrayList<Integer>();
BufferedImage image;
private int[] clut = {
0x000000, 0x787878, 0x008B00, 0x00008B, 0x008B8B,
0x008B00, 0xCDCD00, 0xFF4500, 0x8B0000, 0xFF0000
};
public PiRaster()
{
String s = "3."
+ "14159265358979323846264338327950288419716939937510"
+ "58209749445923078164062862089986280348253421170679"
+ "82148086513282306647093844609550582231725359408128"
+ "48111745028410270193852110555964462294895493038196"
+ "44288109756659334461284756482337867831652712019091"
+ "45648566923460348610454326648213393607260249141273"
+ "72458700660631558817488152092096282925409171536436"
+ "78925903600113305305488204665213841469519415116094"
+ "33057270365759591953092186117381932611793105118548"
+ "07446237996274956735188575272489122793818301194912"
+ "98336733624406566430860213949463952247371907021798"
+ "60943702770539217176293176752384674818467669405132"
+ "00056812714526356082778577134275778960917363717872"
+ "14684409012249534301465495853710507922796892589235"
+ "42019956112129021960864034418159813629774771309960"
+ "51870721134999999837297804995105973173281609631859"
+ "50244594553469083026425223082533446850352619311881"
+ "71010003137838752886587533208381420617177669147303"
+ "59825349042875546873115956286388235378759375195778"
+ "18577805321712268066130019278766111959092164201989";
char temp;
for (int i = 0; i < s.length(); i++)
{
temp = s.charAt(i);
if (temp >= 48 && temp <= 57)
pi.add(s.charAt(i) - '0');
}
W = 50;
H = s.length() / W + 3;
this.setPreferredSize(new Dimension(W * 10, H * 10));
}
#Override
public void paintComponent(Graphics g)
{
if (image == null)
{
image = (BufferedImage) createImage(W, H);
int i = 0;
boolean end = false;
for (int row = 0; row < H && !end; row++)
{
for (int col = 0; col < W && !end; col++)
{
image.setRGB(col, row, clut[pi.get(i)]);
if (++i == pi.size())
{
i = 0;
end = true;
}
}
}
}
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JFrame frame = new JFrame("Pi raster");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new PiRaster());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}