increase text font value with JButton issue - java

I have to create an interface which allows the user to increase/decrease the size of a piece of text and to show the current font size value of that text.
I have two buttons, increase and decrease.
I have two labels. One label has the text "X" which needs to change size every time a button is pressed. The other label has to display the current font size value of "X".
I have managed to implement the increase/decrease method for the text, however I cannot get the value of the text to increase after clicking. The value of the text when increased only allows the user to increase it once. I want the program to be able to increase it by 5 every time the button is activated.
I believe I have to somehow store the new value of the font size and use the new value to allow me to increase/decrease even more.
If anyone could tell me how to do this, or show a solution, it would be greatly appreciated.
package lab3;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FontSize extends JFrame{
JButton increase, decrease;
JLabel sizeX, sizeValue;
public static void main (String[]args){
FontSize changeFont = new FontSize();
changeFont.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
changeFont.setTitle("Increase/Decrease Font Size");
changeFont.setSize(900,700);
changeFont.setVisible(true);
changeFont.setLayout(new GridLayout(2,2));
}
public FontSize(){
increase = new JButton("increase");
increase.setBackground(Color.white);
increase.setFont(increase.getFont().deriveFont(30.0f));
add(increase);
decrease = new JButton("decrease");
decrease.setBackground(Color.white);
decrease.setFont(decrease.getFont().deriveFont(30.0f));
add(decrease);
sizeX = new JLabel("X", SwingConstants.CENTER);
sizeX.setBackground(Color.yellow);
sizeX.setFont(sizeX.getFont().deriveFont(30.0f));
add(sizeX);
int temp = sizeX.getFont().getSize();
sizeValue = new JLabel("",SwingConstants.CENTER);
sizeValue.setText(String.valueOf(temp));
sizeValue.setBackground(Color.yellow);
sizeValue.setFont(sizeValue.getFont().deriveFont(30.0f));
add(sizeValue);
event e = new event();
increase.addActionListener(e);
decrease.addActionListener(e);
}
public class event implements ActionListener {
public void actionPerformed(ActionEvent e){
String operation = e.getActionCommand();
int temp = sizeX.getFont().getSize();
int temp2 = sizeValue.getFont().getSize();
if(operation.equals("increase"))
{
temp = temp + 5;
sizeX.setFont(new Font("Arial", Font.PLAIN, temp));
temp2 = temp2 + 5;
sizeValue.setText(String.valueOf(temp2));
}
else if(operation.equals("decrease"))
{
temp = temp - 5;
sizeX.setFont(new Font("Arial", Font.PLAIN, temp));
temp2 = temp2 - 5;
sizeValue.setText(String.valueOf(temp2));
}
}
}
}

Simple fix really: on like 64 of the original code, you accidentaly are trying to count the variable temp2 as the size of the font of it, not the actual text. I've attached a slightly refactored, as well as corrected, version of the code.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FontSize extends JFrame implements ActionListener {
private JButton increase, decrease;
private JLabel sizeX, sizeValue;
public static void main (String[]args) {
FontSize changeFont = new FontSize();
changeFont.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
changeFont.setTitle("Increase/Decrease Font Size");
changeFont.setSize(900,700);
changeFont.setVisible(true);
changeFont.setLayout(new GridLayout(2,2));
}
public FontSize(){
increase = new JButton("increase");
increase.setBackground(Color.white);
increase.setFont(increase.getFont().deriveFont(30.0f));
add(increase);
decrease = new JButton("decrease");
decrease.setBackground(Color.white);
decrease.setFont(decrease.getFont().deriveFont(30.0f));
add(decrease);
sizeX = new JLabel("X", SwingConstants.CENTER);
sizeX.setBackground(Color.yellow);
sizeX.setFont(sizeX.getFont().deriveFont(30.0f));
add(sizeX);
int temp = sizeX.getFont().getSize();
sizeValue = new JLabel("",SwingConstants.CENTER);
sizeValue.setText(String.valueOf(temp));
sizeValue.setBackground(Color.yellow);
sizeValue.setFont(sizeValue.getFont().deriveFont(30.0f));
add(sizeValue);
increase.addActionListener(this);
decrease.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
String operation = e.getActionCommand();
int temp = sizeX.getFont().getSize();
int temp2 = Integer.parseInt(sizeValue.getText());
if(operation.equals("increase")) {
temp += 5;
sizeX.setFont(new Font("Arial", Font.PLAIN, temp));
temp2 += 5;
sizeValue.setText(String.valueOf(temp2));
} else if(operation.equals("decrease")) {
temp -= 5;
sizeX.setFont(new Font("Arial", Font.PLAIN, temp));
temp2 -= 5;
sizeValue.setText(String.valueOf(temp2));
}
}
}
Hope this helped, and best of luck to you.

int temp2 = sizeValue.getFont().getSize(); isn't the size of the font you're changing, but is the size of the font which is been used to render the label.
Try using something more like instead...
String operation = e.getActionCommand();
int temp = sizeX.getFont().getSize();
if (operation.equals("increase")) {
temp = temp + 5;
sizeX.setFont(new Font("Arial", Font.PLAIN, temp));
sizeValue.setText(String.valueOf(temp));
} else if (operation.equals("decrease")) {
temp = temp - 5;
sizeX.setFont(new Font("Arial", Font.PLAIN, temp));
sizeValue.setText(String.valueOf(temp));
}
You may also need to call revalidate(); and repaint(); at the end of the actionPerformed method to force a refresh, but it work okay without for me
Equally, you could just something like...
Font font = sizeX.getFont();
if (operation.equals("increase")) {
font = font.deriveFont(font.getSize() + 5f);
} else if (operation.equals("decrease")) {
font = font.deriveFont(font.getSize() - 5f);
}
sizeX.setFont(font);
sizeValue.setText(NumberFormat.getNumberInstance().format(font.getSize()));
Which allows you to maintain the font that the label was originally using, but increases/decreases it's size, but also relies on the actual Font size to update the display, rather the relying on calculated values...

Related

Java jFrame canvas draws dots instead of lines

I've been wanting to design a generator for dragon curves.
(If you want info on that check this out, but it doesn't really matter for the issue)
A dragon curve is a repeating mathematical construct.
I've already written a generator for what the canvas should draw, it works by returning a char array consisting of 'r' or 'l', saying whether the line has to turn left or right next. In the code here, it's the method input(). This part works perfectly.
The problem is that whenever I want to draw it on the canvas (using drawLine), it only draws the first two lines as actual lines, the rest are just dots.
The dots are on the right positions and if you make the thing really big, you can't tell the difference anymore, but nevertheless, there are supposed to be lines there.
Image:
This is the code I used:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
*
* Description
*
* #version 1.0 from 4/20/2016
* #author
*/
public class CurveGen extends JFrame {
// start attributes
private Canvas display = new Canvas();
private JButton startButton = new JButton();
private JLabel jLabel1 = new JLabel();
private JTextArea outText = new JTextArea("");
private JScrollPane outTextScrollPane = new JScrollPane(outText);
private JLabel jLabel2 = new JLabel();
private JSlider xSlider = new JSlider();
private JSlider ySlider = new JSlider();
private JNumberField iterationsNF = new JNumberField();
private JNumberField sizeNF = new JNumberField();
// end attributes
public CurveGen(String title) {
// Frame-Init
super(title);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int frameWidth = 1022;
int frameHeight = 731;
setSize(frameWidth, frameHeight);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - getSize().width) / 2;
int y = (d.height - getSize().height) / 2;
setLocation(x, y);
setResizable(false);
Container cp = getContentPane();
cp.setLayout(null);
// start components
display.setBounds(16, 64, 601, 601);
cp.add(display);
startButton.setBounds(736, 464, 241, 129);
startButton.setText("START!");
startButton.setMargin(new Insets(2, 2, 2, 2));
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
startButton_ActionPerformed(evt);
}
});
startButton.setFont(new Font("Dialog", Font.BOLD, 36));
cp.add(startButton);
jLabel1.setBounds(760, 96, 75, 41);
jLabel1.setText("Iterations:");
cp.add(jLabel1);
outTextScrollPane.setBounds(728, 392, 257, 57);
cp.add(outTextScrollPane);
jLabel2.setBounds(768, 144, 67, 41);
jLabel2.setText("Size:");
cp.add(jLabel2);
xSlider.setBounds(0, 8, 633, 49);
xSlider.setMinorTickSpacing(25);
xSlider.setMajorTickSpacing(100);
xSlider.setPaintTicks(true);
xSlider.setPaintLabels(true);
xSlider.setToolTipText("Starting point y-coordinate");
xSlider.setMaximum(600);
xSlider.setValue(300);
cp.add(xSlider);
ySlider.setBounds(624, 56, 65, 625);
ySlider.setMinorTickSpacing(25);
ySlider.setMajorTickSpacing(100);
ySlider.setPaintTicks(true);
ySlider.setPaintLabels(true);
ySlider.setOrientation(SwingConstants.VERTICAL);
ySlider.setMaximum(600);
ySlider.setInverted(true);
ySlider.setValue(300);
ySlider.setToolTipText("Starting point x-coordinate");
cp.add(ySlider);
iterationsNF.setBounds(856, 96, 81, 41);
iterationsNF.setText("");
cp.add(iterationsNF);
sizeNF.setBounds(856, 144, 81, 41);
sizeNF.setText("");
cp.add(sizeNF);
// end components
setVisible(true);
} // end of public CurveGen
// start methods
public static void main(String[] args) {
new CurveGen("CurveGen");
} // end of main
public char[] input(int iter) {
char oldOut[] = new char[0];
for (int i=1;i<=iter;i++) {
char newOut[] = new char[((int)Math.pow(2, i))-1];
for (int n=0;n<oldOut.length;n++) {
newOut[n] = oldOut[n];
if (oldOut[n]=='r') {
newOut[newOut.length-n-1] = 'l';
}
if (oldOut[n]=='l') {
newOut[newOut.length-n-1] = 'r';
} // end of if
} // end of for
newOut[oldOut.length]='l';
oldOut = newOut;
} // end of for
return oldOut;
}
public void startButton_ActionPerformed(ActionEvent evt) {
int iterations = iterationsNF.getInt();
int size = sizeNF.getInt();
char com[] = input(iterations);
outText.setText(String.valueOf(com));
int dir = 0;
int newDir = 0;
int lastPos[] = {xSlider.getValue(),ySlider.getValue()-size};
int newPos[] = {0,0};
Graphics g = display.getGraphics();
g.clearRect(0,0,601,601);
g.drawLine(xSlider.getValue(),ySlider.getValue(),xSlider.getValue(),ySlider.getValue()-size);
for (int i=0;i<=com.length-1;i++) {
dir = newDir;
if (dir==0) {
if (com[i]=='l') {
newPos[0] = lastPos[0]-size;
newPos[1] = lastPos[1];
newDir = 3;
}
if (com[i]=='r') {
newPos[0] = lastPos[0]+size;
newPos[1] = lastPos[1];
newDir = 1;
}
}
if (dir==1) {
if (com[i]=='l') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]-size;
newDir = 0;
}
if (com[i]=='r') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]+size;
newDir = 2;
}
}
if (dir==2) {
if (com[i]=='l') {
newPos[0] = lastPos[0]+size;
newPos[1] = lastPos[1];
newDir = 1;
}
if (com[i]=='r') {
newPos[0] = lastPos[0]-size;
newPos[1] = lastPos[1];
newDir = 3;
}
}
if (dir==3) {
if (com[i]=='l') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]+size;
newDir = 2;
}
if (com[i]=='r') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]-size;
newDir = 0;
}
}
g.drawLine(lastPos[0],lastPos[1],newPos[0],newPos[1]);
lastPos=newPos;
} // end of for
} // end of startButton_ActionPerformed
// end methods
} // end of class CurveGen
Okay, so I've gone back over the code...
Mixing heavyweight (java.awt.Canvas) and lightweight (Swing) components is unadvisable as they can cause or sorts of painting issues
getGraphics is not how paint should be done. Instead, I'd start with a custom JPanel and override its paintComponent. See Painting in AWT and Swing and Performing Custom Painting for more details
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
I believe the problem is associated with this...
lastPos=newPos;
All you are doing is making lastPos point to the same place in memory as newPos, so when you assign values to newPos, lastPos will have the same values, hence the reason you're seeing dots.
What I would do first, is separate the responsible for the generation of the data from the display.
I'd start with some kind of model (note, you could create a model which took iterations instead and which generated the data itself, but I was focusing on solving the initial problem)
public class DragonModel {
private Point startPoint;
private int size;
private char[] values;
public DragonModel(Point startPoint, int size, char[] values) {
this.startPoint = startPoint;
this.size = size;
this.values = values;
}
public Point getStartPoint() {
return startPoint;
}
public int getSize() {
return size;
}
public char[] getValues() {
return values;
}
}
and then the display...
public class DragonPane extends JPanel {
private DragonModel model;
public void setModel(DragonModel model) {
this.model = model;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (model != null) {
Graphics2D g2d = (Graphics2D) g.create();
int size = model.getSize();
int dir = 0;
int newDir = 0;
Point lastPos = model.getStartPoint();
Point newPos = new Point(0, 0);
for (char value : model.values) {
if (dir == 0) {
if (value == 'l') {
newPos.x = lastPos.x - size;
newPos.y = lastPos.y;
newDir = 3;
}
if (value == 'r') {
newPos.x = lastPos.x + size;
newPos.y = lastPos.y;
newDir = 1;
}
}
if (dir == 1) {
if (value == 'l') {
newPos.x = lastPos.x;
newPos.y = lastPos.y - size;
newDir = 0;
}
if (value == 'r') {
newPos.x = lastPos.x;
newPos.y = lastPos.y + size;
newDir = 2;
}
}
if (dir == 2) {
if (value == 'l') {
newPos.x = lastPos.x + size;
newPos.y = lastPos.y;
newDir = 1;
}
if (value == 'r') {
newPos.x = lastPos.x - size;
newPos.y = lastPos.y;
newDir = 3;
}
}
if (dir == 3) {
if (value == 'l') {
newPos.x = lastPos.x;
newPos.y = lastPos.y + size;
newDir = 2;
}
if (value == 'r') {
newPos.x = lastPos.x;
newPos.y = lastPos.y - size;
newDir = 0;
}
}
g.drawLine(lastPos.x, lastPos.y, newPos.x, newPos.y);
dir = newDir;
lastPos = new Point(newPos);
}
}
}
}
The idea here is to try and decouple of the responsibility a little, the responsibility for the generation and displaying of the data sit firmly in two different areas.
Then in your actionPerformed method you could simply do...
public void startButton_ActionPerformed(ActionEvent evt) {
int iterations = Integer.parseInt(iterationsNF.getText());
int size = Integer.parseInt(sizeNF.getText());
char com[] = input(iterations);
outText.setText(String.valueOf(com));
DragonModel model = new DragonModel(new Point(xSlider.getValue(), ySlider.getValue()), size, com);
display.setModel(model);
} // end of startButton_ActionPerformed
which could result in something like...
The drawing code should be inside the paint(Graphics) method to synchronize with the rendering loop properly. In an event handler, update the data model of the component (calculate the lines and keep them in a data structure inside the component), then call the method repaint() to trigger the event rendering loop, which will call your paint method.
There are some other variations of this, but the general idea is that you change the data and then request rendering. The rendering engine may call your paint method in other cases as well, not only when you change the data, so ideally paint() has all the data it needs to render fast, meaning it should not do calculations or heavy operations other than rendering on the Graphics object.
This means that you have to subclass JComponent in a new class, and implement paint inside it. This class should have an internal data structure with the lines ready to render at any point in time. Then use your new class in the JFrame.

Add values when JCheckBox clicked

My program contains a label with the caption “Choose a coffee” and four check boxes – Americano, Espresso, Double Espresso and Latte. Note: A JCheckBox array is recommended here)
I need to add event handling code to allow the user to purchase one or more items. The bill amount is displayed in a label after the user has made their selections.
The prices are Americano €3.75, Espresso €4.00, Double Espresso €4.50 and Latte €3.50. An array is suitable here also.
As the user makes a choice a label is displayed showing the bill.
I cant figure out how to add the cost when the check box is selected and remove the cost when it is de selected using the arrays.
Any help appreciated.
This is my code so far:
package Lab4EventHandling;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Frame3 extends JFrame implements ActionListener {
private Container cPane;
private JLabel tMsg, bMsg;
private JCheckBox americano, espresso, doubleEspresso, latte;
JCheckBox[] boxes = new JCheckBox[]{americano, espresso, doubleEspresso, latte};
private JPanel checkPanel = new JPanel(new GridLayout(0,1));
private Color cl;
private double cost = 0;
private final int WINDOW_WIDTH = 200;
private final int WINDOW_HEIGHT = 200;
private final int x = 550;
private final int y = 400;
public Frame3()
{
cPane = getContentPane();
cl = new Color(150, 150, 250);
cPane.setBackground(cl);
this.setLayout(new BorderLayout(0,1));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocation(x,y);
this.add(checkPanel, BorderLayout.CENTER);
tMsg = new JLabel("Choose a coffee:" ,SwingConstants.CENTER);
tMsg.setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
this.add(tMsg, BorderLayout.PAGE_START);
americano = new JCheckBox("Americano", false);
checkPanel.add(americano);
americano.addActionListener(this);
espresso = new JCheckBox("Espresso", false);
checkPanel.add(espresso);
espresso.addActionListener(this);
doubleEspresso = new JCheckBox("Double Espresso", false);
checkPanel.add(doubleEspresso);
doubleEspresso.addActionListener(this);
latte = new JCheckBox("Latte", false);
checkPanel.add(latte);
latte.addActionListener(this);
bMsg = new JLabel("Bill is ");
bMsg.setHorizontalAlignment(SwingConstants.CENTER);
bMsg.setBorder(BorderFactory.createEmptyBorder(4,4,4,4));
this.add(bMsg, BorderLayout.SOUTH);
this.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
this.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
Double[] array = {3.75, 4.00, 4.50, 3.50};
for (JCheckBox box : boxes) {
if(americano.isSelected())
{
cost += 3.75;
String r = String.valueOf(cost);
bMsg.setText(r);
}
if(espresso.isSelected())
{
cost += 4.00;
String r = String.valueOf(cost);
bMsg.setText(r);
}
else if(doubleEspresso.isSelected())
{
cost = 4.50;
String r = String.valueOf(cost);
bMsg.setText(r);
}
else if(latte.isSelected())
{
cost = 3.50;
String r = String.valueOf(cost);
bMsg.setText(r);
}
}
}
public class Frame3Test{
public static void main(String [] args)
{
Frame3 f = new Frame3();
f.setVisible(true);
}
}
Your first problem (which you may or may not have noticed) is your array of JCheckBoxes only contains null elements:
// check boxes are null here
private JCheckBox americano, espresso, doubleEspresso, latte;
// array created with only null elements
JCheckBox[] boxes = new JCheckBox[]{americano, espresso, doubleEspresso, latte};
So you need to create the array after instantiating the actual check boxes.
...
americano = new JCheckBox("Americano", false);
checkPanel.add(americano);
americano.addActionListener(this);
espresso = new JCheckBox("Espresso", false);
checkPanel.add(espresso);
espresso.addActionListener(this);
doubleEspresso = new JCheckBox("Double Espresso", false);
checkPanel.add(doubleEspresso);
doubleEspresso.addActionListener(this);
latte = new JCheckBox("Latte", false);
checkPanel.add(latte);
boxes = new JCheckBox[] {
americano, espresso, doubleEspresso, latte
};
Then the assignment is suggesting to use arrays because you can create another parallel array of prices (which you did). But since you need these prices in parallel you cannot use a for each loop. You need the index. Then you need to recalculate the entire cost every time anything is selected or deselected.
final double[] prices = {
3.75, 4.00, 4.50, 3.50
};
...
double total = 0.0;
for(int i = 0; i < boxes.length; i++) {
if(boxes[i].isSelected()) {
total += prices[i];
}
}
There's two other notes that seem to be outside the scope of the assignment:
You should always make a class for this kind of association.
You should never use double for money. Use BigDecimal or something like it.
Using a class makes logic simpler and not using double makes the calculation not incur error for this decimal addition.
class PricePair {
JCheckBox jCheckBox;
BigDecimal price;
}
BigDecimal total = new BigDecimal("0.00");
for(PricePair option : options) {
if(option.jCheckBox.isSelected()) {
total = total.add(option.price);
}
}
First of all, you're not handling all the checkboxes the same way. For the first two choices, you add the price to the cost:
cost += 3.75;
whereas for the last two choices, you replace the cost:
cost = 4.50;
The first way is the correct way.
Second, there's no reason to have the cost as a field. You should recompute the cost, and it should always start with 0, every time a checkbox selection changes. So cost should be a local variable of the actionPerformed() method.
Third, there's no reason to change the label value before you know the final cost. So the lines
String r = String.valueOf(cost);
bMsg.setText(r);
should only be there once, at the end of the actionPerformed() method, when the final cost is known.
Finally, you want to use it us an array instead of handling each checkbos separately. It's quite easy, you just need to loop over the checkboxes:
double prices = {3.75, 4.00, 4.50, 3.50};
double cost = 0.0;
for (int i = 0; i < boxes.length; i++) {
if (boxes[i].isSelected()) {
double price = prices[i];
cost += price;
}
}
// now display the cost in the label
Although both answers posted here are very helpful I'm adding this one because IMHO arrays are the less Object Oriented thing ever. You can achieve a more robust and OO solution following this hints:
Use
putClientProperty()
method inherited from
JComponent
to hold the prices in the check boxes.
Implement an ActionListener to add/substract the check box price to the total depending on the check box state. Use getClientProperty() method to retrieve the value stored in the check box.
See the example below:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Demo {
BigDecimal total = new BigDecimal(BigInteger.ZERO);
private void createAndShowGUI() {
final JLabel totalLabel = new JLabel("Total: ");
ActionListener actionListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JCheckBox checkBox = (JCheckBox)e.getSource();
BigDecimal value = (BigDecimal)checkBox.getClientProperty("price");
total = checkBox.isSelected() ? total.add(value) : total.subtract(value);
StringBuilder sb = new StringBuilder("Total: ").append(total);
totalLabel.setText(sb.toString());
}
};
JCheckBox americano = new JCheckBox("Americano");
americano.addActionListener(actionListener);
americano.putClientProperty("price", new BigDecimal("3.75"));
JCheckBox espresso = new JCheckBox("Espresso");
espresso.addActionListener(actionListener);
espresso.putClientProperty("price", new BigDecimal("4.00"));
JCheckBox doubleEspresso = new JCheckBox("Double Espresso");
doubleEspresso.addActionListener(actionListener);
doubleEspresso.putClientProperty("price", new BigDecimal("4.50"));
JCheckBox latte = new JCheckBox("Latte");
latte.addActionListener(actionListener);
latte.putClientProperty("price", new BigDecimal("3.50"));
JPanel content = new JPanel();
content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS));
content.add(americano);
content.add(espresso);
content.add(doubleEspresso);
content.add(latte);
content.add(totalLabel);
JFrame frame = new JFrame("Demo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(content);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Demo().createAndShowGUI();
}
});
}
}
This way you can forget about mapping every check box with a value using arrays or maps. If you need to add a new sort of coffee you should simply add 4 lines like this:
JCheckBox newCoffee = new JCheckBox("New Coffee");
newCoffee.addActionListener(actionListener);
newCoffee.putClientProperty("price", new BigDecimal("4.00"));
content.add(newCoffee);

JOptionPane keeps on overlapping values on JFrame

I'm new to JFrame, and I wanted to know why my JOptionPane won't stop popping up. When I type into the JOptionPane continuously, the values keep overlapping on the JFrame overtop of the previous ones, and it's keeping my program in a loop, preventing the printing process from opening up. I think it's because the program requests input values in a public void class rather than a public static void main class, but I don't know how to put these values on a JFrame otherwise because of the graphics component.
import java.awt.*;
import java.awt.print.PageFormat;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.swing.*;
public class Assignment3 extends JFrame
{
Assignment3()
{
setTitle("Amber's Skateboarders");
setSize(1200,720);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public void paint(Graphics g)
{
Font bigName = new Font("Ariel Bold", Font.BOLD, 20);
Font company = new Font("Comic Sans", Font.BOLD, 12);
Font myList = new Font("Comic Sans", Font.PLAIN, 12);
g.setFont(bigName);
g.drawString("Skateboarders", 15, 100);
String companyName;
String companyAddress;
int itemIndex = 0;
int pricesIndex = 0;
int quantityIndex = 0;
String[] merchandise = new String[1000];
double[] prices = new double[1000];
int[] quantity = new int[1000];
int addMore;
String[] options = {"Yes", "No"};
double subtotal = 0;
double[] result = new double[1000];
String[] list = new String[1000];
companyName = JOptionPane.showInputDialog(null, "What is your company name?");
g.setFont(company);
g.drawString(companyName, 15, 115);
companyAddress = JOptionPane.showInputDialog(null, "What is your company's address?");
g.setFont(company);
g.drawString(companyAddress, 15, 130);
do
{
merchandise[itemIndex] = JOptionPane.showInputDialog(null, "What is the name of the item you want?");
prices[pricesIndex] = Double.parseDouble(JOptionPane.showInputDialog(null, "How much does this cost?"));
quantity[quantityIndex] = Integer.parseInt(JOptionPane.showInputDialog(null, "How much of this item do you need?"));
itemIndex++;
pricesIndex++;
quantityIndex++;
addMore = JOptionPane.showOptionDialog(null, "Do you want to add more to your shopping cart?", "Before you go!", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE,null, options, options[0]);
}
while(addMore == 0);
int k;
g.setFont(myList);
if (addMore == 1)
{
for (int i = 0; i <= pricesIndex-1; i++)
{
result[i] = prices[i]*quantity[i];
}
for (double j : result)
{
subtotal += j;
}
for (k = 0; k<pricesIndex; k++)
{
list[k] = String.valueOf(quantity[k])+"\u00D7"+merchandise[k];
g.drawString(list[k], 15, k*15+145);
g.drawString("$" +String.valueOf(result[k]), 120, k*15+145);
//all += String.valueOf(quantity[k])+"\u00D7"+merchandise[k]+"\t\t\t"+String.valueOf(result[k])+"\n";
}
k=pricesIndex;
double taxes = subtotal*0.2;
g.setFont(company);
g.drawString("Subtotal: ", 15, k*15+145);
g.drawString("$"+String.valueOf(subtotal), 120, k*15+145);
k++;
g.drawString("Tax: ", 15, k*15+145);
g.drawString("$"+String.valueOf(taxes), 120, k*15+145);
k++;
g.drawString("Total: $", 15, k*15+145);
g.drawString("$"+String.valueOf(taxes+subtotal), 120, k*15+145);
}
public static void main(String[] args)
{
Assignment3 main = new Assignment3();
main.paint(null);
}
}
I think your problem in next:
1) You invoke your JOptionPane inside paint() method, it is'n proper way.
2) Why you draw your items with Graphics, I think you can use JLabel's or JTextField's as recommended by #trashgod. I recommend you to use JTable, i think it is suitable for your case. read tutorial for that.
3) You can add new items with help of button action(tutorial for button) instead of while looping.
4) If you want actually to draw your data on component. Extend JPanel class, add instance of it to your JFrame and paint in paintComponents(Graphics g) method.
As discussed in Painting in AWT and Swing: The Paint Methods, "Swing programs should override paintComponent() instead of overriding paint()." It's also highly unusual to evoke a dialog in a callback that is not under you control. Since you're mostly calling drawString() you may find it easier to simply update components such as JLabel and JTextField via setText(). If you want to update the drawing area automatically, use a modeless dialog, shown here.

How to Print on JTextArea

I'm learning to program in Java and I'm creating my first GUI App. It about creating 100 random numbers. I did it first on cmd like this:
public class RandomNumbers {
public static void main(String[] args){
float n = 100;
float m = 1513;
float a = 19713;
float x = 177963;
float c = 1397;
float r;
float i;
for(i=0;i<=n;i++){
r = (a*x+c)%m;
x = r;
r = r/m;
System.out.println(r);
}
}
}
For some reason when i try to print the 100 random numbers on a text area, it only prints me one.This is the code:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class GUIRandomNumbers extends JFrame implements ActionListener{
public JTextArea area;
public JScrollPane scroll;
public JButton button;
public RandomNumbers(){
setLayout(null);
area = new JTextArea();
area.setEditable(false);
scroll = new JScrollPane(area);
scroll.setBounds(10, 10, 400, 300);
add(scroll);
button = new JButton("Generate");
button.setBounds(10, 650, 100, 25);
add(button);
button.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
float n = 100;
float m = 1513;
float a = 19713;
float x = 177963;
float c = 1397;
float r;
float i;
if(e.getSource()==button){
for(i=0;i<=n;i++){
r = (a*x+c)%m;
x = r;
r = r/m;
area.setText(String.valueOf(r));
}
}
}
public static void main(String[] args) {
RandomNumbers p1 = new RandomNumbers();
p1.setBounds(0, 0, 500, 750);
p1.setVisible(true);
}
}
What could be the problem? I will really appreciae your help.
Thanks in advance.
when you do
area.setText(String.valueOf(r));
it overwrites the text on the text area with the new text.
you should use
area.append(String);
method instead.
Use this
area.append(String.valueOf(r) + "\n\r");
instead of
area.setText(String.valueOf(r));
setText(String) method replace the previous text. Use area.append(String) method.
Accordint to docs
Appends the given text to the end of the document. Does nothing if the model is null or the string is null or empty.
At first I suppose that you mean
GUIRandomNumbers p1 = new GUIRandomNumbers();
The reason that makes you see only one number is that one number is written above the other.
I mean that you write 100 times a random number in the textArea!
area.append("text");
is the method that will do your job!

Why is the entered text in my working JTextField not visible / selectable?

I am currently doing the CS106A Stanford Java course for beginners. I am stuck at the handout number 7, requiring me to create a simple program that draws GRects with a GLabel on them on the canvas and then allows me to drag them around, remove them again or clear the whole canvas. In order to add such a box, I have added a JTextField in the SOUTH to enter the name of the box, and ADD / REMOVE / CLEAR buttons.
Entering a name into the textfield to add a box works. My problem is that the text I type into the JTextField, though recorded (since it shows up on the new box) is not displayed in the JTextField itself, so I do not see what I typed until I hit "ADD" and I read it on the box itself.
Here's my code:
package handout07Interactors;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import javax.swing.*;
import acm.graphics.*;
import acm.program.*;
#SuppressWarnings("serial")
public class Box_Diagram extends GraphicsProgram{
public void init() {
displayButtons();
addActionListeners();
//TODO make draggable
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("ADD")) {
//create box
GCompound canvasBox = createBox(tf.getText());
//add box to HashMap
map.put(tf.getText(), canvasBox);
//add box to canvas
int x = (int) (getWidth() - canvasBox.getWidth()) / 2;
int y = (int) (getHeight() - canvasBox.getHeight()) / 2;
add(canvasBox, x, y);
} else if (e.getActionCommand().equals("REMOVE")) {
//remove box with name
if (map.get(tf.getText()) != null) {remove(map.get(tf.getText()));}; //if box exists, remove it
} else {
for( String name: map.keySet() )
{
remove(map.get(name));
}
}
}
private GCompound createBox(String text) {
// GCompound
GCompound box = new GCompound();
// create GRect
GRect rect = new GRect(BOX_WIDTH, BOX_HEIGHT);
box.add(rect);
// add GLabel
GLabel label = new GLabel(text);
int x = (int) (rect.getWidth() - label.getWidth()) / 2;
int y = 30; //manual entry, somehow calculation didn't work as it does for width
box.add(label, x, y);
map.put(text, box);
return box;
}
private void displayButtons() {
//label
add(new JLabel("Name:"), SOUTH);
//textfield
tf = new JTextField(30);
tf.addActionListener(this);
add(tf, SOUTH);
//ADD REMOVE CLEAR
add(new JButton("ADD"), SOUTH);
add(new JButton("REMOVE"), SOUTH);
add(new JButton("CLEAR"), SOUTH);
}
//IVARS
private JTextField tf;
public static final int BOX_WIDTH = 100;
public static final int BOX_HEIGHT = 50;
public HashMap<String, GCompound> map = new HashMap<String, GCompound>();
}
You're adding 5 different components (the label, text field, and the 3 buttons) to the same place in the layout (the SOUTH section of your border layout).
You should add these 5 components to another JPanel, using a FlowLayout for example, and then add this panel to the SOUTH of your main panel.
Sorry for my English - itsn't my first language.
I faced with this "strange behavior" in NameSurfer (Programming Assignments №6 CS106A) when I tried to use JTextField, but in Assignment №7 Section Assignments(the same which author pointed) everything were allright with JTextField.
I noticed that if I use JTextField in NORTH/WEST area JTextField works fine, for SOUTH/EAST I use TextField.

Categories