Learning the MVC design pattern - java

I'm trying to get my head around the MVC design pattern using Swing in Java it's pretty confusing at the moment because I don't fully understand it. I have tried to make what I understand of it in eclipse but I have a error on line 68, I'm not sure why everytime I push a button I get a lot of errors being spat out and not the incrementing value of counter.
Thanks
public class Model
{
int counter = 0;
int counter()
{
this.counter++;
return this.counter;
}
}
#################################################################################
public class Controller
{
Model mRef;
View vRef;
public Controller(Model m, View v)
{
this.mRef = m;
this.vRef = v;
}
int inc()
{
mRef = new Model();
return mRef.counter();
}
}
######################################################################################
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class View extends JFrame
{
JPanel jp;
JButton jb1;
JLabel jl1;
GridBagConstraints c;
Controller con;
public View()
{
c = new GridBagConstraints();
jp = new JPanel();
jb1 = new JButton("First");
jl1 = new JLabel("Label");
jp.setLayout(new GridBagLayout());
add(jp);
c.gridx = 0;
c.gridy = 0;
jp.add(jb1, c);
jb1.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println(con.inc());
}
});
c.gridx = 0;
c.gridy = 2;
jp.add(jl1, c);
setVisible(true);
pack();
}
}

I recommend to consider using JavaFX, is simpler and prettier than Swing. It provides you with what is called a Scene Builder, where you can easily drag and drop controls to your user interface.
In the following link you can install the Scene Builder under Additional Resources.
http://www.oracle.com/technetwork/java/javase/downloads/index.html

Related

Word count for a scrollable JTextArea (scrollPane) word count

I have been trying to make a program where data inputted into a JTextArea, would then be counted and then displayed on a JLabel the number of words, after a button is clicked.
However the code I have tried to use, just shows the value of 1 everytime.
Any idea why?
`
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SPanel extends JPanel {
public SPanel(){
final TextAPanel textPanel = new TextAPanel();
final JLabel outputLabel = new JLabel();
JButton click = new JButton ("Click");
click.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
String word = textPanel.inputBox.getText();
System.out.println("Test: " +word);
}
});
}
}
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
public class TextAPanel extends JPanel {
public JTextArea inputBox = new JTextArea(20,10);
public JScrollPane scrollPane = new JScrollPane(inputBox);
TextAreaPanel(){
JLabel title = new JLabel("Please type in the box below:");
inputBox.setLineWrap(true);
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.NORTHWEST;
gc.gridx = 0;
gc.gridy = 0;
add(title,gc);
gc.gridx = 0;
gc.gridy = 1;
add(scrollPane, gc);
}
}
Just to put it in context, my JTextArea is on a seperate panel / class to the panel containing the button and JLabel.
Every time I run the program and click the button, after inputting some words the value is always one even if the text box is empty.
Well, if you create a new TextAPanel and assign it to the textPanel variable - then when you try to get input you get nothing, because the newly created panel doesn't contain anything. If textPanel is a field in your class, you should just remove the textPanel = new TextAPanel(); line and it should work fine. If you get a NullPointerException, it means you forgot to initialize it earlier in the code, you should probably do it in the constructor.
EDIT: OK, I made it work, the code is below. I have no idea how your program compiled, because in your TextAPanel class you had TextAreaPanel() method/constructor, which caused compilation error in my Eclipse. Anyway, I got this working, you'll need to complete it, but this should get you started:
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
#SuppressWarnings("serial")
public class SPanel extends JPanel {
public SPanel() {
final TextAPanel textPanel = new TextAPanel();
this.add(textPanel);
final JLabel outputLabel = new JLabel();
JButton click = new JButton("Click");
click.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
String word = textPanel.inputBox.getText();
System.out.println("Test: " + word);
System.out.println(word.split("\\s+").length);
}
});
this.add(click);
}
public static void main(String[] args) {
JFrame f = new JFrame();
f.add(new SPanel());
f.setVisible(true);
}
}
#SuppressWarnings("serial")
class TextAPanel extends JPanel {
public JTextArea inputBox = new JTextArea(20, 10);
public JScrollPane scrollPane = new JScrollPane(inputBox);
TextAPanel() {
JLabel title = new JLabel("Please type in the box below:");
inputBox.setLineWrap(true);
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints();
gc.anchor = GridBagConstraints.NORTHWEST;
gc.gridx = 0;
gc.gridy = 0;
add(title, gc);
gc.gridx = 0;
gc.gridy = 1;
add(scrollPane, gc);
}
}

Java ActionListener Return Variable To Method That Contains ActionListener

I have a method like so, which is given an array of JButton and returns their text whenever they are pressed:
public static String foo(JButton[] buttons) {
for (JButton i : buttons) {
i.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
return i.getText();
}
});
}
}
But, of course, this code will not compile because I am returning a variable to a null method. So, how would I have i.getText() return its output too the foo() method?
Edit, all of the code:
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class JCustomFrame {
public static void showMessageFrame(String title, String message,
String[] textOnButtons, ImageIcon icon) {
final JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.setBackground(Color.WHITE);
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.RELATIVE;
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(5, 5, 5, 5);
JLabel messageLabel = new JLabel(message);
messageLabel.setFont(messageLabel.getFont().deriveFont(16.0f));
panel.add(messageLabel, c);
c.gridy = 1;
c.gridx = 0;
for (int i = 0; i < textOnButtons.length; i++) {
JButton button = new JButton(textOnButtons[i]);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
return ((JButton) arg0.getSource()).getText();
frame.dispose();
}
});
button.setFont(button.getFont().deriveFont(16.0f));
panel.add(button, c);
c.gridx++;
}
if (icon == null) {
frame.setIconImage(new BufferedImage(1, 1,
BufferedImage.TYPE_INT_ARGB_PRE));
} else {
frame.setIconImage(icon.getImage());
}
frame.add(panel);
frame.setTitle(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
public static void main(String[] args) {
JCustomFrame.showMessageFrame("Test Frame",
"Do you really want to do this?", new String[] { "Hell No",
"Sure, Why Not" }, null);
}
}
This statement doesn't make sense:
So, how would I have i.getText() return its output too the foo() method?
The method foo() is no longer running after the ActionListeners have been added to the buttons, and certainly will have ended by the time a user pushes a button, as per the rules of event-driven programming. Instead, though you could have the ActionListeners change the state of a class, any class, and that should suffice. For instance:
class FooClass {
private String text;
public void foo(JButton[] buttons) {
for (JButton i : buttons) {
i.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
text = e.getActionCommand();
}
});
}
}
}
If you need greater detail on a viable solution, please tell us more details about your actual program and your specific problem.
Now if you actually needed a method to return the value of the button pressed, you would need to do this via notification mechanisms and a call-back method, but again the details of a solution will depend on the details of the actual problem and code.
Edit
You're trying to emulate a JOptionPane. Your solution is to either use a JOptionPane, adding a JPanel to it, or create your own using a modal JDialog:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JCustomFrame2 {
public static String showMessageFrame(Window owner, String title,
String message, String[] textOnButtons, ImageIcon icon) {
final JDialog dialog = new JDialog(owner);
StringBuilder sb = new StringBuilder();
// make it application modal!
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.setBackground(Color.WHITE);
GridBagConstraints c = new GridBagConstraints();
c.anchor = GridBagConstraints.EAST;
c.fill = GridBagConstraints.RELATIVE;
c.gridx = 0;
c.gridy = 0;
c.insets = new Insets(5, 5, 5, 5);
JLabel messageLabel = new JLabel(message);
messageLabel.setFont(messageLabel.getFont().deriveFont(16.0f));
panel.add(messageLabel, c);
c.gridy = 1;
c.gridx = 0;
for (int i = 0; i < textOnButtons.length; i++) {
JButton button = new JButton(textOnButtons[i]);
button.addActionListener(new ButtonListener(sb));
button.setFont(button.getFont().deriveFont(16.0f));
panel.add(button, c);
c.gridx++;
}
if (icon == null) {
dialog.setIconImage(new BufferedImage(1, 1,
BufferedImage.TYPE_INT_ARGB_PRE));
} else {
dialog.setIconImage(icon.getImage());
}
dialog.add(panel);
dialog.setTitle(title);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.pack();
dialog.setVisible(true);
return sb.toString();
}
private static class ButtonListener implements ActionListener {
private StringBuilder sb;
public ButtonListener(StringBuilder sb) {
this.sb = sb;
}
#Override
public void actionPerformed(ActionEvent e) {
sb.append(e.getActionCommand());
Component component = (Component) e.getSource();
Window win = SwingUtilities.getWindowAncestor(component);
if (win != null) {
win.dispose();
}
}
}
public static String showMessageFrame(String title,
String message, String[] textOnButtons, ImageIcon icon) {
return showMessageFrame(null, title, message, textOnButtons, icon);
}
public static void main(String[] args) {
String result = JCustomFrame2.showMessageFrame("Test Frame",
"Do you really want to do this?", new String[] { "Hell No",
"Sure, Why Not" }, null);
System.out.println(result);
}
}
Why so complicated? whatever foo is supposed to do, it would be a lot easier to simply call another method from inside the ActionListener with the name of the button as argument. Or, if you really want to achieve something like this, make the thread wait for the user to press a button.
public void doSomething(){
JButton[] someButtons = ...;//whereever you create the buttons
System.out.println(foo(someButtons));
}
public static String foo(JButton[] buttons){
final String someString = "";
final Object lock = new Object();
for(JButton b : buttons){
b.addActionListener(e -> {
someString.concat(b.getName());
synchronized(lock){
lock.notifyAll();
}
});
}
synchronized(lock){
try{
lock.wait();
}catch(InterruptedException e){}
}
return someString;
}

JPanel in JApplet

I need to have one JPanel opened on start. I have a button on that one to open to another JPanel which contains a button to bring me back. How do i write action listeners for those buttons. I have searched extensively. Do I need a JFrame? All examples seem to have it.
Regardless of which approach you might take, the basic idea is the same. You need to know where to go based on where you are...
To this end, this simple example uses a simple navigation interface to provide movement control for the panels and a List to maintain the order of the components.
You could just as simply use a queue of some kind, pushing the next panel onto it and popping the last panel of it as you switched views.
This is a quick and simple example of CardLayout
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SwitchPanel extends JApplet{
private String currentView;
private List<String> viewNames;
#Override
public void init() {
final CardLayout cardLayout = new CardLayout();
setLayout(cardLayout);
Navigator navi = new Navigator() {
#Override
public void next() {
int index = viewNames.indexOf(currentView);
if (index > -1) {
index++;
if (index < viewNames.size()) {
currentView = viewNames.get(index);
cardLayout.show(getContentPane(), currentView);
}
}
}
#Override
public void previous() {
int index = viewNames.indexOf(currentView);
if (index > -1) {
index--;
if (index >= 0) {
currentView = viewNames.get(index);
cardLayout.show(getContentPane(), currentView);
}
}
}
};
MainPane mainPane = new MainPane(navi);
LastPane lastPane = new LastPane(navi);
viewNames = new ArrayList<>(2);
viewNames.add("main");
viewNames.add("last");
add(mainPane, "main");
add(lastPane, "last");
currentView = "main";
cardLayout.show(getContentPane(), "main");
}
public interface Navigator {
public void next();
public void previous();
}
public class MainPane extends JPanel {
private Navigator navigator;
public MainPane(Navigator navi) {
this.navigator = navi;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
JButton btn = new JButton("Next >");
add(new JLabel("Main"), gbc);
add(btn, gbc);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
navigator.next();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class LastPane extends JPanel {
private Navigator navigator;
public LastPane(Navigator navi) {
this.navigator = navi;
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
JButton btn = new JButton("< Previous");
add(new JLabel("Last"), gbc);
add(btn, gbc);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
navigator.previous();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}

Populating JList with List<String> nullpointerexception

I am trying to populate the JList using a file I create, before I write the code for adding things to the file that is being read, I would like to make sure it will be read, and display properly on the screen. I am getting a nullpointerexception, and my GUI is launching, but only the "enter" button is showing. I appreciate any help anyone can offer me with this issue.
package movieinfo;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.List;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Map;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import org.apache.commons.io.FileUtils;
import com.json.parsers.JSONParser;
import com.json.parsers.JsonParserFactory;
public class Swinggui {
private static JButton enter;
private static JTextField movietext;
private static JTextArea movieinfo;
private static JList listofmovies;//converts moviestowatch into gui element.
private static File textfilemovie; //file which movies marked for watching are saved
private static java.util.List<String> moviestowatch; //arraylist which is populated by textfilemovie than printed to GUI element.
public static void main(String[] args) throws IOException
{
Gui();
Json();
YourMovies();
}
public static void Gui()
{
JFrame maingui = new JFrame("Gui");
maingui.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.VERTICAL;
enter = new JButton("Enter");
c.gridx = 2;
c.gridy = 1;
maingui.add(enter, c);
movieinfo = new JTextArea(5,20);
movieinfo.setBorder(BorderFactory.createMatteBorder(2,2,2,2,Color.red));
movietext = new JTextField(18);
c.gridx = 1;
c.gridy = 1;
maingui.add(movietext, c);
final JScrollPane scrolll = new JScrollPane(movieinfo);
c.gridx = 1;
c.gridy = 4;
c.gridwidth = 2;
maingui.add(scrolll, c);
final JLabel titlee = new JLabel("Enter movie name below!");
c.gridx = 1;
c.gridy = 0;
maingui.add(titlee, c);
maingui.setResizable(false);
maingui.setVisible(true);
listofmovies = new JList(moviestowatch.toArray());
c.gridx = 2;
c.gridy = 3;
maingui.add(new JScrollPane(listofmovies), c);
movieinfo.setLineWrap(true);
movieinfo.setWrapStyleWord(true);
movieinfo.setEditable(false);
scrolll.getPreferredSize();
//pangui.setPreferredSize(new Dimension(300, 150));
//pangui.add(scrolll, BorderLayout.CENTER);
//movieinfo.add(scrolll);
maingui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
maingui.pack();
}
public static void Json()
{
enter.addActionListener(new ActionListener(){
#SuppressWarnings("rawtypes")
public void actionPerformed(ActionEvent e)
{
System.out.println(apicall.getMovieInfo(movietext.getText()));
JsonParserFactory factory=JsonParserFactory.getInstance();
JSONParser parser=factory.newJsonParser();
Map jsonData=parser.parseJson(apicall.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);
}
});
}
public static void YourMovies() throws IOException
{
textfilemovie = new File("yourmovies.txt");
moviestowatch = FileUtils.readLines(textfilemovie);
}
}
You're calling moviestowatch.toArray() before you instantiate moviestowatch. You need to call YourMovies() before you call Gui().
I see that in the method Gui() you are using an un-initialized list. The method where the list is getting initialized is called afterwards ( method YourMovies())
listofmovies = new JList(moviestowatch.toArray());
^^^^^^^^^^^^^
this is null
On a side note:
As per Java naming convention, methods start with small case and follow camel case, example - yourMovies() gui()
moviestowatch is not assigned when Gui is called - reverse the order of these methods
YourMovies();
Gui();
and follow Java naming conventions for method names with initial lowercase latter, e.g. loadMovies

is there a way to set a jbutton on top of a jbutton?

I am wondering about this since we are making a game in Swing and we made our map tiles into jButtons instead of jPanels for whatever reason. Now we want to put units on top of them so the map background is still shown when the unit is on top of them. Anyone know if this is possible?
OK, so I am not sure this is really what you are looking for and how your application is currently set up, but this is an example to have JButtons on top of each other (if this is not what you are looking for, consider posting an SSCCE and give more details). There are other alternatives and better way to handle such thing, but since you asked JButton over a JButton, here is a snippet showing that:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.basic.BasicButtonUI;
public class TestButtonGrid {
protected int x;
protected int y;
protected void initUI() throws MalformedURLException {
final JFrame frame = new JFrame();
frame.setTitle(TestButtonGrid.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JPanel panel = new JPanel(new GridBagLayout());
ImageIcon icon = new ImageIcon(new URL("http://manhack-arcade.net/pivot/isdrawing/tile_bluerock.png"));
ImageIcon unit = new ImageIcon(new URL("http://static.spore.com/static/image/500/642/783/500642783372_lrg.png"));
ButtonUI ui = new BasicButtonUI();
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
gbc.gridx = i;
gbc.gridy = j;
JButton button = new JButton(icon);
button.setBorderPainted(false);
button.setPreferredSize(new Dimension(icon.getIconWidth(), icon.getIconHeight()));
button.setUI(ui);
button.setOpaque(false);
panel.add(button, gbc);
if (i == j) {
// Choose a layout that will center the icon by default
button.setLayout(new BorderLayout());
JButton player = new JButton(unit);
player.setPreferredSize(new Dimension(unit.getIconWidth(), unit.getIconHeight()));
player.setBorderPainted(false);
player.setUI(ui);
player.setOpaque(false);
button.add(player);
}
}
}
frame.add(panel);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
new TestButtonGrid().initUI();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
});
}
}
It might be a better idea to have a panel which contains buttons. Your panel could then use a mouse event listener to perform an action when clicked on.
The advantage of using a jPanel is that you can set a layout within it, which will make positioning your buttons in it much easier.
Well it is possible to put a JButton Over an other JButton you just wont be able to see it.
CardLayout cl = new CardLayout();
JPanel jpnlMain = new JPanel(cl);
jpnlMain.add(new JButton(), "FIRST");
jpnlMain.add(new JButton(), "SECOND");
Then Maybe you could create a Class that Extends Either the Cardlayout or the JPanel to make it show both Items.
EDIT
Made a little Test and HJere is a Button in a Button Buttonception!!
Main class:
import javax.swing.JFrame;
public class Test {
public static void main(String[] arg0){
SpecialButton sp = new SpecialButton();
JFrame jf = new JFrame();
jf.add(sp);
jf.setVisible(true);
jf.pack();
}
}
Special Button Class:
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SpecialButton extends JButton{
SpecialButton(){
super();
JButton jbtnMid = new JButton();
JLabel jlblMid = new JLabel(new ImageIcon(this.getClass().getResource("/Images/arrowUpIcon.png")));
jbtnMid .add(jlblMid);
this.add(jbtnMid);
this.setVisible(true);
}
}

Categories