I fixed my prior problem yesterday by just separating all the classes into separate files. Nevertheless, I wrote all the code down and seeing no errors was able to compile the program. Or so I thought.
Here's the error code:
Exception in thread "main" java.lang.StackOverflowError
at java.util.AbstractCollection.<init>(Unknown Source)
at java.util.AbstractList.<init>(Unknown Source)
at java.util.Vector.<init>(Unknown Source)
at java.util.Vector.<init>(Unknown Source)
at java.util.Vector.<init>(Unknown Source
Here are the spots where my I get the errors(marked with problem?)
public class GameWorld implements IObservable, IGameWorld
{
// create collections class
public Vector<GameObject> GameObjectList = new Vector<GameObject>(); // PROBLEM
private Vector<IObserver> ObserverList = new Vector<IObserver>();
// declare objects
Tank pTank = new Tank(10, 10);
// other objects and variables to declare
public GameWorld()
{
// add objects to GameObjectList
}
// accessors/mutators
}
I get another error here
public class Tank extends Movable implements ISteerable
{
private int armorStrength;
private int missileCount;
public Tank()
{}
public Tank(int armStr, int misslCt) // problem?
{
armorStrength = armStr; // default armorStrength
missileCount = misslCt; // default missileCount
}
public void setDirection(int direction)
{
this.setDirection(direction); // get input from left turn or right turn
// updateValues();
}
// access/mutators here
I'm stumped on what to do here.
here's the main code
public class Starter {
public static void main (String args[])
{
Game g = new Game();
}
}
which has a Game class that is basically the GUI of the program
public class Game extends JFrame {
private GameWorld gw;
private MapView mv; // new in A2
private ScoreView sv; // new in A2
public Game() {
gw = new GameWorld(); // create “Observable”
mv = new MapView(); // create an “Observer” for the map
sv = new ScoreView(gw); // create an “Observer” for the game state data
gw.addObserver(mv); // register the map Observer
gw.addObserver(sv); // register the score observer
// code here to create menus, create Command objects for each command,
// add commands to Command menu, create a control panel for the buttons,
// add buttons to the control panel, add commands to the buttons, and
// add control panel, MapView panel, and ScoreView panel to the frame
setVisible(true);
}
}
and has a lot of references to other functions.
Related
I am often struggling with the same problem of custom Objects that creates a e.g. gui Component. And I never know what is the best way to get from the gui Component back to the object.
So multiple hacks and tricks are welcome.
Let me explain it to you:
This is my custom Object I need to find afterwards
public class MyObject {
int yearOfBirth;
String name;
public MyObject(int yearOfBirth, String name) {
this.yearOfBirth = yearOfBirth;
this.name = name;
}
public int getYearOfBirth() {
return yearOfBirth;
}
public Component getPanel() {
Component panel1 = makeTextPanel("This is the personal tab of "+name);
return panell;
}
}
This is where I need to find it through the Tab I am focusing
public class MyTabControl implements ChangeListener {
JTabbedPane myTabPane = new JTabbedPane();
public MyTabControl(){
//This will add a Listener for clicking on one Tab
myTabPane.addChangeListener(this);
}
public void oneMoreTab(MyObject myObject) {
myTabPane.addTab(myObject.name, myObject.getPanel())
}
public void stateChanged(ChangeEvent arg0) {
System.out.println("Focus of Tab changed");
int actualFocusedTabIndex = myTabPane.getSelectedIndex();
Component acutalFocusedComponent = myTabPane.getComponentAt(actualFocusedTabIndex);
//This works fine, I can get the Tab. Or at least the Component.
//But how do I get the yearOfBirth or better the Object itself?
int yearOfBirthOfTheSelectedTab = ???
}
}
This is just the main function
public static void main(String[] args) {
//Commands to start and create the GUI
MyTabControl myTabControl = new MyTabControl();
MyObject mother = new MyObject(1960, "Helen");
myTabControl.oneMoreTab(mother);
MyObject father = new MyObject(1955, "James");
myTabControl.oneMoreTab(father);
}
EDIT:
1 not working solution: Extend Component class
I have tried to extend the class Component. But this will create a failure (see comment in code):
public class ComponentWithExtras extends Component {
MyObject myObject;
public void addMyObject(MyObject myObject) {
this.myObject = myObject;
}
}
// The following line will create failure: Can't cast Component to ComponentWithExtras
ComponentWithExtras componentWithExtras = (ComponentWithExtras) myObject.getPanel();
componentWithExtras.addMyObject(myObject);
myTabPane.addTab(myObject.name, componentWithExtras);
I have an abstract GUI parent class handling a click event.
public abstract class GUI implements Listener {
private final Inventory inventory;
public GUI(Player player) {
Bukkit.getPluginManager().registerEvents(this, NPCs.getPlugin());
ItemStack fillerItem = new ItemStack(getFiller());
ItemMeta fillerItemMeta = fillerItem.getItemMeta();
fillerItemMeta.setDisplayName("");
fillerItem.setItemMeta(fillerItemMeta);
int inventorySize = (getFunctionalItems().size()>=54) ? 54 : getFunctionalItems().size()+(9-getFunctionalItems().size()%9)*Math.min(1, getFunctionalItems().size()%9);
inventory = Bukkit.createInventory(player, inventorySize, getName());
for(int i = 0; i < inventory.getSize(); i++) {
inventory.setItem(i, fillerItem);
}
for(int i = 0; i < getFunctionalItems().size(); i++) {
inventory.setItem(i, getFunctionalItems().get(i));
}
}
#EventHandler
public void onClick(InventoryClickEvent event) {
handle(event);
}
public abstract ArrayList<ItemStack> getFunctionalItems();
public abstract String getName();
protected abstract void handle(InventoryClickEvent event);
public Material getFiller() {
return Material.GRAY_STAINED_GLASS_PANE;
}
public Inventory getInventory() {
return inventory;
}
protected final ItemStack createFunctionalItem(String name, Material material) {
ItemStack itemStack = new ItemStack(material);
ItemMeta itemMeta = itemStack.getItemMeta();
itemMeta.setDisplayName(name);
itemStack.setItemMeta(itemMeta);
return itemStack;
}
}
In my child class it gets handled like following
#Override
public void handle(InventoryClickEvent event) {
ItemStack clicked = event.getCurrentItem();
Player player = (Player) event.getWhoClicked();
MainGUI mainGUI = new MainGUI(player);
NameGUI nameGUI = new NameGUI(player);
SkinGUI skinGUI = new SkinGUI(player);
//Main GUI
if(Arrays.equals(event.getClickedInventory().getContents(), mainGUI.getInventory().getContents())) {
switch(clicked.getItemMeta().getDisplayName()) {
case "Set Name" -> player.openInventory(nameGUI.getInventory());
case "Set Skin" -> player.openInventory(skinGUI.getInventory());
}
event.setCancelled(true);
}
}
But if I test it gets called 2 times on the first click and on the following so many times it even forces my game to crash. I know I can just put in a delay but I really want to know why this is the case.
Thank you
It's running multiple times because you are adding each new GUI to listener.
For example, here:
MainGUI mainGUI = new MainGUI(player);
NameGUI nameGUI = new NameGUI(player);
SkinGUI skinGUI = new SkinGUI(player);
You are creating 3 GUIs, so 3 new inventory click event register in listener.
To fix this, I suggest you to :
Make ONE class that receive InventoryClickEvent event, and call GUI that you be called.
For example, you have a list with all GUI:
public static List<GUI> ALL_GUIS = new ArrayList<>();
Then, you should have a way to determine in which inventory the player clicked, such as:
Inventory name. Not very good solution if this can change, but easier to create and use
Inventory holder like this:
public class MainGUIHolder implements InventoryHolder {
#Override
public Inventory getInventory() {
return null;
}
}
Now use it like that:
Inventory mainInv = Bukkit.createInventory(new MainGUIHolder(), 9, "My inv");
You can check with inventory instanceof MainGUIHolder, then get the holder instance with maybe some object that is currently edited by the player
Don't create multiple times GUI instance. For me, it's not a good way, and I think it's better to do like this :
MainGUI mainGUI = GuiManager.getMainGUID(); // here get the alone main GUI instance
// now use it
I know this question has been covered in many posts here.
However, something is still not clear to me, so i wanted to ask you my problem in detail.
I have to develop a java application using Swing and using the MVC model.
The application is mainly divided into two parts:
login part
questionnaire part (after login, a questionnaire is displayed)
So following MVC model i divided my code into 3 packages containing the following classes:
Model
LoginModel
QuestionModel
View
LoginView
QuestionView
Controller
LoginController
QuestionController
After developing these classes, i didn't know how to set the window that the program was current working on (login, questionnaire or other future implementations).
So i thought about implementing 3 other classes that use the Observer pattern:
MainModel - Observable
MainView
MainController - Observer
But now i'm not sure how to change the current window.
For example when login is successful, the window must change from LOGIN to QUESTION, so "MainModel.window = Window.QUESTION" and send it to the View.
Should it be added in LoginModel.login() by extending LoginModel with MainModel?
Or how can I do this?
My code:
public class main {
public static void main(String[] args) {
MainView view = new MainView();
MainModel model = new MainModel();
MainController controller = new MainController(view, model);
}
}
public class MainView {
private JFrame window;
public MainView() {
window = new JFrame();
window.setLayout(new CardLayout(0, 0));
LoginView login = new LoginView(); // init window at opening
QuestionView question = new QuestionView();
window.add(login);
window.add(question);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public void update(Window window) {
// ??
}
}
public class MainModel {
private List<Observer> observers = new ArrayList<>();
private Window window;
public MainModel() {
window = Window.LOGIN; // init window at opening
}
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void setWindow(Window newWindow) {
newWindow = window;
for (Observer o : observers)
o.update(newWindow);
}
}
public class MainController implements Observer {
private MainView view;
private MainModel model;
public MainController(MainView view, MainModel model) {
this.view = view;
this.model = model;
this.model.addObserver(this);
}
#Override
public void update(Window window) {
this.view.update(window);
}
}
public class LoginView extends JPanel {
private JButton btnLogin;
// ... other attributes
public LoginView() {
btnLogin = new JButton("Login");
new LoginController(this);
}
public JButton getBtnLogin() {
return btnLogin;
}
public void ShowResult(boolean bResult) {
// print result with JOptionPane.showMessageDialog
}
}
public class LoginController {
private LoginView view;
public LoginController(LoginView view) {
this.view = view;
setActionListener();
}
public void setActionListener() {
ActionListener loginButton;
loginButton = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
LoginModel model = new LoginModel();
boolean bResult = model.login(view.getUserNameField(), view.getPasswordField());
view.ShowResult(bResult);
}
};
view.getBtnLogin().addActionListener(loginButton);
}
}
public class LoginModel {
// ... attributes etc
public boolean login(String username, String password) {
boolean bResult;
// ... Some operation etc (useless for this example)
bResult = true; // Simulation login successful
if (bResult)
// ? Change window model to Window.QUESTION.
// But how?
// LoginModel extends MainModel? To call "super.setWindow(Window.QUESTION)?
return bResult;
}
}
// My Observer class
public interface Observer {
public void update(Window window);
}
// My Window class
public enum Window {
LOGIN,
QUESTION,
}
// Questionnaire classes code is very similar to the Login code
public class QuestionView extends JPanel {
private JButton btn;
// ...
new QuestionController(this);
// ...
}
public class QuestionController {
private QuestionView view;
// ...
setActionListener();
// ...
}
So in conclusion is it correct to use this approach? Or how else could i view/update the current window better?
In Swing, the MVC pattern looks like this:
The view reads from the model
The view may not update the model
The controller updates the model and the view
The MVC name implies that you create the model first, then the view, then the controllers.
There's usually not one controller to "rule them all". Each listener is responsible for its own part of the model and the view.
You usually have one application model. An application model is made up of one or more plain Java getter/setter classes. In your case, it looks like a Person class and a Questionaire class. You would probably also have a Question class, to hold one question, several possible answers, and the chosen answer. You may have additional plain Java getter/setter classes I'm not thinking about now.
You would have one JFrame, one JPanel to hold a question and possible answers, and a JDialog for the login and password. You may need multiple JPanels for different types of answers (not different questions), so you might need a main JPanel with a CardLayout.
Your controllers will be the ActionListener for the login JButton, and the "I'm finished answering this question" JButton. You may have other listeners that I'm not thinking about now.
I am writing an applet which contains a panel (PanelCondition) with a java.awt.choice dropdown.
http://docs.oracle.com/javase/7/docs/api/java/awt/Choice.html
public class PanelCondition extends Panel
{
Choice choiceCond = new Choice();
public PanelCondition(bool isGood)
{
setCond(isGood);
}
private void setCond(boolean isGood)
{
condCode = getCondItems(isGood);
this.choiceCond.removeAll();
for (int i=0; i < condCode.length; i++)
{
this.choiceCond.addItem(condCode[i]);
}
this.choiceCond.repaint();
}
...
}
The PanelCondition is included in a java.awt.Frame
public class FrameExample extends Frame
{
PanelCondition cond;
private void setCond(bool isGood)
{
cond = new PanelCondition(isGood)
this.add(orderCond,...)
...
}
}
When the FrameExample.setCond() is called first time (isGood=true), the correct items are added to the dropdownlist. However if I call the setCond() the second time (isGood=false), the dropdownlist items don't have any changes.
I have tried to call this.choiceCond.validate() or this.choiceCond.repaint, but it still doesn't work.
Without further evidence,
cond = new PanelCondition(isGood)
this.add(orderCond,...)
Looks suspicious. This is likely just adding another PanelCondition to the UI, but it may be covered by the pre-existing instance.
Generally, it's easy just to update the pre-existing instance...
//cond = new PanelCondition(isGood)
//this.add(orderCond,...)
cond.setCond(isGood);
STARTED - 3:00PM
UPDATE 1 - 5:36PM
Apply Button in the Option() class:
private void cmdApplyActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
hud.setTime(btnTxtTime);
hud.setTemp(btnTxtTemp);
hud.setSurface(btnTxtSurface);
hud.setWeather(btnTxtWeather);
hud.setRadiation(btnTxtRadiation);
dispose();
}
This is a section of the Option() Class.
public class Options extends javax.swing.JFrame {
public String btnTxtTime;
public String btnTxtTemp;
public String btnTxtSurface;
public String btnTxtWeather;
public String btnTxtRadiation;
public static boolean ApplyClicked;
/**
* Creates new form Profile
*/
private HUD hud;
public Options(HUD hud) {
initComponents();
this.hud = hud;
}
This is a method in Option() class:
public String getTime() {
if ("Day".equals(grpTimeOfDay.getSelection())) {
btnTxtTime = "Day";
return this.btnTxtTime;
}
if ("Night".equals(grpTimeOfDay.getSelection())) {
btnTxtTime = "Night";
return this.btnTxtTime;
}
return null;
}
This is how Options() is openned from within HUD():
private void cmdOptionsActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
Options o = new Options(hud);
this.getLocation(p);
o.setLocation((int) p.getX() + 100, (int) p.getY() + 100);
o.setVisible(true);
}
This is the start of my HUD() Class:
public abstract class HUD extends javax.swing.JFrame implements Runnable {
private Options o;
private HUD hud;
public HUD(Options o) {
initComponents();
this.o = o;
and this is the method from HUD() which gets the value of the JButtons from Options():
public void setTime(String strTime) {
strTime = o.getTime();
txtTime.setText(strTime);
}
However whenever I click Apply, the options set in Options() are not then set in the TextFields that display them in HUD() like they should be :/
It's difficult to navigate through your very lengthy code sample, however take a look at your cmdApplyActionPerformed() method. You are creating a new HUD() and setting values in it... and then doing absolutely nothing with it.
If you are trying to use the "Apply" button to modify an existing HUD object, your class needs to have a reference to it somewhere. If the HUD is the parent class which creates the Options, try having the Options store a reference to the parent in its constructor. Then, when you perform changes like this in the Options, you can perform them on the parent rather than on a new variable which has no effect.
private HUD parent;
/**
* Creates new form Profile
*/
public Options(HUD parent) {
initComponents();
this.parent = parent;
}
Then, in your event handler, you can have ...
parent.setTime(btnTxtTime);
parent.setTemp(btnTxtTemp);
parent.setSurface(btnTxtSurface);
parent.setWeather(btnTxtWeather);
parent.setRadiation(btnTxtRadiation);
dispose();
From what I understand, HUD is your 'main window' and the users gets to this option frame from that window.
But when you apply, you're setting the properties on a new HUD, not the one you had before.
To fix this, you need a handle to your main window in your config window, so that you can set the properties on it.
in your hud:
ConfigFrame config = new ConfigFrame();
config.setHUD(this);
config.setVisible(true);
In your config
private HUD hud;
public void setHUD(HUD hud){
this.hud = hud;
}
then just leave out the HUD hud = new hud();