I'm making a Java interactive novel, but my JTextArea Disappears - java

My adventure game has a bunch of nested if statements to output something based on the input, but my JTextField only gets one input and then disappears. I want to get the JTextField to take unlimited inputs and use .append to to show them in the jtextarea. I want to have the program continue to take user inputs until the story path in the if statements end. If want to get input from a JTextField and put the output in the JTextArea and keep it there.
import java.awt.Dimension;
import java.awt.Font;
import java.awt.KeyboardFocusManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.IOException;
import java.util.Scanner;
import java.io.Reader;
import javax.swing.*;
import javax.swing.text.BadLocationException;
/*JakeBarcelona
*Date:May 5, 2016
*Program Name:StoryTester.java
*Description:
*/
public class StoryTester extends JFrame
{
static JTextField input = new JTextField(30);
static JTextArea fields = new JTextArea(30,50);
static Story ARoom=new Story();
public static void main(String[] args) throws BadLocationException
{
JFrame frame = new JFrame();
String story=new String();
JLabel intro = new JLabel(story);
//Sets the JLabels font and color
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//puts a red x to close it
Story wow = new Story();
String introduction=wow.intro();
//creates array field for text editing
fields.insert(introduction, 0);
String name= fields.getText(0,30);
//creates new Panel
JPanel myPanel=new JPanel();
//creates label for text box
myPanel.setPreferredSize(new Dimension(600,600));
myPanel.add(fields);
myPanel.add(input);
//puts a scroll bar and cancel and ok button
JScrollPane scroll = new JScrollPane(fields, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
myPanel.add(scroll);
int result = JOptionPane.showConfirmDialog(null, myPanel, "Story", JOptionPane.OK_CANCEL_OPTION);
if(result==JOptionPane.OK_OPTION);
{
String jake = input.getText();
String need = ARoom.storyStatements(jake);
System.out.println(need);
fields.append(need);
}
}
}

You are adding fields twice to the GUI, once to myPanel and once to the JScdrollPane, scrool, which is then added to myPanel. Don't do this, but rather add it to the JScrollPane only. You're also artificially constraining the size of your myPanel JPanel, and this is likely what's getting you into trouble.
Instead use layouts in a smart way by for instance giving myPanel a BorderLayout, adding the JScrollPane to the BorderLayout.CENTER position and the inputs JTextField to the BorderLayout.PAGE_END position. And don't set the preferred size of myPanel but rather let the text component column and row properties set their preferred size which will in turn set the preferred size of the myPanel JPanel.
Also you're using static fields inappropriately and in fact none of your current fields should be static.
For example
import java.awt.BorderLayout;
import javax.swing.*;
public class LayoutEg extends JPanel {
private static final int COLS = 50;
private static final int ROWS = 30;
private JTextField input = new JTextField(COLS);
private JTextArea fields = new JTextArea(ROWS, COLS);
public LayoutEg() {
// two methods below so that words wrap
fields.setWrapStyleWord(true);
fields.setLineWrap(true);
fields.setFocusable(false); // so we can't write directly into JTextArea
JScrollPane scrollPane = new JScrollPane(fields);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
setLayout(new BorderLayout(2, 2));
add(scrollPane, BorderLayout.CENTER);
add(input, BorderLayout.PAGE_END);
}
private static void createAndShowGui() {
LayoutEg mainPanel = new LayoutEg();
JFrame frame = new JFrame("Story GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}

Related

border and panel orginization

I'm having a very hard time with borders, I've looked through tutorials and examples and each seems to use a different style, I'm just trying to organise the content into separated borders. The content for the bottom panal isn't finished yet but I'm just trying to get it to work as is before adding more.
The compiler says there are problems on two lines java.lang.NullPointerException:
package question2;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.TitledBorder;
/**
* #author Matt Headley
This frame shows a data set and its statistics.
*/
public class ComputerStoreGUI extends JFrame
{
private JCheckBox item1;
private JCheckBox item2;
private JCheckBox item3;
private JCheckBox item4;
private JCheckBox item5;
private TitledBorder border;
private TitledBorder border2;
private static JPanel content;
private static JPanel top;
private static JPanel bottom;
private JTextField parts;
public ComputerStoreGUI()
{
JCheckBox item1 = new JCheckBox("Install Hard Drive - $25.00");
JCheckBox item2 = new JCheckBox("Install RAM - $15.00");
JCheckBox item3 = new JCheckBox("Remove Virus - $50.00");
JCheckBox item4 = new JCheckBox("Format Hard Drive - $80.00");
JCheckBox item5 = new JCheckBox("Quote Hourly Labour - $10.00");
item1.setHorizontalAlignment(JCheckBox.LEFT);
item2.setHorizontalAlignment(JCheckBox.LEFT);
item3.setHorizontalAlignment(JCheckBox.LEFT);
item4.setHorizontalAlignment(JCheckBox.LEFT);
item5.setHorizontalAlignment(JCheckBox.LEFT);
JTextField cost = new JTextField(10);
top = new JPanel(new FlowLayout(FlowLayout.LEFT));
top.add(item1);
top.add(item2);
top.add(item3);
top.add(item4);
top.add(item5);
bottom.add(cost); //here ????????
cost.setHorizontalAlignment(JTextField.CENTER);
}
public static void main(String[] args)
{
JFrame frame = new ComputerStoreGUI(); // and here ???????
content = new JPanel();
content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
top = new JPanel();
top.setBorder(BorderFactory.createTitledBorder("Standard Services"));
bottom = new JPanel();
bottom.setBorder(BorderFactory.createTitledBorder("Hourly Service"));
frame.setSize(250, 400);
frame.setTitle("LU Computer Store");
frame.setContentPane(content);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
content.add(top);
content.add(bottom);
frame.setVisible(true);
}
}
the end goal is to look something like this:
First, I dont see a reson to extend JFrame in your example. So without inheritance you can use composition like:
JFrmae frame = new JFrame();
Read more: Why do we need to extend JFrame in a swing application?
The compiler says there are problems on two lines
java.lang.NullPointerException:
Reason is, you have declared the JPanel bottom but without initializing you are trying to use it, from this line: bottom.add(cost);
Do something like:
bottom = new JPanel(new FlowLayout(FlowLayout.LEFT));
bottom.add(cost);
EDIT:
comment: It runs now, but the panels are tiny
Because you need to set layout for the parent JPanel, you can use BoxLayout, to add child panels one below another, like below:
content = new JPanel();
content.setLayout(new BoxLayout(content, BoxLayout.PAGE_AXIS));
In case if you want to add space between those two child panels, use as below:
content.add(top);
content.add(Box.createRigidArea(new Dimension(0,10)));
content.add(bottom);

Java FlowLayout

I am writing some Java code that allows the user to see a frame with JLabel, JTextField and JButton.
I want the JLabel to be called "Count" and I have a problem with FlowLayout.
I want the interface to look like this:
Instead, I have this:
This is my code:
package modul1_Interfate_Grafice;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Exercitiu04 implements ActionListener {
private JFrame frame;
private JLabel labelCount;
private JTextField tfCount;
private JButton buttonCount;
private int count = 0;
public void go() {
frame = new JFrame("Java Counter");
labelCount = new JLabel("Counter");
labelCount.setLayout(new FlowLayout());
frame.getContentPane().add(BorderLayout.CENTER, labelCount);
tfCount = new JTextField(count + " ", 10);
tfCount.setEditable(false);
labelCount.add(tfCount);
buttonCount = new JButton("Count");
labelCount.add(buttonCount);
buttonCount.addActionListener(this);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(350, 150);
frame.setLocation(400, 200);
}
#Override
public void actionPerformed(ActionEvent event) {
count++;
tfCount.setText(count + "");
}
public static void main(String[] args) {
Exercitiu04 a = new Exercitiu04();
a.go();
}
}
Solve it.
Instead of labelCount.setLayout(new FlowLayout());` i should have had
frame.setLayout(new FlowLayout());
From description of JLabel class,
JLabel is:
A display area for a short text string or an image, or both.
But here: labelCount.add(tfCount) and here labelCount.add(buttonCount) you're trying to put a textfield and a button into a label. In this case, positions of button and textfield are controlled by FlowLayout but position of the text in the label is not.
Instead of this, you should put all of your elements in common JPanel, like this:
...
frame = new JFrame("Java Counter");
frame.setLayout(new BorderLayout());
JPanel wrapper = new JPanel(); // JPanel has FlowLayout by default
labelCount = new JLabel("Counter");
labelCount.setLayout(new FlowLayout());
wrapper.add(labelCount);
tfCount = new JTextField(count + " ", 10);
tfCount.setEditable(false);
wrapper.add(tfCount);
buttonCount = new JButton("Count");
buttonCount.addActionListener(this);
wrapper.add(buttonCount);
frame.add(BorderLayout.CENTER, wrapper);
...
And, like MasterBlaster said, you should put swing methods in EDT.
There are only two things you should know about FlowLayout:
a) It is a default layout manager of the JPanel component
b) It is good for nothing.
This trivial layout cannot be achieved with FlowLayout.
When doing layouts in Swing, you should familiarize yourself
with some powerful layout managers. I recommend MigLayout and
GroupLayout.
package com.zetcode;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import net.miginfocom.swing.MigLayout;
/*
Simple UI with a MigLayout manager.
Author Jan Bodnar
Website zetcode.com
*/
public class MigLayoutCounterEx extends JFrame {
public MigLayoutCounterEx() {
initUI();
}
private void initUI() {
JLabel lbl = new JLabel("Counter");
JTextField field = new JTextField(10);
JButton btn = new JButton("Count");
createLayout(lbl, field, btn);
setTitle("Java Counter");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createLayout(JComponent... arg) {
setLayout(new MigLayout());
add(arg[0]);
add(arg[1]);
add(arg[2]);
pack();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
MigLayoutCounterEx ex = new MigLayoutCounterEx();
ex.setVisible(true);
});
}
}
The example is trivial. You just put the three components into the
cells.
Screenshot:
You shouldn't use setSize when dealing with FlowLayout. Instead use pack(). It makes the window just about big enough to fit all your components in. That should tidy things up for you

A Grid layout containing Card layouts - can it be done?

The goal is to display a table of cells, where all cells are independent of one another, and each cell has several optional displays (Imagine a Kakuro board, jeopardy board, ext.)
It's my first attempt at swing. After a lot of reading, I decided that my approach will be to first design each cell independently using a Card Layout (this part I'm happy with), and then to 'wrap' it in a grid layout.
This is probably where my lack of understanding in basic Swing raises its head:
When designing each cell I create a frame and add a panel to it:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Cell extends Component{
JFrame frame = new JFrame();
/* we'll use a card layout with a panel for each look of the cell */
CardLayout cardLayout = new CardLayout();
JPanel containterPanel = new JPanel();
JPanel firstPanel = new JPanel();
JPanel secondPanel = new JPanel();
JPanel thridpanel = new JPanel();
public Cell(){
/* assign the card layout to the container panel */
containterPanel.setLayout(cardLayout);
/* assign objects to the different panels - details not important for the sake of the question */
//....
/* add the different panels to the container panel and show the initial one */
containterPanel.add(firstPanel, "firstPanel");
containterPanel.add(secondPanel, "secondPanel");
containterPanel.add(thridpanel, "thridpanel");
cardLayout.show(containterPanel, "firstPanel");
/* add the container to the frame and display it*/
frame.add(containterPanel);
frame.setVisible(true);
}
}
This behaves nicely.
But my attempt to wrap it in a grid layout where each cell behaves like this is very clumsy:
import java.awt.*;
public class Board{
private static final int COLUMNS_NUM = 3;
private static final int ROWS_NUM = 3;
JFrame frame = new JFrame();
JPanel panel = new JPanel();
Cell cells[] = new Cell[COLUMNS_NUM * ROWS_NUM];
public Board(){
panel.setLayout(new GridLayout(ROWS_NUM, COLUMNS_NUM));
for (int i = 0; i <ROWS_NUM * COLUMNS_NUM; i++)
{
cells[i] = new Cell();
panel.add(cells[i]);
}
frame.add(panel);
frame.setVisible(true);
}
public static void main(String[] args) {
new Board();
}
}
What I get is a bunch of unrelated frames, separated from the main board frame.
clearly I'm not handling the frames correctly (should I create only one..?).
Any help in guiding me to the correct approach will be appreciated.
If Cells are to be added to Board, make them a JPanel, not a JFrame
An example:
import java.awt.CardLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
//make it a sub class of JPanel for easier implementation.
public class Cell extends JPanel{
public Cell(){
JPanel firstPanel = new JPanel();
//add a lable just so something is displayed
firstPanel.add(new JLabel(("Panel 1")));
JPanel secondPanel = new JPanel();
JPanel thridpanel = new JPanel();
CardLayout cardLayout = new CardLayout();
/* assign the card layout */
setLayout(cardLayout);
/* add the different panels to the container panel and show the initial one */
add(firstPanel, "firstPanel");
add(secondPanel, "secondPanel");
add(thridpanel, "thridpanel");
cardLayout.show(this, "firstPanel");
}
}
And a board to hold the cell:
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
//make it a sub class of JFrame for easier implementation.
public class Board extends JFrame{
private static final int COLUMNS_NUM = 3;
private static final int ROWS_NUM = 3;
Cell cells[] = new Cell[COLUMNS_NUM * ROWS_NUM];
public Board(){
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setPreferredSize(new Dimension(800, 800));
JPanel panel = new JPanel();
add(panel); //or better getContentPane().add(panel);
panel.setLayout(new GridLayout(ROWS_NUM, COLUMNS_NUM));
for (int i = 0; i <(ROWS_NUM * COLUMNS_NUM); i++)
{
cells[i] = new Cell();
panel.add(cells[i]);
}
pack();
setVisible(true);
}
public static void main(String[] args) {
new Board();
}
}
That is how it look like:

Why might a JTextArea made scrollable, fail to be scrollable?

Does anyone see an issue with my code that might prevent JTextArea to become scrollable when you query data which expands it's bounds, it also seems that some words are getting cut in half, but the JScrollPane, which is supposedly supposed to fix the issue is failing at doing so.
package guiprojj;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Map;
import javax.swing.*;
import com.eclipsesource.json.JsonObject;
import com.google.gson.JsonParser;
import com.json.parsers.JSONParser;
import com.json.parsers.JsonParserFactory;
public class gui {
public static void main(String[] args)
{
JFrame maingui = new JFrame("Gui");
JButton enter = new JButton("Enter");
final JTextArea movieinfo = new JTextArea(5,20);
final JTextField movietext = new JTextField(16);
final JScrollPane scrolll = new JScrollPane(movieinfo);
JPanel pangui = new JPanel();
pangui.add(movietext);
pangui.add(enter);
scrolll.add(movieinfo);
pangui.add(movieinfo);
maingui.setResizable(false);
maingui.setVisible(true);
movieinfo.setLineWrap(true);
movieinfo.setEditable(false);
maingui.add(pangui);
scrolll.getPreferredSize();
//pangui.setPreferredSize(new Dimension(300, 150));
//pangui.add(scrolll, BorderLayout.CENTER);
//movieinfo.add(scrolll);
maingui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
maingui.pack();
enter.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e)
{
System.out.println(Test.getMovieInfo(movietext.getText()));
JsonParserFactory factory=JsonParserFactory.getInstance();
JSONParser parser=factory.newJsonParser();
Map jsonData=parser.parseJson(Test.getMovieInfo(movietext.getText()));
String Title = (String)jsonData.get("Title");
String Year = (String)jsonData.get("Year");
String Plot = (String)jsonData.get("Plot");
movieinfo.setText("Title: "+Title+"\nYear: "+ Year +"\nPlot: "+Plot);
}
});
}
}
final JTextArea movieinfo = new JTextArea(5,20);
final JScrollPane scrolll = new JScrollPane(movieinfo);
JPanel pangui = new JPanel();
//scrolll.add(movieinfo);
//pangui.add(movieinfo);
pangui.add(scroll);
A component can only have a single parent. You create the scrollpane with the text area which is good. But then you add the textarea to the panel, which is bad since the text area gets removed from the scrollpane).
You need to add the scrollpane to the panel since this is the component that contains the text area.
I think you should use a ScrollPane.
JTextArea ta = new JTextArea();
JScrollPane sp = new JScrollPane(ta);

Replacing a JPanel with a different JPanel

Hi this is a bit of a basic question. In my code I create a gui in a constructor then nest a ActionListener class to handle button changes. This code will create the gui and the action listener runs through the actionPerformed method correctly. However, I've tried multiple ways to change the panel in the gui but I feel like the way I have the program set up it is not possible for this to work. Sorry if this is a repeat but after searching for a while on S.O. I haven't found a good example that would help me with my problem.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import org.math.plot.Plot2DPanel;
import org.math.plot.plotObjects.BaseLabel;
public class GraphGui extends JFrame {
//default width and height of the GUI
private static final int WIDTH = 1200;
private static final int HEIGHT = 700;
GraphPlot gp = new GraphPlot();
Plot2DPanel plotPanel =gp.determinePlotToPlot("duration");
/**
* This is the constructor that initializes the JFrame and the layout of the GUI.
* The radio buttons are also created here and grouped accordingly.
*/
public GraphGui() {
//title of GUI
setTitle("VibeTech Graph Gui");
//First JRadioButton for date vs duration
JRadioButton durToDate = new JRadioButton("Duration vs. Date");
durToDate.addActionListener(new RadioButtonListener());
durToDate.setActionCommand("duration");
durToDate.setSelected(true);
//JRadioButton for weight vs date
JRadioButton weightToDate = new JRadioButton("Weight vs. Date");
weightToDate.addActionListener(new RadioButtonListener());
weightToDate.setActionCommand("weight");
//JRadioButton for plan type vs date
JRadioButton planToDate = new JRadioButton("Plan vs. Date");
planToDate.addActionListener(new RadioButtonListener());
planToDate.setActionCommand("level");
//button group of the buttons to display them as one group
ButtonGroup group = new ButtonGroup();
group.add(planToDate);
group.add(weightToDate);
group.add(durToDate);
//create JPanel to add objects to
JPanel jplRadio = new JPanel();
jplRadio.setLayout(new GridLayout(0, 1));
//add radio buttons
jplRadio.add(planToDate);
jplRadio.add(weightToDate);
jplRadio.add(durToDate);
Plot2DPanel dvt = new Plot2DPanel();
dvt.addLinePlot("Duration over Time", gp.getDate(), gp.getDuration());
BaseLabel title = new BaseLabel("Duration over Time", Color.RED,
0.5, 1.1);
title.setFont(new Font("Courier", Font.BOLD, 20));
dvt.addPlotable(title);
dvt.setAxisLabels("Time", "Duration");
setLayout(new BorderLayout());
add(jplRadio, BorderLayout.WEST);
add(plotPanel, BorderLayout.EAST);
setSize(WIDTH, HEIGHT);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
//main method to run program
public static void main(String [ ] args)
{
//create new GUI
#SuppressWarnings("unused")
GraphGui test = new GraphGui();
}
//create a radio button listener to switch graphs on button press
class RadioButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("duration")) {
plotPanel = gp.determinePlotToPlot("duration");
} else if (e.getActionCommand().equals("weight")) {
plotPanel = gp.determinePlotToPlot("weight");
} else if (e.getActionCommand().equals("level")) {
plotPanel = gp.determinePlotToPlot("level");
}
//here is where I tried to do removes, adds, and validates but
//I have trouble getting to the frame itself to remove the JPanel
//component. I think this is a setup problem.
}
}
}
You would need to add the panel and revalidate/repaint the JFrame for it to appear:
add(plotPanel, BorderLayout.EAST);
revalidate();
repaint();
Better to use CardLayout to manage this type of functionality.
Try using CardLayout for switching between panels. Here is my solution for a similar question: https://stackoverflow.com/a/9377623/544983

Categories

Resources