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
Related
I am writing a GUI with Swing. I'm using a GridBagLayout to display multiple JLabels in a grid (basically like a chess board). As soon as I use a self made label class derived from JLabel instead of JLabel, the GridBagLayout stacks every label on the top left corner of the JPanel.
Either my subclass TileLabel is incorrect or I don't use the layout and constraints the right way. I think the last one because I can't see what would be a problem in such a minimal subclass.
This is how it looks using JLabel (L represents a label):
(MenuBar)
L L L L L L L L L
L L L L L L L L L
L L L L L L L L L
This is how it looks using TileLabel (S represents all the labels stacked):
(MenuBar)
S
This is my simple subclass from JLabel:
import javax.swing.JLabel;
public class TileLabel extends JLabel {
private static final long serialVersionUID = 6718776819945522562L;
private int x;
private int y;
public TileLabel(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
And this is the GUI class. I Marked the three lines where I used my custom label which lead to the layout problem.
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainGUI extends JPanel {
private static final long serialVersionUID = -8750891542665009043L;
private JFrame frame;
private MainMenuBar menuBar;
private TileLabel[][] labelGrid; // <-- LINE 1
private GridBagConstraints constraints;
private int gridWidth;
private int gridHeight;
// Basic constructor.
public MainGUI(int frameWidth, int frameHeight) {
super(new GridBagLayout());
constraints = new GridBagConstraints();
buildFrame(frameWidth, frameHeight);
buildLabelGrid(frameWidth, frameHeight);
}
// Builds the frame.
private void buildFrame(int frameWidth, int frameHeight) {
menuBar = new MainMenuBar();
frame = new JFrame("Carcasonne");
frame.getContentPane().add(this);
frame.setJMenuBar(menuBar);
frame.setResizable(false);
frame.setVisible(true);
frame.setSize(frameWidth, frameHeight);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBackground(new Color(165, 200, 245));
}
// Creates the grid of labels.
private void buildLabelGrid(int frameWidth, int frameHeight) {
gridWidth = frameWidth / 100;
gridHeight = frameHeight / 100;
labelGrid = new TileLabel[gridWidth][gridHeight]; // <-- LINE 2
for (int x = 0; x < gridWidth; x++) {
for (int y = 0; y < gridHeight; y++) {
labelGrid[x][y] = new TileLabel(x, y); // <-- LINE 3
constraints.gridx = x;
constraints.gridy = y;
add(labelGrid[x][y], constraints); // add label with constraints
}
}
}
// sets the icon of a specific label
public void paint(Tile tile, int x, int y) {
if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) {
labelGrid[x][y].setIcon(tile.getImage());
} else {
throw new IllegalArgumentException("Invalid label grid position (" + x + ", " + y + ")");
}
}
// Just to test this GUI:
public static void main(String[] args) {
MainGUI gui = new MainGUI(1280, 768);
Tile tile = TileFactory.createTile(TileType.Road);
for (int x = 0; x < 12; x++) {
for (int y = 0; y < 7; y++) {
gui.paint(tile, x, x);
}
}
}
}
Where is the problem?
There are quite a few things to fix in your code, but your problem originates from 3 things:
Your method definitions in your custom label:
public class TileLabel extends JLabel {
// #Override !!!!
public int getX() {
return x;
}
// #Override !!!!
public int getY() {
return y;
}
}
You are overriding JComponent's getX() and getY(), which are responsible for returning their coordinates. This messes up the layout completely.
Be careful with your paint method, a method with the same name exists in a superclass, though you are saved in this case since the arguments are different.
You have a typo at your loop: gui.paint(tile, x, x) should be gui.paint(tile, x, y).
The order in which you call your methods is wrong. First, you create the frame and display it, then you change its contents by adding the panel with the labels to it, then you change the text in the labels. You should do this the other way around.
My recommendations:
Make your paint method be made a member of your TileLabel class. It makes more sense.
Set the icons during creation of the labels, unless they are not known. If you can't, you might need to recalculate the space requirements.
Never make your layout dependent on the size of the screen or its resolution. It makes for a fragile GUI (as noted in the comments). Use pack() for the frame to calculate the correct size.
You have accidentally overridden JComponent#getX() and JComponent#getY(). The values returned by this method are not consistent with the values that the layout may set internally (via calls to setBounds or so). This messes up the layout.
(Admittedly, I did not really check whether this is the reason, but it likely is, and it is a problem in general!)
I'm not really keen on Java GUI, but am learning as I go. I am in the process of making a very simple and basic Sudoku puzzle. Right now I am just on the basic layout of it.
I wanted to see if there was a simple way of adding a text field to each little rectangle that I have drawn out (81 total rectangles - 9x9 puzzle). So that a user can type something in there.
I am delving into it, but wanted to get the code up here to see if anyone had any tips, cause truth be told, I am mega lost with this.
Here is what I have so far...
import java.awt.*;
import javax.swing.*;
class MyCanvas extends JComponent {
public void paint(Graphics g) {
int coordinateX = 0;
int coordinateY = 0;
// maximum 9 rows
int rows = 9;
int columns = 1;
// make a 9x9 puzzle
while (columns <= rows) {
//for loop to increment the boxes
for (int j = 1; j <= rows; j++) {
// add and assign coordinte x... equivalent to x = x + 30
coordinateX += 30;
// where x and y determine start of the box and 30 determines the size
g.drawRect(coordinateX, coordinateY, 30, 30);
} //end of for loop
//reset the value of x to start a new row
coordinateX = 0;
coordinateY += 30;
columns++;
} //end of while loop
} //end of void paint
} //end of class
public class DrawRect {
public static void main(String[] a) {
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(100, 100, 500, 500);
window.getContentPane().add(new MyCanvas());
window.setVisible(true);
} // end of void main
} // end of class
Hopefully someone has some pointers that could help me out, cause boy oh boy do I need it. Was kinda thrown into the lion's den without prior knowledge or practice, but I'm trying hard.
Thanks guys!!
You could use a GridLayout(9,9) and an array of arrays of JTextField's
This is, of course, just an example of how I would do it. There are other ways to do this.
Find below a generic example.
Solution
public static void main(String[] args) {
JTextField[][] boxes = new JTextField[9][9];
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(9,9));
frame.setSize(500, 500);
for (int i = 0 ; i < 9 ; i++){
for (int j = 0 ; j < 9 ; j++){
boxes[i][j] = new JTextField("0");
frame.add(boxes[i][j]);
}
}
frame.setVisible(true);
}
Output
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.....
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
I'm trying to use a double that has a very small value to produce one of a more regular size. For example, dividing 1/(double) would produce something like 14.12848572.... I then cast this double into an int to produce a number which I can use to draw an image in a JPanel.
The issue I've been having is that the image does not draw how I expect it to draw. I think this is because there's something I don't understand about how casting doubles works. Anyone who can tell me a bit about how this process actually goes down would be very helpful.
EDIT:
The purpose of this code is translating a monetary value into the size of a bar on a graph. The size of these bars should change as the value changes so that they utilize space in the most efficient manner.
Therefore...
Due to the nature of the monetary values, max will never be less than 430.
I want the image to be bigger the smaller xscale is. If there are fewer values to graph, xscale is smaller, and then the bars are drawn bigger.
EDIT:
The following image shows what my program is currently drawing. What I would like to draw is a series of bars on a bar graph. The xscale and associated variables are what I am primarily concerned with right now.
EDIT:
The SSCCE is completed (I think)! If you run this code, you will see the drawing I don't want. If you change barwidth to equal 7 or some normal int, you will see something that is more along the lines of what I want drawn. Please let me know if there is anything more I should do to make things easier!
EDIT: Copy/pasted wrong code, has been corrected (derp)
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class castingexample extends JPanel
{
private static int ypoint;
private static int barheight;
private static Color color;
private static int bars = 10;
private static int xpoint = 0;
private static int barwidth = 7;
private static double xscale = 7;
private static int yscaleplus = 10000;
private static int yscaleneg = 0;
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.add(new castingexample());
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,500);
}
public castingexample()
{
new Timer(100, new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
resize();
repaint();
}
}).start();
}
public void resize()
{
xscale = bars/(800 - bars*5);
xscale = 1/xscale;
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
for (int i = 0; i < bars; i++)
{
barheight = 200;
barwidth = (int) (xscale);
ypoint = 450 - barheight;
xpoint = 105+(barwidth + 5)*i;
if(ypoint < 450)
color = Color.green;
else
color = Color.red;
g.setColor(color);
g.fillRect(xpoint, ypoint, barwidth, barheight);
}
}
}
Here's some relevant code:
public void resize()
{
int max = 0;
int min = 0;
for (int i = 0; i < bars; i++)
{
if (getTime(i) > max)
max = (int)getTime(i);
}
yscaleplus = max/430;
/*
for (int i = (int)(getLife() - getRetire() + 1); i < bars; i++)
{
if (getTime(i) < min)
min = (int)getTime(i);
}
yscaleneg = Math.abs(min/200);
*/
xscale = bars/(800 - bars*5);
xscale = 1/xscale;
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.drawLine(100, 20, 100, 630);
g.drawLine(100, 450, 900, 450);
for (int i = 0; i < bars; i++)
{
barheight = (int) (getTime(i)/yscaleplus);
barwidth = (int) (xscale);
ypoint = 450 - barheight;
xpoint = 105+(barwidth + 5)*i;
if(ypoint < 450)
color = Color.green;
else
color = Color.red;
g.setColor(color);
g.fillRect(xpoint, ypoint, barwidth, barheight);
}
}
doubles do not store information as you seem to think, they store information as a value followed by an exponential value of 2^x, this removes the capability you are trying to use
take a look at Math.round(x) instead.
I stumbled upon a problem which i would like to solve it using Java. User inputs Larger Rectangle dimension (i.e L_width and L_height) and smaller rectangle dimension (i.e S_width and S_height). I would like to place as many smaller rectangle inside the larger rectangle and show it graphically.
for example: When the Larger Rectangle size is 4 x 5 and smaller rectangle size is 2 x 2, then the maximum number of smaller rectangle that i would be able to place it inside the larger rectangle is 4. I would like to show them graphically.
As im new to java, i wanted to know how i can approach this problem from programmatic point of view and what concept i have to use to achieve the same.
Initial code for calculating the maximum number of rectangles. Can any1 help me to show this result graphically using java
// Code Starts
import java.awt.Graphics;
import java.util.Scanner;
import javax.swing.JComponent;
import javax.swing.JFrame;
//Class to store the output of layout
class layout{
private int Cnt_BW_CW=0; // BoardWidth and CardWidth are arranged together
private int Cnt_BW_CH=0;
private int option=0; // Option 1: width-width Option 2: width-height
public int getCnt_BW_CW (){
return Cnt_BW_CW;
}
public int getCnt_BW_CH (){
return Cnt_BW_CH;
}
public int getoption (){
return option;
}
public void setCnt_BW_CW (int newValue){
Cnt_BW_CW = newValue;
}
public void setCnt_BW_CH (int newValue){
Cnt_BW_CH = newValue;
}
public void setoption (int newValue){
option = newValue;
}
}
// Stores the Dimension
class Dimension{
private float w,h;
Scanner input = new Scanner( System.in );
public Dimension(){
System.out.print( "Enter Width: " );
w = input.nextInt();
System.out.print( "Enter Height: " );
h = input.nextInt();
}
public Dimension(float width, float height){
w = width;
h = height;
}
public float getWidth (){
return w;
}
public float getHeight (){
return h;
}
public void setWidth (float newWidth){
w = newWidth;
}
public void setHeight (float newHeight){
h = newHeight;
}
}
class MyCanvas extends JComponent {
private static final long serialVersionUID = 1L;
public void paint(Graphics g) {
g.drawRect (10, 10, 200, 200);
}
}
public class boundedRect {
#SuppressWarnings("unused")
public static void main(String[] a) {
Dimension Board = new Dimension();
Dimension Card = new Dimension();
int Cnt =0;
Cnt = NumOfRect(Board, Card);
System.out.printf( "Number of Cards:%d",Cnt );
JFrame window = new JFrame();
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(30, 30, 300,300);
window.getContentPane().add(new MyCanvas());
window.setVisible(true);
}
public static int NumOfRect(Dimension b,Dimension c){
float bw,bh,cw,ch;
int bw_cw,bh_ch,bw_ch,bh_cw;
int SameDimensionCnt,DiffDimensionCnt;
int count;
layout Result = new layout();
bw =b.getWidth(); bh = b.getHeight();
cw =c.getWidth(); ch = c.getHeight();
if (bw < cw || bh < ch){
System.out.println( "Board and Card Dimension mismatch" );
System.exit(0);
}
bw_cw = (int)Math.floor(bw/cw);
bh_ch = (int)Math.floor(bh/ch);
SameDimensionCnt = bw_cw * bh_ch;
Result.setCnt_BW_CW(SameDimensionCnt);
bw_ch = (int)Math.floor(bw/ch);
bh_cw = (int)Math.floor(bh/cw);
DiffDimensionCnt = bw_ch * bh_cw;
Result.setCnt_BW_CH(DiffDimensionCnt);
System.out.printf( "Matching BW x CW: %d\n",SameDimensionCnt );
System.out.printf( "Matching BW x CH: %d\n",DiffDimensionCnt );
if (SameDimensionCnt < DiffDimensionCnt ){
count = DiffDimensionCnt;
System.out.println( "Align Board Width and Card Height" );
Result.setoption(2);
}else {
count = SameDimensionCnt;
System.out.println( "Align Board Width and Card Width" );
Result.setoption(1);
}
return count;
}
}
So you want to tile a large rectangle with a number of smaller rectangles. First define a class to represent the small rectangles, and create a data structure (probably an ArrayList) to hold them. Use a nested for loop to walk over the area of the large rectangle in S_width/S_height steps, and create as many small rectangles as will fit. Add them to the ArrayList as they are created. Search for ArrayList on Google to find the Java docs if you need them.
Then you need to write the code to draw them on the screen. For that, look up the official Java Tutorial on Google and read the section on graphics.
Try writing the code first and if you have problems, post your code here (you can edit the question).