Why wont squares show up after repaint()? - java

I posted this question a bit earlier and was told to make it SSCCE so here goes (if I can make any improvements feel free to let me know):
I'm wondering why when my button "confirm" is clicked the old squares disappear and the redrawn squares do not appear on my GUI (made with swing). The Squares class draws 200 spaced out squares with an ID (0, 1, 2, or 3 as String) inside obtained from a different class (for the purpose of this question, let's assume it is always 0 and not include that class). For clarification: Squares draws everything perfectly the first time (also retrieves the correct IDs), but I want it to redraw everything once the button is clicked with new IDs.
Code for Squares:
import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.ArrayList;
public class Squares extends JPanel{
private ArrayList<Rectangle> squares = new ArrayList<Rectangle>();
private String stringID = "0";
public void addSquare(int x, int y, int width, int height, int ID) {
Rectangle rect = new Rectangle(x, y, width, height);
squares.add(rect);
stringID = Integer.toString(ID);
if(ID == 0){
stringID = "";
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
FontMetrics fm = g2.getFontMetrics();
int fontAscent = fm.getAscent();
g2.setClip(new Rectangle(0,0,Integer.MAX_VALUE,Integer.MAX_VALUE));
for (Rectangle rect : squares) {
g2.drawString(stringID, rect.x + 7, rect.y + 2 + fontAscent);
g2.draw(rect);
}
}
}
Code for GUI:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GUIReserver extends JFrame implements Runnable{
private int myID;
private JButton confirm = new JButton("Check Availability and Confirm Reservation");
private JFrame GUI = new JFrame();
private Squares square;
public GUIReserver(int i) {
this.myID = i;
}
#Override
public void run() {
int rows = 50;
int seatsInRow = 4;
confirm.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
GUI.getContentPane().remove(square);
square = new Squares();
int spaceNum = 0;
int rowNum = 0;
int offsetX = 200;
int offsetY = 0;
for(int i = 0; i < rows * seatsInRow; i++){
square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
rowNum++;
if(rowNum == 10){
rowNum = 0;
spaceNum++;
}
if(spaceNum == 2){
spaceNum = 3;
rowNum = 0;
}
if(spaceNum == 5){
spaceNum = 0;
offsetY += 140;
}
}
GUI.getContentPane().add(square); //this does not show up at all (could be that it wasn't drawn, could be that it is out of view etc...)
GUI.repaint(); //the line in question
}
});
GUI.setLayout(new FlowLayout());
GUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GUI.setLocation(0,0);
GUI.setExtendedState(JFrame.MAXIMIZED_BOTH);
square = new Squares();
int spaceNum = 0;
int rowNum = 0;
int offsetX = 200;
int offsetY = 0;
for(int i = 0; i < rows * seatsInRow; i++){
square.addSquare(rowNum * 31 + offsetX,spaceNum * 21 + 50 + offsetY,20,20, 0); //normally the 4th parameter here would retrieve the ID from the main class
rowNum++;
if(rowNum == 10){
rowNum = 0;
spaceNum++;
}
if(spaceNum == 2){
spaceNum = 3;
rowNum = 0;
}
if(spaceNum == 5){
spaceNum = 0;
offsetY += 140;
}
}
GUI.getContentPane().add(square); //this shows up the way I wish
GUI.add(confirm);
GUI.pack();
GUI.setVisible(true);
}
}
Code for main:
public class AircraftSeatReservation {
static AircraftSeatReservation me = new AircraftSeatReservation();
private final int rows = 50;
private final int seatsInRow = 4;
private int seatsAvailable = rows * seatsInRow;
private Thread t3;
public static void main(String[] args) {
GUIReserver GR1 = new GUIReserver(3);
me.t3 = new Thread(GR1);
me.t3.start();
}
}

One major problem: Your Squares JPanels preferred size is only 20 by 20, and will likely actually be that size since it seems to be added to a FlowLayout-using container. Next you seem to be drawing at locations that are well beyond the bounds of this component, and so the drawings likely will never be seen. Consider allowing your Squares objects to be larger, and make sure to only draw within the bounds of this component.
Note also there is code that doesn't make sense, including:
private int myID;
private JTextField row, column, instru draft saved // ???
package question2;ction1, instruction2, seatLabel, rowLabel; // ???
I'm guessing that it's
private int myID;
private JTextField row, column, instruction1, instruction2, seatLabel, rowLabel;
And this won't compile for us:
int rows = AircraftSeatReservation.getRows();
int seatsInRow = AircraftSeatReservation.getSeatsInRow(); // and shouldn't this take an int row parameter?
since we don't have your AircraftSeatReservation class (hopefully you don't really have static methods in that class).
And we can't compile or run your current code. We don't want to see your whole program, but rather you should condense your code into the smallest bit that still compiles, has no extra code that's not relevant to your problem, but still demonstrates your problem. So as Andrew Thompson recommends, for better help, please create and post your Minimal, Complete, and Verifiable example or Short, Self Contained, Correct Example.
I would try to OOP-ify your problem as much as possible, to allow you to divide and conquer. This could involve:
Creating a SeatClass enum, one with possibly two elements, FIRST and COACH.
Creating a non-GUI Seat class, one with several fields including possibly: int row, char seat ( such as A, B, C, D, E, F), a SeatClass field to see if it is a first class seat or coach, and a boolean reserved field that is only true if the seat is reserved.
This class would also have a getId() method that returns a String concatenation of the row number and the seat char.
Creating a non-GUI Airplane class, one that holds two arrays of Seats, one for SeatClass.FIRST or first-class seats, and one for SeatClass.COACH.
It would also have a row count field and a seat count (column count) field.
After creating all these, then work on your GUI classes.
I'd create a GUI class for Seats, perhaps GuiSeat, have it contain a Seat object, perhaps have it extend JPanel, allow it to display its own id String that it gets from its contained Seat object, have it override getBackground(...) so that it's color will depend on whether the seat is reserved or not.
etc.....

Related

How do I make Random generating objects come on my Screen?

This is my background Image that i have usedI am a New programmer and I am still learning to code. I am tring to create a flappy bird game but my code does not seem to work. What I am tring to do is create code that generates random pipes within my program and tring to make them have collision with the red Ball.
I have tried to look around for flappy bird games that explain to me how it works but it does not work within my code or it is very very complicated I can not understand.
Hey Thanks for the help but I had tried to implement your code and I got this error. I am trying to fix this. As for your other comments I was trying to make a game called flappy bird in which I must generate random pipes with varying heights of pipes with the same amount of space in between. This is what is happening:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Random;
import java.awt.Rectangle;
/**
* Auto Generated Java Class.
*/
public class Game extends JFrame implements ActionListener{
static final int NUMBER_OF_OBSTACLES = 30; // pre-assign the number of obstacles to be generated
// setup our objects for our game
JLabel[] columns = new JLabel [NUMBER_OF_OBSTACLES];
public Rectangle bird;
public final int WIDTH = 100, HEIGHT = 100;
public Random rand;
int number;
ImageIcon lblBackground = new ImageIcon("Test1.jpg");
ImageIcon lblBackground2 = new ImageIcon("Background2.jpg");
static int randomNumber;
int xLocation = 0;
int yLocation = 0;
int wLocation = 450;
int xForRect = 300;
int yForBall = 300;
int xForRectTop = 300;
static int randY;
int xSpeed = 1;
int ySpeed = 1;
int delay = 5;
Rectangle rect;
public Game() {
Rectangle column [];
column = new Rectangle [150];
setLayout(null);
setSize (404, 600);
setVisible(true); //sets everything to visable
}
private void generateRectangles() {
for (int i = 0; i < columns.length; i ++ ) {
columns[i] = new JLabel("" + i); // the name of the object will be shown as the number it is
columns[i].setBackground(Color.green);
columns[i].setOpaque(true);
columns[i].setBounds(randomRect());
}
}
private Rectangle randomRect() {
// create a rectangle to store the bounds of our new object
Rectangle rect = new Rectangle();
rect.height = randomizer(5, 100); // random height 1 to 100
rect.width = randomizer(5, 100); // random width 1 to 100
return rect;
}
private static int randomizer(int min, int max) {
Random random = new Random(); // create new randomizer
int number = random.nextInt(max - min); //randomizes a number from 0 to dist between them (for example if we are generating from 50 to 100 it will run from 0 to 50)
number = number + min; // then add 50 to match the bottom range
return number; // return this random number to the method that called for it
}
public void makeColumn(Graphics g, Rectangle column) {
g.setColor(Color.green);
g.fillRect(column.x, column.y, column.width, column.height);
}
public static int addRandomColumn() {
randomNumber = (int)(Math.random() * 300 + 250);
randomNumber = randY;
return randY;
}
public void paint(Graphics g){
super.paint(g);
for (int p = 0; p < 9999999; p = p+1) {
for (int i = 0; i <=630; i= i + 1){
lblBackground.paintIcon(this,g, xLocation, yLocation);
System.out.println(xLocation);
xLocation = xLocation - xSpeed;
g.setColor(Color.red);
g.fillRect(150, yForBall, 20, 20);
yForBall = yForBall + 1;
rect = new Rectangle(xForRect,450,50,number);
makeColumn(g,rect);
rect = new Rectangle(xForRectTop,0,50,number);
makeColumn(g,rect);
xForRect = xForRect -1;
xForRectTop = xForRectTop -1;
try {
Thread.sleep(delay);
}
catch (Exception error) {
}
}
}
}
public void actionPerformed(ActionEvent evt){
}
public static void main(String[] args) {
new Game();
}
}
That I what I have so far. Hope you can help me
What I was planing to do was generate pipes in in the program with varying heights.
I will address you question in 2 areas.
1. Firstly project design
It is good to have an idea of what you want before you ask a question or begin writing your program. From the sounds of it I assume you are trying to make a game where you control a bird which must avoid obstacles.
Currently you are generating your game by drawing the components onto the frame. This is a good option but I prefer to generate the components as objects (usually JLabels so that it is easy to give them graphics). By creating objects it allows you to only modify the object on the screen if you want to move it during the game rather than repainting all the components.
Java is an object oriented programming language so it is best if you design your program with a modular structure.
Here are the key features of your program which must be created:
Background JFrame
Obstacle creator
Input listener
Collision checker
I will address merely the obstacle creator because that is what you have asked about in your question.
When writing the obstacle creator you want to write it in a way that is robust and easy to use multiple times. Ideally this will come in the form of a class or function which can be called and returns and object on your screen. This will allow for maximum flexibility.
Also it is worth noting that unless you plan on using your procedures in other classes the modifier public is unnecessary, using private void is better practice.
2. Writing Code
Here I have re-written your program in a simpler way. By not overriding the paint method you save yourself much hassle.
Note the key changes I have made:
I am now generating your game components as JLabels. They are created by the procedures in the Game() method.
The rectangles are no longer painted which will allow easier collision detecting when you write that part of the program
Notice how I created a function which randomly generates numbers. I can now easily call this function from other places in the program later.
Lastly I removed your delay Thread.sleep(delay); code. It is better to use a timer thread to handle your events rather than a delay. I would recommend you create a timer thread which runs parallel to your program. Ever half second when the thread runs you can move the bird in the direction of the input and then check if it has collided with an object from columns array.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.awt.Rectangle;
public class Game extends JFrame implements ActionListener{
static final int NUMBER_OF_OBSTACLES = 30; // pre-assign the number of obstacles to be generated
// setup our objects for our game
JLabel[] columns = new JLabel [NUMBER_OF_OBSTACLES];
JLabel bird;
public Game() {
// setup the frame
setLayout(null);
setSize (404, 600);
setVisible(true); //sets everything to visable
setDefaultCloseOperation(EXIT_ON_CLOSE);
generateRectangles();
placeBird();
}
private void placeBird() {
// create the new bird
bird = new JLabel("B");
bird.setBackground(Color.red); // set background
bird.setOpaque(true); // make the label's background color not invisible but opaque
bird.setBounds(this.getWidth()/2, 0 , 30, 30); // place bird at top midpoint of screen, its size is a 30,30 square
this.add(bird); // add the bird to our frame
bird.setVisible(true); // show the bird on our frame
}
private void generateRectangles() {
for (int i = 0; i < columns.length; i ++ ) {
columns[i] = new JLabel("" + i); // the name of the object will be shown as the number it is
columns[i].setBackground(Color.green);
columns[i].setOpaque(true);
columns[i].setBounds(randomRect());
this.add(columns[i]);
columns[i].setVisible(true);
}
}
private Rectangle randomRect() {
// create a rectangle to store the bounds of our new object
Rectangle rect = new Rectangle();
rect.height = randomizer(5, 100); // random height 1 to 100
rect.width = randomizer(5, 100); // random width 1 to 100
rect.x = randomizer(1, this.getWidth()); // random x position up to the width of the frame
rect.y = randomizer(30, this.getHeight()); // random y position from 30 up to the height of the frame (NOTE: the 30 gap is so no obstacles start on top of the bird)
return rect;
}
private static int randomizer(int min, int max) {
Random random = new Random(); // create new randomizer
int number = random.nextInt(max - min); //randomizes a number from 0 to dist between them (for example if we are generating from 50 to 100 it will run from 0 to 50)
number = number + min; // then add 50 to match the bottom range
return number; // return this random number to the method that called for it
}
// main runs on startup creating our frame
public static void main(String[] args) {
Game game = new Game(); // start a new game
}
#Override
public void actionPerformed(ActionEvent e) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}

Resizeable Number Triangle in Java GUI

I have this assignment for a Java class I am taking. I was assigned to do this:
Write a program that displays numbers as shown below. The number of lines in the display changes to fit the window as the window resizes.
This is whats displayed in the GUI ( without the large spaces in between lines):
1
12
123
1234
12345
123456
1234567
with the numbers counting larger and the number of lines increasing as I expand the GUI window.
Heres my code that I have now:
import javax.swing.*;
import java.awt.*;
public class ResizingGUI extends JPanel{
public int width = 600;
public int height = 200;
public int x_coord = 10;
public int y_coord = 40;
public static final int point_size = 12;
public Font fontObject = new Font("SansSerif", Font.PLAIN, point_size);
public int maxLines = 16;
public ResizingGUI (){
super();
setSize(width, height);
}
public void paint(Graphics g){
super.paint(g);
g.setFont(fontObject);
x_coord = 10;
y_coord = 40;
int lineCount = 0;
int line = 1;
maxLines = (this.getHeight()-40)/10;
while(lineCount < maxLines){
while(line < maxLines){
String s = String.valueOf(line);
g.drawString(s, x_coord, y_coord);
line++;
x_coord = x_coord + 10;
if(line > 10){
x_coord = x_coord + 5;
}
line = 0;
lineCount++;
y_coord = y_coord + 10;
}
}
}
public static void main(String[]args){
JFrame frame = new JFrame();
frame.setTitle("Resizeable GUI");
frame.setSize (600,200);
frame.getContentPane().add (new ResizingGUI());
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
I think this might be the solution, but the nested loops are throwing me for a loop (hah)
If anyone could please advise on either a way to fix the nested loops or (more likely) how to achieve my goal, I would be very grateful.
Your loops are a little confusing, basically, you want to loop for the number of lines and the loop for the number columns (which is the current line number)...
int line = 0;
while (line < maxLines) {
int col = 0;
while (col < line) {
//...
col++;
}
line++;
}
You're also no resetting the x_coord back to it's initial position, meaning that each new line will start at the end of the last line...just below it.
You should also:
Override paintComponent instead of paint. Take a look at Performing Custom Painting for more details
Override getPreferredSize instead of using setSize. It will work better with the layout managers
Make use of the FontMetrics in order to determine how many pixels you need to adjust for each line/column. Take a look at Measuring Text for more details

adding and removing shapes continuously in a loop?

I'm trying to write a program that displays 10 randomly colored and randomly located boxes, but according to the assignment, "Only the last 10 random boxes are to be displayed on the screen. That is, when the 11th box is drawn, remove the 1st box that was drawn. When the 12th box is drawn, remove the 2nd box, and so on".
I'm not sure how to do this, as the farthest I can get is to use a for loop to display 10 random boxes.
This is what I have so far:
package acm.graphics;
import acm.graphics.*;
import acm.program.*;
import java.awt.*;
import java.util.Random;
import javax.swing.*;
public class ShootingStar extends GraphicsProgram
{
public void run()
{
final int width = 800;
final int height = 600;
final int boxWidth = 50;
final int maxBoxes = 10;
this.setSize(width, height);
Random random = new Random();
for( int i = 0; i<=maxBoxes ;i++) {
float r = random.nextFloat();
float b = random.nextFloat();
float g = random.nextFloat();
Color randColor = new Color(r,g,b);
GRect r1 = new GRect(boxWidth, boxWidth);
r1.setFilled(true);
r1.setColor(randColor);
GPoint x = new GPoint(random.nextInt(width),
random.nextInt(height));
add(r1, x);
}
this.pause(100);
}
}
please any tips or advice would be greatly appreciated
One way to do it would be:
public class Test {
private int boxWidth, boxHeight = 50;
private GRect[] rects;
private int first;//keep track of oldest rectangle
public Test()
{
this.rects = new GRect[10];
this.first = 0;
}
void drawRects()
{
//for each rectangle, draw it
}
void addRect()
{
this.rects[first] = new GRect(boxWidth, boxHeight);
first++;
first = first % 10; //keeps it within 0-9 range
}
}
Just call addRect() whenever a new rectangle needs to be added and the new one will replace the oldest one.
You're only iterating ten times, which only makes ten boxes, right? Let's start there. maxBoxes should be larger than 10 (I don't know the specifics of what you're trying to do, so I can't say what maxBoxes should be)
Basically, you want to store the information for these boxes somewhere, and then pull the last ten items out. You could use an array of arrays for this. If you're pushing to then end of the main array, then you just have to pop off the last ten, then draw the boxes.

Calculate cell sizes and draw (with lines in between) them

I want to draw a grid and draw stuff in the cells (to keep things easy just fill them).
Overall I've got it pretty much working only in some panel sizes the cell is about 1 pixel off of where it should be placed (overlapping the line).
TBH I haven't really done enough calculating to possibly find the answer myself, so my apologies for that, I'm really not too sure how to approach this "bug" either though.
Anyway, here's the code:
public class Gui extends JFrame {
public static void main(String[] args) {
new Gui().setVisible(true);
}
public Gui() {
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
add(new JPanel() {
public static final int SIZE = 3;
/** Line thickness ratio to a block */
public static final float LINE_THICKNESS = 0.1f;
/** #return the width of a block. */
protected final int getBlockWidth() {
return getWidth() / SIZE;
}
/** #return the height of a block. */
protected final int getBlockHeight() {
return getHeight() / SIZE;
}
/** #return the width of a cell. */
protected final int getCellWidth() {
return (int) Math.ceil(getBlockWidth()*(1-LINE_THICKNESS));
}
/** #return the height of a cell. */
protected final int getCellHeight() {
return (int) Math.ceil(getBlockHeight()*(1-LINE_THICKNESS));
}
#Override
public void paintComponent(Graphics g) {
g.setColor(new Color(0, 0, 255, 100));
int lineWidth = (int) (LINE_THICKNESS * getBlockWidth());
int lineHeight = (int) (LINE_THICKNESS * getBlockHeight());
for(int i = 0; i <= SIZE; i++) {
g.fillRect(i * getBlockWidth() - lineWidth / 2, 0, lineWidth, getHeight());
g.fillRect(0, i * getBlockHeight() - lineHeight/2, getWidth(), lineHeight);
}
g.setColor(new Color(255, 0, 0, 100));
for(int i = 0; i < SIZE; i++) {
for(int j = 0; j < SIZE; j++) {
int x = j * getBlockWidth() + lineWidth/2;
int y = i * getBlockHeight() + lineHeight/2;
Graphics temp = g.create(x, y, getCellWidth(), getCellHeight());
drawCell(temp, i, j);
}
}
}
private void drawCell(Graphics g, int i, int j) {
g.fillRect(0, 0, getCellWidth(), getCellHeight());
}
});
setLocation(new Point(500, 200));
setSize(new Dimension(600, 600));
}
}
If you run it you'll probably see what I mean. I can't think of a good explanation in words. At first I thought I had to add + 1 to x and y since I want to draw next to the line, but this (obviously) just shifts the problem to the other side.
Running this with a SIZE bigger (like 30) gives me another bug that it gives open space to the sides. I know (or assume) this is because I'm using integers and it isn't too big of a deal though. But hints for a better approach (in general) are always welcome.
There are several ways you can fix this. I will not give you code, since I believe (based on how you asked your question) you are one of those who like to think and solve problems on their own.
First of all: first draw the background on the whole panel and then draw the lines. There'll be no while lines and the drawing will be slightly faster.
Second way: the order of drawing is important. You can safely draw the background first (even if it overlaps) and then overwrite it with borders.
Third way: do not use ints. Use floats or doubles. All your trouble will go away.
Fourth way: calculate the remainder. You can predict when the lines are drawn and when not, think about it. Predict it and draw appropriately.
Hi I had your same problem but the solution I implemented is inspired by the sample available from the Java Tutorial for drawing multiline text and draws the text on the cell using the text APIs.
http://java.sun.com/docs/books/tutorial/2d/text/drawmulstring.html
import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import java.text.BreakIterator;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
public class MultilineTableCell
implements TableCellRenderer {
class CellArea extends DefaultTableCellRenderer {
/**
*
*/
private static final long serialVersionUID = 1L;
private String text;
protected int rowIndex;
protected int columnIndex;
protected JTable table;
protected Font font;
private int paragraphStart,paragraphEnd;
private LineBreakMeasurer lineMeasurer;
public CellArea(String s, JTable tab, int row, int column,boolean isSelected) {
text = s;
rowIndex = row;
columnIndex = column;
table = tab;
font = table.getFont();
if (isSelected) {
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
}
}
public void paintComponent(Graphics gr) {
super.paintComponent(gr);
if ( text != null && !text.isEmpty() ) {
Graphics2D g = (Graphics2D) gr;
if (lineMeasurer == null) {
AttributedCharacterIterator paragraph = new AttributedString(text).getIterator();
paragraphStart = paragraph.getBeginIndex();
paragraphEnd = paragraph.getEndIndex();
FontRenderContext frc = g.getFontRenderContext();
lineMeasurer = new LineBreakMeasurer(paragraph,BreakIterator.getWordInstance(), frc);
}
float breakWidth = (float)table.getColumnModel().getColumn(columnIndex).getWidth();
float drawPosY = 0;
// Set position to the index of the first character in the paragraph.
lineMeasurer.setPosition(paragraphStart);
// Get lines until the entire paragraph has been displayed.
while (lineMeasurer.getPosition() < paragraphEnd) {
// Retrieve next layout. A cleverer program would also cache
// these layouts until the component is re-sized.
TextLayout layout = lineMeasurer.nextLayout(breakWidth);
// Compute pen x position. If the paragraph is right-to-left we
// will align the TextLayouts to the right edge of the panel.
// Note: this won't occur for the English text in this sample.
// Note: drawPosX is always where the LEFT of the text is placed.
float drawPosX = layout.isLeftToRight()
? 0 : breakWidth - layout.getAdvance();
// Move y-coordinate by the ascent of the layout.
drawPosY += layout.getAscent();
// Draw the TextLayout at (drawPosX, drawPosY).
layout.draw(g, drawPosX, drawPosY);
// Move y-coordinate in preparation for next layout.
drawPosY += layout.getDescent() + layout.getLeading();
}
table.setRowHeight(rowIndex,(int) drawPosY);
}
}
}
public Component getTableCellRendererComponent(
JTable table, Object value,boolean isSelected, boolean hasFocus, int row,int column
)
{
CellArea area = new CellArea(value.toString(),table,row,column,isSelected);
return area;
}
}
It resizes row heigth too but it does it well only when this renderer is used for a single column.
And this is the way I used to invoke it for render my table.
final int wordWrapColumnIndex = ...;
myTable = new JTable() {
public TableCellRenderer getCellRenderer(int row, int column) {
if (column == wordWrapColumnIndex ) {
return wordWrapRenderer;
}
else {
return super.getCellRenderer(row, column);
}
}
};

Change variables in one class from another class

FNAKLNFDKA.java
import java.awt.*;
import javax.swing.*;
public class GraphApplet extends JApplet{
private static final long serialVersionUID = 1L;
public static Graphics p;
public void init(){
SwingUtilities.invokeLater(new Runnable() {
public void run() {
});
}
}
FANKJ.java
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
class FASKHF extends JPanel {
public static Graphics p;
private static final long serialVersionUID = 1L;
public Graph(){
this.setBackground(Color.yellow);
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(560,560));
}
public static void updateGraph() {
repaint();
}
public void paint(Graphics F) {
//line co-ordinates
//the numbers represent the number of boxes on the graph
//1st line on the l/h side
int xstart1 = 2;
int ystart1 = 3;
int xfinish1 = 1;
int yfinish1 = 9;
//2nd line on the r/h side
int xstart2 = 8;
int ystart2 = 3;
int xfinish2 = 9;
int yfinish2 = 9;
//drawing upper arc
int arcX = 2;
int arcY = 1;
int imagRectWid = 6;
int imagRectHei = 4;
int startAngle = 0;
int arcAngle = 180;
//other
f = xaxis22;
g = xaxis11;
//to be assigned later.
//the values of xaxis and yaxis need to be separated
//yaxis3 = 5;
//yaxis4 = -5;
//change -ve num to +ve
int g3 = Math.abs(g);
int a1 = g3 + f;
int b1 = a1;
int d = (appletWidth / a1);
int e = (Height / b1);
/**
to determine the
ammount of pixles there
is in each box of the
graph, both y-axis and
x-axis
*/
int xbox = x1 / 10;
int ybox = y1 / 10;
//line variables
//the xstart, ystart, etc represent the number of boxes
//top point of the line on the graph
px1 = xbox * xstart1;//start x
py1 = ybox * ystart1;//start y
//lowwer point of the line on the graph
px = xbox * xfinish1;//finish x
py = ybox * yfinish1;//finish y
//other line on the right hand side
p2x = xbox * xstart2;
p2y = ybox * ystart2;
p2x2 = xbox * xfinish2;
p2y2 = ybox * yfinish2;
//drawing arc
int arcBoxX = arcX * xbox;
int arcBoxY = arcY * ybox;
int arcBoxWidth = imagRectWid * xbox;
int arcBoxHeight = imagRectHei * ybox;
//draw y-axis numbers
//(+ve)
while(f != 0){
String s = String.valueOf(f);
p.drawString(s,(x + 5),m + 13);
m = m + b;
f = f - 1;
}
//(-ve)
m2 = y;
while(f2 != g-1){
String u = String.valueOf(f2);
p.drawString(u,(x + 5),m2 - 3);
m2 = m2 + b;
f2 = f2 - 1;
}
//draw x-axis numbers.
//(-ve)
while(g != 0){
String t = String.valueOf(g);
p.drawString(t,n,y - 5);
n = n + a;
g = g + 1;
}
//(+ve)
n2 = x + a;
while(g2 != g3+1){
String vw = String.valueOf(g2);
p.drawString(vw,n2 -10,y - 5);
n2 = n2 + a;
g2 = g2 + 1;
}
BasicStroke aLine2 = new BasicStroke(1.0F,
BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
graph.setStroke(aLine2);
//notch on numbers and grid lines
//left to right, top to bottom notches
int v2 = -5;
int v5 = 0;
while(i <= a1-1){
p.drawLine(Da,0,Ea,y1);
a = a + d;
b = b + e;
i = i + 1;
}
//notches
while(i2 <= a1){
p.setColor(Color.blue);//notch color
p.drawString("x",v2+2,y+3);//xaxis
p.drawString("x",x-4,v5+4);//yaxis
v5 = v5 + e;
v2 = v2 + d;
i2 = i2 + 1;
}
}
}
}
import java.awt.*;
import javax.swing.*;
}
}
/*
* this code is to accept a user input in order for him to
* change the ranges of the xaxis and yaxis to his needs
*/
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JTextField;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class ControlsB extends JPanel{
private static final long serialVersionUID = 1L;
public static int xaxis1,xaxis2,yaxis3,yaxis4;
//public int xaxis11,xaxis22,yaxis33,yaxis44;
//public Object ControlsB;
//private Graph graph;
//public static Graphics p;
public String s;
public ControlsB(Box box2) {
JButton btn1 = new JButton("Resize");
final Box b = Box.createHorizontalBox();
b.add(new JLabel("Please enter range: "));
Box b0 = Box.createVerticalBox();//create a vertical box to stack the controls
Box b1 = Box.createHorizontalBox(); // create a horizontal box for the x-axis
//x-axis
b1.add(new JLabel("x-axis "));
b1.add(new JLabel("from"));
final JTextField f1 = new JTextField(" 0");
f1.setMaximumSize(new Dimension(100,30));
b.add(btn1);
}
protected Object Integer(int xaxis12) {
return null;
}
}
Now the problem with this program is; in ControlsB I have a method that places the controls at the bottom side (Under the yellow box / graph), now these controls are supposed to accept the range of the graph on the x-axis line (x-axis only at the moment because the code for the y-axis is not ready yet). When the user presses the "resize" button the graph should come up with the changes.
However this is not happening and the button is being pressed for nothing... and I cannot figure out what I have wrong.
In ControlsB file I have an action listener for the btn1 that is the "resize" button and a soon as the bottom is pressed it changes the text fields inputs (f1 and f2) into integers and assigned to x-axis1,x-axis 2,etc...
Now I am making a reference from theses variables (found in the action listener method) to the class Graph.java with this line: public static int xaxis11 = ControlsB.xaxis1;
Can anyone please let me know what is the best solution for this problem I have..??..
NOTE: all these files compile. but the graph does not come up.
The way that it is currently coded, you are assigning the xaxis11, xaxis22, yaxis33, and yaxis44 only one time. The variables are not updated dynamically when they change in ControlsB. This means that you simply have to update them each time the values change. To do this, add a method to your Graph class:
public static void updateGraph() {
xaxis11 = ControlsB.xaxis1;
xaxis22 = ControlsB.xaxis2;
yaxis33 = ControlsB.yaxis3;
yaxis44 = ControlsB.yaxis4;
}
Then, when the user changes the values in ControlsB, call Graph.update(). Make sure you are also calling repaint when this happens.
Also note that making all of these things static is not your only option. You can also simply have a reference to an object as a field of another class, set it in the constructor, and call methods on it when necessary. You may run into some problems with your implementation due to this problem, as making everything static may affect your ability to call repaint() on an object, which you need to do in order to update it.
A workaround to that problem would be to add repaint() to the bottom of the updateGraph method I outlined above.
When you set the static variables in Graph, you are making a copy of the variables in ControlB, so when you are chaning them in ControlB, the changes do not reflect in Graph. Instead access the variables through ControlB (preferably via a public method in ControlB)
Update
to enable calling repaint, remove all static modifies from Graph and ControlsB; add a variable holding the graph instance to ControlsB and pass that instance to its constructor
public class ControlsB extends JPanel
{
Graph my_graph;
//...
public ControlsB(Box box2, Graph graph)
{
my_graph = graph;
// ...
}
}
then change the updateGraph() method in Graph to
public void updateGraph(int xaxis1, xaxis2, yaxis3, yaxis4)
{
xaxis11 = xaxis1;
xaxis22 = xaxis2;
yaxis33 = yaxis3;
yaxis44 = yaxis4;
repaint();
}
and call it like this in the button's actionperformed() method:
graph.updateGraph(xaxis1, xaxis2, yaxis3, yaxis4);
Note: you don't seem to be using box2 in the ControlsB constructor, so you can remove that parameter.

Categories

Resources