I am learning Java Swing. I am trying to develop as simple app for learning purpose. There is are multiple issues in following code. I try to read a csv file and populate JComboBox on button click.
public class MyForm {
private JButton btnRead;
private JButton btnRead2;
private JComboBox cbCodes;
private JPanel mainPanel;
private DefaultComboBoxModel comboBoxModel;
public MyForm(){
// issue 1: I always get null pointer exception in this line
comboBoxModel = new DefaultComboBoxModel();
cbCodes = new JComboBox(comboBoxModel);
btnRead.addActionListener( e -> {
List<String[]> data = readData();
comboBoxModel.removeAllElements();
data.forEach(item -> comboBoxModel.addElement(item));
});
// issue 2: Since DefaultComboBoxModel was not working. I tried without it. As this I get correct data in the array. But when I make JComboBox with array. Nothing is filled. It is empty.
btnRead2.addActionListener( e -> {
List<String[]> data = readData();
String[] array = new String[data.size()];
data.toArray(array);
cbCodes = new JComboBox(array);
});
}
// issue 3: I can't complie the code without this empty method. Why do I need it?
// error: Form contains components with Custom Create option but no createUIComponents() method
void createUIComponents(){
}
public List<String[]> readData() {
String file = "data.csv";
List<String[]> content = new ArrayList<>();
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
String line = "";
while ((line = br.readLine()) != null) {
if(line.contains("\"")){
content.add(line.split(" "));
}
content.add(line.split(","));
}
} catch (FileNotFoundException e) {
//Some error logging
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
public static void main(String[] args) {
JFrame frame = new JFrame("MyForm");
frame.setContentPane(new MyForm().mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
I make my question in the source code with the comment to show exactly here those issues are involved.
You don't get the NullPointerException in the lines you indicated, but in the line btnRead.addActionListener( e -> { because btnRead has not been initialized yet!
When you create a new JComboBox, you have to add it to the panel, too. Just creating it with new will not display it. But the real problem behind it is: you're using the model wrong. Write
comboBoxModel.removeAllElements();
for (final String string : array) {
comboBoxModel.addElement(string);
}
to solve that.
The problem you have here does not lie within the code you provided, but from another component. At some point, someone used a UI designer. Those designers usually create initialization methods, just like createUIComponents. See where that method gets called.
Synopsis:
All in all, your code is really chaotic. Restructure from new, this will clean up a lot of problems.
And initialize UI components as soon as possible, best do it in the declaration line: private final JButton btnRead = new JButton("Read!");
I strongly recommend using an IDE like Eclipse or IntelliJ that will help you write clean code and see and correct problems easier.
Related
I'm a bit new to programming so sorry if there is a few things that could have been done better
My combobox is successfully filled with my string array and the auto-complete works fine. I just cant get the text in the combobox.
returns java.lang.NullPointerException
private ArrayList<String> arrRekening;
private ArrayList<String> arrEienaar;
private String[] sarrRekening;
private String[] sarrEienaar;
public NewConnectionPoint() {
arrAccount = new ArrayList<String>();
arrOwner = new ArrayList<String>();
FillCombo(arrAccount , "Owners", "OwnerName");
FillCombo(arrOwner , "Accounts", "AccountName");
sarrOwner= arrOwner.toArray(new String[arrOwner .size()]);
sarrAccount= arrAccount.toArray(new String[arrAccount.size()]);
JComboBox<String> comboAccount = new JComboBox<String>();
AutoCompleteSupport<String> supAccount = AutoCompleteSupport.install(comboRekening, GlazedLists.eventList(Arrays.asList(sarrAccount)));
supAccount.setStrict(true);
JComboBox<String> comboOwner = new JComboBox<String>();
AutoCompleteSupport<String> supOwner = AutoCompleteSupport.install(comboOwner,GlazedLists.eventList(Arrays.asList(sarrOwner)));
supOwner.setStrict(true);
JButton btnShow = new JButton("ShowSelectedr");
btnShow.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
//Error occurs at this line
JOptionPane.showMessageDialog(null, comboOwner.getSelectedItem().toString());
});}
}
//Data loaded into arraylists from a Database with sql
private void FillCombo(ArrayList<String> ComboElements, String sTable, String sColumn){
try{
Data.changeQuery(sTable);// database connection fine returns and fills combobox
while(MyData.rs.next()){
String sReturn= MyData.rs.getString(sColumn);
ComboElements.add(sReturn);
}
}catch(Exception e){
JOptionPane.showMessageDialog(null, e);
}
}
The fundamental difficulty you're experiencing here is that you're trying to leverage the GlazedLists package without properly embracing it's core utility: EventLists.
You can easily side-step your difficulties if you use EventLists rather than ArrayLists.
If you really want to you can keep your FillCombo method returning an ArrayList (perhaps better name as getElements()) but straight-away initiate an EventList, use the GlazedLists EventComboBoxModel to link the EventList to the JComboBox and then you'll find your combobox getSelectedItem() should work fine.
The modified code to hook a list up to a combobox with autocomplete support will look something like this:
...
FillCombo(arrOwner , "Owners", "OwnerName");
EventList<String> ownerEventList = GlazedLists.eventList(arrOwner);
EventComboBoxModel<String> ownerModel = new EventComboBoxModel<String>(ownerEventList);
JComboBox comboOwner = new JComboBox(ownerModel);
AutoCompleteSupport<String> supOwner = AutoCompleteSupport.install(comboOwner,ownerEventList);
supOwner.setStrict(true);
...
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MyCalculatorGUI extends JFrame implements ActionListener {
JButton tripled, doubled;
JTextField input, output;
JPanel p1, p2;
MyCalculatorGUI() {
Container c = getContentPane();
tripled = new JButton("Triple");
tripled.addActionListener(this);
doubled = new JButton("Doubled");
doubled.addActionListener(this);
input = new JTextField("Input a number here.");
output = new JTextField("Result..");
p1.add(doubled);
p1.add(tripled);
p2.add(input);
p2.add(output);
c.add(p1);
c.add(p2);
setVisible(true);
setSize(400,400);
}
public void actionListener(ActionEvent e) {
}
public static void main(String[] args) {
MyCalculatorGUI output = new MyCalculatorGUI();
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
}
Eclipse is having a problem with my code where it is MyCalculatorGUI, it says the local variable is not used. Can somebody help me fix this?? I have recently just moved to Eclipse and everything I have tried to fix this isn't working for me.
I think you have created an object and not using it anywhere in main method
MyCalculatorGUI output = new MyCalculatorGUI();
This is just a warning by Eclipse. It cannot see that your actual logic happens inside the constructor - so it thinks you create a new object of your class MyCalculatorGUI inside the main method, but never use it. This could be a sign for unnecessary memory usage/consumption which might be a problem in large projects...
IF you change the line to just new MyCalculatorGUI(); the warning will disappear.
This is not an error, it's just a warning.
It simply means that you have created a variable which is never accessed later in the code. If you don't need it, then don't create it. If you do then just make use of it ;)
MyCalculatorGUI output = new MyCalculatorGUI(); //either delete this line
output.someMethod(); //or use the instance in some way
The warning should dissapear afterwards.
You don't use the variable you created in the main method, so either don't create it, use it or add the following above the main method: #SuppressWarnings("unused")
It's not a problem, it's just an Eclipse information to inform you that your local variable is not used. You can compile with 0 problem!
To resolve the warning you have two solutions:
First:
Implement the variable:
MyCalculatorGUI myCalculator = new MyCalculatorGUI();
Second:
Use the SupressWarnings on the top of your function like that:
#SuppressWarnings("unused")
MyCalculatorGUI() {
Container c = getContentPane();
tripled = new JButton("Triple");
tripled.addActionListener(this);
doubled = new JButton("Doubled");
doubled.addActionListener(this);
input = new JTextField("Input a number here.");
output = new JTextField("Result..");
p1.add(doubled);
p1.add(tripled);
p2.add(input);
p2.add(output);
c.add(p1);
c.add(p2);
setVisible(true);
setSize(400,400);
}
I've created a small application that reads data about university subjects from an XML file.
I can add new subjects, etc.
My problem however is that I have another frame with a JComboBox in it which is filled only via one method, which is called whenever I make a change (either reading from an XML file or adding a subject which is then added to my JTable and the XML file).
When I initially start my application it will automatically open a default XML file and read the contents, and add every subject to the combo box, just as I want. However, subsequent calls (like adding a subject or opening a new file) seem to have no effect, whatsoever.
The code in question:
public void fillComboBoxSubject(ArrayList<Subject> subjectList)
{
DefaultComboBoxModel<String> cbm = new DefaultComboBoxModel<String>();
for ( Subject subject : subjectList )
{
cbm.addElement( subject.getName() ); //getName() returns a String
System.out.println(subject.getName());
}
comboBoxSubject.setModel(cbm);
}
The println will display me every single subject if I open a new file, the combo box is not updated, though.
Regards,
LML
edit: SSCCE
Contains all appearances of the combo box:
public class FEnterMark extends JFrame
{
private JComboBox<String> comboBoxSubject;
public FEnterMark()
{
comboBoxSubject = new JComboBox<String>();
comboBoxSubject.setBounds(83, 8, 140, 20);
contentPane.add(comboBoxSubject);
}
public void fillComboBoxSubject(ArrayList<Subject> subjectList)
{
DefaultComboBoxModel<String> cbm = new DefaultComboBoxModel<String>();
for ( Subject subject : subjectList )
{
cbm.addElement( subject.getName() );
System.out.println(subject.getName());
}
comboBoxSubject.setModel(cbm);
}
}
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
//Return the string "stats" to gameLoop() as cmd
}
});
public void gameLoop(){
Scanner lineScanner = new Scanner(System.in);
cmd = "";
System.out.print(getBoard().printBoard(false));
while (!cmd.equals("quit")) {
System.out.print(">");
Scanner wordScanner = new Scanner(lineScanner.nextLine());
if (wordScanner.hasNext()) {
cmd = wordScanner.next();
if (cmd.equals("board")) {
System.out.print(getBoard().printBoard(false));
} else if (cmd.equals("ships")) {
System.out.print(getBoard().printBoard(true));
} else if (cmd.equals("help")) {
printHelp();
} else if (cmd.equals("stats")) {
printStats();
} else if (cmd.equals("fire")) {
if(fire(wordScanner)) {
printStats();
cmd = "quit";
}
} else if (cmd.equals("quit")) {
} else if (!cmd.equals("")) {
System.out.println(ILLEGAL_COMMAND);
}
}
}
}
What I'm trying to do is that when the user clicks the statsButton, the String cmd in the gameLoop would be changed to "stats". The statsButton and the gameLoop() are located in two different classes. Anyone can give me an idea how to do it? (I've attempted pipedreader/pipedwriter) and I just can't seem to get it right.
*I'm basically trying to make my console application into a GUI application without changing the original console application.
Edit: What I've tried
Class textBased
PipedInputStream in = new PipedInputStream()
public void gameLoop(){
try{
in.connect(GUIclass.out);
Scanner lineScanner = new Scanner(in);`
Class GUIclass
PipedOutputStream out = new PipedOutputStream();
PrintWriter writer;
public GUIclass(){
final PrintWriter writer = new PrintWriter(out);
statsButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
writer.println("stats");
}
});
that's what I tried writing but it doesn't seem to work.
Regarding
I'm basically trying to make my console application into a GUI application without changing the original console application..."
My advice is simple: "don't do it".
The two applications have completely different structure, one being linear, the other being event-driven, and are not directly translatable to each other. Better to make a new GUI program from the ground up. Now if your non-GUI application contains some well-structured and behaved object-oriented classes, then by all means use those classes in your GUI's "model" or logic section, but don't try to directly translate the program flow of one type of application to the other.
Edit
Based on your posted requirements:
"You should be able to play your Battleship game through your GUI interface. In addition, the text-based front-end you wrote for project 1 should still "work" and be playable."
Correct me if I'm wrong, but I'm betting that you have several classes involved here, and only one of them is the "text-based front-end". If so, then use the non front-end classes as the model of your GUI as I suggested above, but do not use the text-based front-end for anything GUI related, and do not try to emulate it in your GUI.
Have the console application instantiate the button ActionListener and pass it to the UI. When the action event is fired, the listener will tell the console app that it happened. The method in the ActionListener will tell it what to do.
I agree with Hovercrafts comment (changed to a reply).
But in general for problems like this I would change the method signature of your gameLoop(). I would use:
public void gameLoop(Reader reader)
Then you can pass different types of readers to the loop depending on the requirement.
For a console you might do something like:
gameloop( new InputStreamReader( System.in ) );
For a GUI you could do something like:
gameLoop ( new StringReader("some text") );
Edit:
Without changing the method signature you can redirect System.in to come from the String retrieved by the ActionListener:
public class Test
{
public static void main(String args[]) throws Exception
{
String text = "some text";
System.setIn( new ByteArrayInputStream( text.getBytes() ) );
// gameloop();
Scanner lineScanner = new Scanner(System.in);
System.out.println( lineScanner.nextLine() );
}
}
If you have something like this :
class B {
public void gameLoop(){
..
}
}
and
class A{
statsButton.addActionListener(new ActionListener() {
...
});
}
You can declare reference to B in A with final . In that case it's will be visible in inner class ActionListener.
class A{
final B b = ...; //final variable is visible in inner class
statsButton.addActionListener(new ActionListener() {
b.gameLoop();
...
});
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 4 years ago.
Improve this question
Hey, I've been developing an application in the windows console with Java, and want to put it online in all of its console-graphics-glory.
Is there a simple web applet API I can use to port my app over?
I'm just using basic System.out and System.in functionality, but I'm happy to rebuild my I/O wrappers.
I think something along these lines would be a great asset to any beginning Java developers who want to put their work online.
Sure, just make into an applet, put a small swing UI on it with a JFrame with two components - one for writing output to, and one for entering inputs from. Embed the applet in the page.
I did as Lars suggested and wrote my own.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.awt.Font;
public class Applet extends JFrame {
static final long serialVersionUID = 1;
/** Text area for console output. */
protected JTextArea textArea;
/** Text box for user input. */
protected JTextField textBox;
/** "GO" button, in case they don't know to hit enter. */
protected JButton goButton;
protected PrintStream printStream;
protected BufferedReader bufferedReader;
/**
* This function is called when they hit ENTER or click GO.
*/
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
goButton.setEnabled(false);
SwingUtilities.invokeLater(
new Thread() {
public void run() {
String userInput = textBox.getText();
printStream.println("> "+userInput);
Input.inString = userInput;
textBox.setText("");
goButton.setEnabled(true);
}
}
);
}
};
public void println(final String string) {
SwingUtilities.invokeLater(
new Thread() {
public void run() {
printStream.println(string);
}
}
);
}
public void printmsg(final String string) {
SwingUtilities.invokeLater(
new Thread() {
public void run() {
printStream.print(string);
}
}
);
}
public Applet() throws IOException {
super("My Applet Title");
Container contentPane = getContentPane();
textArea = new JTextArea(30, 60);
JScrollPane jScrollPane = new JScrollPane(textArea);
final JScrollBar jScrollBar = jScrollPane.getVerticalScrollBar();
contentPane.add(BorderLayout.NORTH, jScrollPane);
textArea.setFocusable(false);
textArea.setAutoscrolls(true);
textArea.setFont(new Font("Comic Sans MS", Font.TRUETYPE_FONT, 14));
// TODO This might be overkill
new Thread() {
public void run() {
while(true) {
jScrollBar.setValue(jScrollBar.getMaximum());
try{
Thread.sleep(100);
} catch (Exception e) {}
}
}
}.start();
JPanel panel;
contentPane.add(BorderLayout.CENTER, panel = new JPanel());
panel.add(textBox = new JTextField(55));
textBox.addActionListener(actionListener);
panel.add(goButton = new JButton("GO"));
goButton.addActionListener(actionListener);
pack();
// End of GUI stuff
PipedInputStream inputStream;
PipedOutputStream outputStream;
inputStream = new PipedInputStream();
outputStream = new PipedOutputStream(inputStream);
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "ISO8859_1"));
printStream = new PrintStream(outputStream);
new Thread() {
public void run() {
try {
String line;
while ((line = bufferedReader.readLine()) != null) {
textArea.append(line+"\n");
}
} catch (IOException ioException) {
textArea.append("ERROR");
}
}
}.start();
}
}
This below code was in a separate class, "Input", which has a static "inString" string.
public static String getString() {
inString = "";
// Wait for input
while (inString == "") {
try{
Thread.sleep(100);
} catch (Exception e) {}
}
return inString;
}
Through-out the lifespan of the project I will probably maintain this code some more, but at this point - it works :)
As a premier example of a glorious and incredibly useful cnsole-like webapp, please see goosh, the Google Shell. I cannot imagine browsing the Net without it anymore.
Granted, there's no source code, but you might get out a bit of its magic by using Firebug or so.
Using a TextArea might be a bug-prone approach. Remember that you'll need to do both input and output to this TextArea and that you must thus keep track of cursor position. I would suggest that, if you really do this approach, you abstract away over a plain TextArea (inheritance, maybe?) and use a component that has, e.g. a prompt() to show the prompt and enable input and a also follows the usual shell abstraction of having stdin (an InputStream, that reads from the prompt, but can be bound to, let's say files or so) and stdout and possibly stderr, OutputStreams, bound to the TextArea's text.
It's not an easy task, and I don't know of any library to do it.
I remember seenig telnet client applet implementationa around years ago (back when people used telnet). Maybe you could dig them out and modify them.
System.out and System.in are statics and therefore evil. You'll need to go through your program replacing them with non-statics ("parameterise from above"). From an applet you can't use System.setOut/setErr/setIn.
Then you're pretty much sorted. An applet. Add a TextArea (or equivalent). Append output to the text area. Write key strokes to the input. Job done.