I have 3 Java books, and use online resources, including the posts on this website, also but something is just not clicking. New too programming in general and not the brightest bulb so please try and dumb down the responses if at all possible. Going to try and explain in detail the best I can, sorry if this is a long post and THANK YOU FOR YOUR TIME. Also, am using IntelliJ IDEA IDE
GOAL:
I'm trying to create a simple "Game" that implements a GUI, you click 1 of 3 JButtons to perform an action, and above the JButtons is a JTextArea used to relay all the information to the User.
PROBLEM: I'm not referencing objects in other classes correctly and creating static methods and variables to compensate (I think) But please take a look and let me know what else I'm doing incorrectly I need comments and criticism from people that know whats up.
SIDE NOTE:
Its buggy and a lot has been turned into a "static" method or variables in order to use between classes. When it came time to create a new "Level" I couldn't recycle my enemy ArrayList and load new enemies in it due to the static nature of it all. I will post the working version but I have started to rebuild it for practice makes perfect, and possibly upgrade my code.
As far as structure, should each "Level" be its own class, should all the levels be in an ArrayList like the enemies, and should I have 1 class that works as the game loop?
Is there a generic best way when creating something or as long as it works it doesn't matter? (opinions please)
I have 6 Packages and 13 Classes which is a lot of code, so I will just print the classes I believe are of importance to the situation.
Main Class:
package Primary;
import GUI.PrimaryFrame;
import Game.Loop;
/**
* Created by Thunderfoot on 8/4/2016. Keep Growing!
*/
public class Alpha {
public static void main(String[] args) {
//Instantiate our GUI
PrimaryFrame frameGUI = new PrimaryFrame();
frameGUI.buildGUI();
//Instantiate our game loop
Loop.newGame();
}
}
GUI:
package GUI;
import javax.swing.*;
import java.awt.*;
/**
* Graphical User Interface requires:
* 1 JFrame (PrimaryFrame)
* 4 JPanel (outputPanel, characterStatsPanel, topButtonPanel, bottomButtonPanel)
* 3 JTextArea (output, playerStats, enemyStats)
* 1 JScrollPane (output)
* 3 JButton (attackButton, kickButton, powAttButton)
*/
public class PrimaryFrame extends JFrame {
private OutputPanel outPanel = new OutputPanel();
private StatsPanel statPanel = new StatsPanel();
private TopButtons topPanel = new TopButtons();
private BottomButtons botPanel = new BottomButtons();
//Constructor
public PrimaryFrame() {
//frame
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
Dimension FRAME_MIN = new Dimension(400, 600);
setMinimumSize(FRAME_MIN);
Dimension FRAME_MAX = new Dimension(600, 800);
setMaximumSize(FRAME_MAX);
setTitle("Generic Fighting Game");
getContentPane().setBackground(Color.BLACK);
}
public void buildGUI() {
//Add components and spacing
add(Box.createRigidArea(new Dimension(8, 8)));
add(outPanel);
add(Box.createRigidArea(new Dimension(8, 8)));
add(statPanel);
add(Box.createRigidArea(new Dimension(8, 8)));
add(topPanel);
add(Box.createRigidArea(new Dimension(8, 8)));
add(botPanel);
add(Box.createRigidArea(new Dimension(8, 8)));
//Set attributes
pack();
setLocationRelativeTo(null);
setVisible(true);
}
}
Output Panel:
package GUI;
import javax.swing.*;
import javax.swing.text.DefaultCaret;
import java.awt.*;
/**
* Created by Thunderfoot on 8/4/2016. Keep Growing!
*/
public class OutputPanel extends JPanel {
//Class variables
public static JTextArea output;
OutputPanel() {
Font myFont = new Font("Serif", Font.BOLD, 16);
BoxLayout outFlow = new BoxLayout(this, BoxLayout.X_AXIS);
setLayout(outFlow);
setBackground(Color.GRAY);
setMinimumSize(new Dimension(400, 100));
setMaximumSize(new Dimension(600, 300));
//TextArea
output = new JTextArea(1,50);
output.setLineWrap(true);
output.setWrapStyleWord(true);
output.setEditable(false);
output.setFont(myFont);
JScrollPane outputScroll = new JScrollPane(output, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
outputScroll.isWheelScrollingEnabled();
//TextArea always scroll to bottom after update
DefaultCaret caret = (DefaultCaret)output.getCaret();
caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);
//Add components and spacing
add(Box.createRigidArea(new Dimension(8, 8)));
add(outputScroll, CENTER_ALIGNMENT);
add(Box.createRigidArea(new Dimension(8, 8)));
}
}
Game Loop:
package Game;
import Characters.BasicEnemy;
import Characters.UserCharacter;
import GUI.BottomButtons;
import GUI.TopButtons;
import Levels.Level_One;
import Levels.Tutorial;
import java.util.ArrayList;
public class Loop {
//Class variables
public static UserCharacter player;
public static ArrayList<BasicEnemy> enemyList;
public static int currLevel = 0;
public static void newGame() {
combatDisabled();
switch (currLevel) {
case 0:
Tutorial tutorial = new Tutorial();
tutorial.runTutorial();
combatEnabled();
break;
case 1:
Level_One lvl1 = new Level_One();
lvl1.runLevelOne();
combatEnabled();
break;
}
}
public static void combatEnabled() {
TopButtons.attackButton.setEnabled(true);
TopButtons.kickButton.setEnabled(true);
}
public static void combatDisabled() {
TopButtons.attackButton.setEnabled(false);
TopButtons.kickButton.setEnabled(false);
BottomButtons.powAttButton.setEnabled(false);
}
}
Level 1:
package Levels;
import Characters.BasicEnemy;
import Characters.UserCharacter;
import CombatSystem.Combat;
import GUI.OutputPanel;
import Game.Loop;
import java.util.ArrayList;
public class Tutorial {
public void runTutorial() {
//Instance variables
Loop.player = new UserCharacter(100, 10);
BasicEnemy enemy0 = new BasicEnemy(100, 5);
BasicEnemy enemy1 = new BasicEnemy(100, 5);
BasicEnemy enemy2 = new BasicEnemy(100, 5);
Loop.enemyList = new ArrayList<>();
Loop.enemyList.add(enemy0);
Loop.enemyList.add(enemy1);
Loop.enemyList.add(enemy2);
OutputPanel.output.append("Greetings player! Use the buttons at the bottom of the screen to fight your opponent.");
Combat.statusUpdate();
Loop.combatEnabled();
}
}
Class that handles combat:
package CombatSystem;
import GUI.BottomButtons;
import GUI.OutputPanel;
import GUI.StatsPanel;
import Game.Loop;
import java.util.Random;
public class Combat {
//Player stats
private static int playerCurrHealth = Loop.player.getHealth();
private static int playerCurrRage = Loop.player.getRageMeter();
private static int playerAttack = Loop.player.getAttackPower();
private static int playerKick = Loop.player.getKickPower();
private static int playerPowAttack = Loop.player.getRagePower();
//Enemy stats
private static int enemyCurrHealth = Loop.enemyList.get(0).getHealth();
private static int enemyCurrRage = Loop.enemyList.get(0).getRageMeter();
private static int enemyAttack = Loop.enemyList.get(0).getAttackPower();
//Fighting
private static boolean fighting = true;
public Combat() {
}
//Update status fields
public static void statusUpdate() {
StatsPanel.playerStats.setText(" <" + playerCurrHealth + "> [" + playerCurrRage + "] ");
StatsPanel.enemyStats.setText(" <" + enemyCurrHealth + "> [" + enemyCurrRage + "] ");
}
//Basic attack
public static void basicAttack() {
if (fighting) {
playerBasicAttack();
if (enemyCurrHealth <= 0) {
death();
} else {
enemyBasicAttack();
if (playerCurrHealth <= 0) {
death();
}
}
}
}
//Player combat systems
private static void playerBasicAttack() {
OutputPanel.output.append("\n Your attack does " + playerAttack + " damage to the enemy!");
enemyCurrHealth -= playerAttack;
gainPlayerRage();
gainEnemyRage();
statusUpdate();
}
//Player kick attack
public static void playerKickAttack() {
OutputPanel.output.append("\n Your kick does " + playerKick + " damage to the enemy!");
enemyCurrHealth -= playerKick;
gainPlayerRage();
gainEnemyRage();
statusUpdate();
Random random = new Random();
int kickChance = random.nextInt(100) + 1;
if (kickChance >= 60) {
OutputPanel.output.append("\n Your kick has stunned the enemy!");
} else {
enemyBasicAttack();
gainEnemyRage();
gainPlayerRage();
statusUpdate();
}
}
//Player power attack
public static void playerPowAttack() {
OutputPanel.output.append("\n Your POWER ATTACK does " + playerPowAttack + " damage to the enemy!");
enemyCurrHealth -= playerPowAttack;
playerCurrRage = 0;
gainEnemyRage();
statusUpdate();
BottomButtons.powAttButton.setEnabled(false);
}
private static void gainPlayerRage() {
if (playerCurrRage < 100) {
playerCurrRage += 5;
if (playerCurrRage >= 100) {
playerCurrRage = 100;
BottomButtons.powAttButton.setEnabled(true);
} else {
BottomButtons.powAttButton.setEnabled(false);
}
}
}
//Enemy combat systems
private static void enemyBasicAttack() {
OutputPanel.output.append("\n Enemy's attack does " + enemyAttack + " damage to you!");
playerCurrHealth -= enemyAttack;
gainEnemyRage();
gainPlayerRage();
statusUpdate();
}
private static void gainEnemyRage() {
if (enemyCurrRage < 100) {
enemyCurrRage += 5;
} else {
enemyCurrRage = 100;
}
}
//END GAME
private static void death() {
if (playerCurrHealth <= 0) {
Loop.combatDisabled();
fighting = false;
loseGame();
} else if (enemyCurrHealth <= 0) {
if (!Loop.enemyList.isEmpty()) {
Loop.enemyList.remove(0);
OutputPanel.output.append("\nYou have killed an enemy!");
statusUpdate();
fighting = true;
} else {
fighting = false;
Loop.combatDisabled();
winGame();
}
}
}
private static void winGame() {
OutputPanel.output.setText("You won!");
Loop.combatDisabled();
Loop.currLevel++;
Loop.enemyList.clear();
Loop.newGame();
}
private static void loseGame() {
OutputPanel.output.setText("You lost!");
Loop.combatDisabled();
}
}
Generally, the right way to do this is to create an instance of a class that is called a controller. A controller is an object that handles references to other objects and handles out the tasks to be done. So, in your main, you do something like
GameController cont = new GameController();
Then, if you need something that the controller requires access to, just link it inside the controller:
GUI gui = new GUI();
cont.setGUI(gui);
Also, whenever something will need to access the controller to do its work, you need to provide it with the controller:
gui.setController(controller);
This way, you provide abstraction - you do not call eg. GUI drawing from within your player character, you just create methods within the controller such as say handlePlayerInput(...) and the controller knows what objects to call and what methods to handle.
"Everything static" is not a bad programming paradigm per se, however it usually signals heavy-coupled and inflexible architecture. For example, should you have two enemyLists, what would you do? Another static field would probably do but it would require a lot of copy-paste for all things that use enemyList right now. Copy-pasting is usually the thing you want to avoid so as to make long-term maintenance easier.
Better architectures encapsulate things into meaningful abstractions, either object-oriented or somehow else representing modules with single responsibilities. Game logic and rendering are usually separate things. As is said in a another answer by #PiotrWilkin, many implementations encapsulate top-level components into a controller while those components themselves manage other related things.
If you are interested in software design and architecture, I would suggest reading the following two classics:
Principles and Patterns by Robert C. Martin, a detailed explanation of SOLID design principles, simple to learn yet hard to master concepts that together help making rock-solid software architectures.
Design Patterns by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides with a foreword by Grady Booch. This is a dictionary-like book, describing patterns commonly applied in software design.
Related
Hi people of StackOverflow, I'm fairly new to Java and need some help,
I have made a program that compiles how I want it, a guessing game whereby the computer randomly generates a number and the user is asked to guess it, this is all in the console however. I wish to create a GUI for the game, I have made the outline of the GUI in code but I am struggling to put the logic into it, am I better off calling the methods from the console program (and make some changes) or start from the top within in the GUI code and put the logic in there? If the latter, where do i put the logic? Any help would be greatly appreciated!
Here are my two programs so far, both compile but the GUI is kind of meaningless right now!
Thank you in advance
This code is the console one, the user's guess is scanned and compared with the random number.
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class GuessingGameSystem {
public static int randomizer() {
Random rand = new Random();
int num = rand.nextInt(10)+1;
System.out.println(num);
return num;
}
public static int userInput() {
System.out.println("I've thought of a number between 1 and 10");
System.out.println("Enter your guess...");
Scanner scan = new Scanner(System.in);
int guess = scan.nextInt();
return guess;
}
public static String compare(int a, int b) {
String result = null;
if (a < b) {
result = "Higher!";
}
else if (a > b) {
result = "Lower!";
}
else {
result = "You guessed it - I was thinking of " + b;
}
return result;
}
public static void main(String[] args) {
Scanner scanLine = new Scanner(System.in);
String playAgain = "";
int count = 0;
int a;
int b;
do {
b= randomizer();
count = 0;
ArrayList<Integer> guessesSoFar = new ArrayList<>();
do {
a = userInput();
count++;
guessesSoFar.add(a);
System.out.println("Guesses so far: " + Arrays.toString(guessesSoFar.toArray()));
System.out.println("Number of guesses so far: " + guessesSoFar.size());
System.out.println(compare(a,b));
} while (a != b);
System.out.println("It took you " + count + " guesses.");
System.out.println("Play again? Yes/No");
playAgain = scanLine.nextLine();
} while (playAgain.equalsIgnoreCase("yes") || playAgain.equalsIgnoreCase("y"));
}
}
And here is the GUI code I have so far:
import javax.swing.*;
import java.awt.event.*;
public class GuessingGameGUI {
private JFrame frame;
private JPanel panel;
private JLabel lblInstructions, lblResult, lblGuesses, lblNoOfGuesses;
private JButton btnCheck, btnNewGame, btnExit;
private JTextField txtUserGuess, txtListOfGuesses, txtGuessesCount;
public static void main(String[] args) {
new GuessingGameGUI();
}
public GuessingGameGUI() {
createForm();
createFields();
createButtons();
createTextField();
frame.add(panel);
frame.setVisible(true);
}
public void createForm() {
frame = new JFrame();
frame.setTitle("Guessing Game");
frame.setSize(800,350);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setLayout(null);
}
public void createFields() {
lblInstructions = new JLabel("Guess the number between 1 and 10:");
lblInstructions.setBounds(285, 50, 350, 20);
panel.add(lblInstructions);
lblResult = new JLabel("Result");
lblResult.setBounds(380, 200, 100, 20);
panel.add(lblResult);
lblGuesses = new JLabel("Your Guesses:");
lblGuesses.setBounds(70, 50, 100, 20);
panel.add(lblGuesses);
lblNoOfGuesses = new JLabel("Number of Guesses:");
lblNoOfGuesses.setBounds(600, 50, 200, 20);
panel.add(lblNoOfGuesses);
}
public void createButtons() {
btnCheck = new JButton("Check");
btnCheck.setBounds(325, 150, 150, 20);
panel.add(btnCheck);
btnNewGame = new JButton("New Game");
btnNewGame.setBounds(160, 300, 150, 20);
panel.add(btnNewGame);
btnExit = new JButton("Exit");
btnExit.setBounds(495, 300, 150, 20);
panel.add(btnExit);
btnCheck.addActionListener(new CheckHandler());
btnNewGame.addActionListener(new NewGameHandler());
btnExit.addActionListener(new ExitHandler());
}
public void createTextField() {
txtUserGuess = new JTextField();
txtUserGuess.setBounds(300, 100, 200, 20);
panel.add(txtUserGuess);
txtListOfGuesses = new JTextField("List of Guesses");
txtListOfGuesses.setBounds(65, 75, 115, 200);
panel.add(txtListOfGuesses);
txtGuessesCount = new JTextField("Guesses Count");
txtGuessesCount.setBounds(610,75, 110, 20);
panel.add(txtGuessesCount);
}
class CheckHandler implements ActionListener{
public void actionPerformed(ActionEvent event){
//to check random number against user guess in txtUserGuess
}
}
class NewGameHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
//to start a new game
}
}
class ExitHandler implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
}
}
You should have a look at MVP (Model View Presenter).
GUI code shouldn't have the game's logic – you shouldn't call methods that define the game's behaviour, only pass user commands forward.
Here's the outline of a possible way of implementing it using MVP (A > B means A calls B's method; the GUI is the View):
User writes a number
User presses "Check"
View > Presenter: onCheckCommand(int number)
Presenter > Model: receiveGuess(int number)
Model adds the received number to a list of guesses
Model returns HIGHER, LOWER or RIGHT
Presenter > Model: getListOfGuesses() and getGuessesCount()
Presenter > View: showListOfGuesses(List<Integer> list), showGuessesCount(int count) and showResult(Result result) (HIGHER, LOWER or RIGHT)
View: If the result is RIGHT, disable the "Check" button
User presses "New Game"
View enables the "Check" button and clears the result, list of guesses and guesses count
View > Presenter: onNewGameCommand()
Presenter > Model: startNewGame()
Model clears the list of guesses and generates a new number
Basically, the presenter is who knows which game methods should be called (and when) and what should be displayed (and when).
Model should have a public method for anything that happens (in the game) in response to user input or other external events, if any – for example, a timer that fires every second to update the remaining time.
I'm assuming the view forces the user to input integers. You should be careful to call methods that update the GUI on the event dispatching thread. This already happens in this example, since all methods are called when handling the "button pressed" events. Calling everything from the handlers doesn't always work.
I want to know how to add a GUI to my program. I have started creating a java program in Blue J and the first class of the program is a class which has been extended by other classes.
Now I have to make a GUI too but from my understanding I can only implement an interface as the GUI extends the class Frame. The problem is I want to create a GUI of my class, it has instance variables too so is there a work around? Could I make my first class an interface without altering the extensions too much?
code:
public class Players /* Class name */
{
private int attack; /* Instance variables* */
private int defence;
private int jump;
public Players(int a, int d, int j) /* Constructor being defined */
{
int total = a + d + j;
if((total) == 100)
{
attack = a;
defence = d;
jump = j;
}
else
{
System.out.println("Make stats add to 100");
}
}
public Players()/* Default contructor if not user defined */
{
attack = 34;
defence = 33;
jump = 33;
}
public void addAttack(int a)
{
attack += a;
}
public void addDefence(int a)
{
defence += a;
}
public void addJump(int a)
{
jump += a;
}
public void getBasicStats()
{
System.out.println(attack + " " + defence + " " + jump);
}
}
This is my first class and my superclass for most of the other classes
I suggest learning how to use Swing. You will have several different classes interacting together. In fact, it is considered good practice to keep separate the code which creates and manages the GUI from the code which performs the underlying logic and data manipulation.
Another suggestion:
Learn JavaFX and download SceneBuilder from Oracle: here
At my university they have stopped teaching Swing and started to teach JavaFX, saying JavaFX has taken over the throne from Swing.
SceneBuilder is very easy to use, drag and drop concept. It creates a FXML file which is used to declare your programs GUI.
How will I declare aan instance variable inside the GUI class?
Like as shown bellow, you could start with something like this, note that your application should be able to hand out your data to other classes, for instance I changed getBasicStats() to return a String, this way you can use your application class anywhere you want, I guess this is why you were confused about where to place the GUI code...
public class PlayersGUI extends JFrame {
private static final long serialVersionUID = 1L;
private Players players; // instance variable of your application
private PlayersGUI() {
players = new Players();
initGUI();
}
private void initGUI() {
setTitle("This the GUI for Players application");
setPreferredSize(new Dimension(640, 560));
setLocation(new Point(360, 240));
JPanel jPanel = new JPanel();
JLabel stat = new JLabel(players.getBasicStats());
JButton attack = new JButton("Attack!");
attack.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
players.addAttack(1);
}
});
JButton hugeAttack = new JButton("HUGE Attack!");
hugeAttack.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
players.addAttack(10);
}
});
JButton defend = new JButton("Defend");
defend.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
players.addDefence(1);
}
});
JButton showStats = new JButton("Show stats");
showStats.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
stat.setText(players.getBasicStats());
}
});
jPanel.add(stat);
jPanel.add(attack);
jPanel.add(hugeAttack);
jPanel.add(defend);
jPanel.add(showStats);
add(jPanel);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
PlayersGUI pgui = new PlayersGUI();
pgui.pack();
pgui.setVisible(true);
}
});
}
}
I would recommend using netbeans to start with. From there you can easily select pre created classes such as Jframes. Much easier to learn. You can create a GUI from there by dragging and dropping buttons and whatever you need.
Here is a youtube tut to create GUI's in netbeans.
https://www.youtube.com/watch?v=LFr06ZKIpSM
If you decide not to go with netbeans, you are gonna have to create swing containers withing your class to make the Interface.
I recently have implemented clipping in my VTK Java program. I used BoxWidget to control what should be clipped. However, i'm having an issue with vtkRenderWindowInteractor that attached to BoxWidget. The program freezes at the renderWindowInteractor.Start() statement (I've remarked it in my code).
This is my re-simulate code :
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import vtk.*;
public class VTKWindowInteractor extends JPanel {
static {
if (!vtkNativeLibrary.LoadAllNativeLibraries()) {
for (vtkNativeLibrary lib : vtkNativeLibrary.values()) {
if (!lib.IsLoaded()) {
System.out.println(lib.GetLibraryName() + " not loaded");
}
}
System.out.println("Make sure the search path is correct: ");
System.out.println(System.getProperty("java.library.path"));
}
vtkNativeLibrary.DisableOutputWindow(null);
}
private vtkPanel renWin;
private vtkRenderWindowInteractor renderWindowInteractor;
private vtkPolyDataMapper mapper;
private vtkActor coneActor;
private vtkPlanes planes;
private vtkBoxWidget boxWidget;
public VTKWindowInteractor() {
setLayout(new BorderLayout());
renWin = new vtkPanel();
add(renWin, BorderLayout.CENTER);
renWin.setMinimumSize(new Dimension(50, 50));
renWin.GetRenderer().SetBackground(0, 0, 0); // black
renWin.GetRenderWindow().AddRenderer(renWin.GetRenderer());
}
public void render() {
mapper = new vtkPolyDataMapper();
vtkConeSource cone = new vtkConeSource();
cone.SetHeight(3.0);
cone.SetRadius(1.0);
cone.SetResolution(10);
mapper.SetInputConnection(cone.GetOutputPort());
coneActor = new vtkActor();
coneActor.SetMapper(mapper);
renWin.GetRenderer().AddActor(coneActor);
planes = new vtkPlanes();
renderWindowInteractor = new vtkRenderWindowInteractor();
renderWindowInteractor.SetRenderWindow(renWin.GetRenderWindow());
boxWidget = new vtkBoxWidget();
boxWidget.SetInteractor(renderWindowInteractor);
boxWidget.SetPlaceFactor(1.25);
boxWidget.PlaceWidget(coneActor.GetBounds());
boxWidget.AddObserver("InteractionEvent", this, "executeClipping");
renderWindowInteractor.Initialize();
boxWidget.On();
renWin.Render();
renWin.resetCamera();
/**************************************/
// This is where the freeze come from //
// //
/************************************/
renderWindowInteractor.Start(); // if i comment out this line, the program works but the boxWidget cannot be resized or rescale or moved
}
public void executeClipping() {
planes = new vtkPlanes();
boxWidget.GetPlanes(planes);
mapper.SetClippingPlanes(planes);
planes.Delete();
}
public static final int WINDOW_WIDTH = 1000;
public static final int WINDOW_HEIGHT = 500;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
VTKWindowInteractor _vtkRendererPanel = new VTKWindowInteractor();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("......");
frame.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
frame.setVisible(true);
frame.setLayout(new BorderLayout());
frame.add(_vtkRendererPanel);
_vtkRendererPanel.render();
}
});
}
}
I have been finding my mistake for hours and hours and frustrated hence come here to seek for help. If anyone have experienced this or know what did I do wrong please correct me. Thanks !!!
VTK version : 6.2.0
OK. I finally solved the problem. The follows is the quote from vtkPanel.java
/*
*
* Java AWT component that encapsulate vtkRenderWindow, vtkRenderer, vtkCamera,
* vtkLight.
*
* If a vtkInteractor is needed, use vtkCanvas instead. This is necessary when
* Widget and Picker are used.
*
* #author Kitware */
so I changed my
vtkPanel
to
vtkCanvas
&
renderWindowInteractor = new vtkRenderWindowInteractor();
to
renderWindowInteractor = renWin.getRenderWindowInteractor();
and it solves the problem.
Thanks and this is for anyone who are going to face similiar problem as me in the future.
I have been having a problem with my JFrame. I have added five JButtons for a user interface for an rpg program that I'm working on. When the "Status" button is pressed, the JFrame freezes, and nothing, not even EXIT_ON_CLOSE works. I want to know how to get the status button to work, and how to avoid this problem with any of the other buttons.
Here's the ButtonListener class:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class ButtonListeners {
public static final int WIDTH=360;
public static final int HEIGHT=360;
final static Monsters sk = new Monsters("Skeleton",120,20,30,5,50);
final static Monsters dm = new Monsters("Dark Mage",130,10,40,10,100);
final static Monsters kn = new Monsters("Knight",160,30,40,2,120);
final static Monsters sm = new Monsters("Slime",200,1,50,5,150);
final static Monsters go = new Monsters("golem",500,50,55,15,400);
final static Monsters dg = new Monsters("dragon",1000,35,100,25,600);
final static Monsters bk = new Monsters("Black Knight",2000,35,90,12,1000);
final static Monsters zm = new Monsters("Zombie",100,30,35,5,50);
public static void UI(){
final JFrame frame=new JFrame("Guantlet");
frame.setSize(800,600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Player p = new Player();
frame.setSize(WIDTH,HEIGHT);
final JButton item = new JButton("Items");
final JButton status=new JButton("Status");
final JButton attack=new JButton("Attack");
final JButton defend = new JButton("Defend");
final JButton mStat = new JButton("Monster Status");
frame.setVisible(true);
frame.add(attack,BorderLayout.EAST);
frame.add(defend,BorderLayout.WEST);
frame.add(item, BorderLayout.NORTH);
frame.add(status, BorderLayout.SOUTH);
frame.add(mStat, BorderLayout.CENTER);
final ArrayList<Monsters> monOrder = new ArrayList<Monsters>();
monOrder.add(0,sk);
monOrder.add(1,zm);
monOrder.add(2,kn);
monOrder.add(3,sm);
monOrder.add(4,dm);
monOrder.add(5,go);
monOrder.add(6,dg);
monOrder.add(7,bk);
frame.setVisible(true);
JOptionPane.showMessageDialog(frame, "Welcome to the arena! Many opponents await.");
JOptionPane.showMessageDialog(frame,"A Skeleton draws near!");
class Button1Listener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
boolean battle1 = true;
while(battle1){
if(e.getSource() == attack){// &&monOrder.contains(sk) && monOrder.contains(zm) && monOrder.contains(kn) && monOrder.contains(dm) && monOrder.contains(go) && monOrder.contains(dg)&& monOrder.contains(bk)) {
if(monOrder.contains(sk)){
sk.mHP=sk.mHP-sk.attacked(p);
sk.status();
sk.isAlive();
if(sk.isAlive()){
p.hp=p.hp-sk.attacking(p);
System.out.println("The Skeleton has "+sk.mHP+" health left");
System.out.println("You have "+"You have "+p.hp+ " health left");
p.status();
}else if(!sk.isAlive()){
monOrder.remove(0);
p.exp=p.exp+sk.exp;
p.levelUp();
JOptionPane.showMessageDialog(frame,"A Zombie emerges!");
}
//}
System.out.println(zm.mHP);
}
if(monOrder.contains(zm) && !monOrder.contains(sk)){
zm.mHP=zm.mHP-zm.attacked(p);
zm.status();
zm.isAlive();
if(zm.isAlive()){
p.hp=p.hp-zm.attacking(p);
System.out.println("The Skeleton has "+zm.mHP+" health left");
System.out.println("You have "+"You have "+p.hp+ " health left");
p.status();
}else if(!zm.isAlive()){
monOrder.remove(0);
p.exp=p.exp+zm.exp;
p.levelUp();
JOptionPane.showMessageDialog(frame,"A Dark Mage appears before you!");
}
}
break;
}
}
}
}
ActionListener b1L=new Button1Listener();
attack.addActionListener(b1L);
status.addActionListener(b1L);
status.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == status ){
JOptionPane.showMessageDialog(frame, "Maximum Health = " + p.maxHP+" \n Strength = " + p.str + "\n Speed = "+p.spd+"\n Experience to next level- "+(p.reqExp-p.exp));
Thread t = new Thread(new Runnable() {
public void run() {
// execute query here
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// update the ui here
final JFrame frame=new JFrame("Guantlet");
frame.setSize(800,600);
frame.add(attack,BorderLayout.EAST);
frame.add(defend,BorderLayout.WEST);
frame.add(item, BorderLayout.NORTH);
frame.add(status, BorderLayout.SOUTH);
frame.add(mStat, BorderLayout.CENTER);
}
});
}
});
t.start();
}
}
});
}
}
You've got a long-running bit of code here:
while(battle1){
//....
}
and since this is running in the Swing event thread, it is tying up the event thread, freezing your application. The solution is to avoid doing this, avoid tying up the event thread. Possible solutions depend on your needs including use of a Swing Timer for a game loop, use of a background Thread for long-running processes, or re-constructing your code so that this while loop isn't needed.
A quick review of your code suggests that perhaps you would want to go the Swing Timer route. If you Google Java Swing Timer tutorial you'll get decent info on using this.
As an aside, you are over-using the static modifier and should fix this. You should use this only sparingly and only for specific needs.
Aside number 2: look into the M-V-C or Model-View-Control design pattern as a way to separate your game logic out of your GUI. You've got them mixed together in a way that will make extending, improving and debugging your program difficult.
Why are you using while(true) an infinite loop whereas you have called break statement in a condition. what happened if condition is not matched? Please look it again as shown below.
while(battle1){
if(e.getSource() == attack){
...
break;
}
}
When status button is clicked then if(e.getSource() == attack) will never be matched and your program will go in infinite loop.
This is my first attempt at using a GUI layout in Java. I am trying to create a simple memory card game, where the user flips over two cards, and tries to get a match, and if there's no match they flip back over, if there's a match they stay flipped until you get all the matches. I might have made it hard on myself though in that I made the whole game dynamic to the constructor variables that define the number of columns and rows of cards. I thought this was better than hard-coding a certain value in, but now I'm having trouble putting the images in my img folder onto my cards.
I understand that variables of variables are not permitted in Java & this is really hard for me to adapt to as a ColdFusion developer. Can you help me think of ways to accomplish this this the proper way in Java?
Here is a simplified version of my code.
import javax.swing.JFrame;
public class MemoryApp
{
public static void main(String args[])
{
//Creates a new game with 3 columns and 4 rows
final CardGame myGame = new CardGame(3, 4);
javax.swing.SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI(myGame.getCols(), myGame.getRows());
}
});
}
private static void createAndShowGUI(int c, int r) {
//Create and set up the window.
Window frame = new Window("GridLayoutDemo", c, r);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set up the content pane.
frame.addComponentsToPane(frame.getContentPane());
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
Card game class:
public class CardGame
{
private int cols, rows;
public CardGame(int c, int r)
{
cols = c;
rows = r;
}
public int getCols(){
return cols;
}
public int getRows(){
return rows;
}
}
The window with the grid layout:
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSeparator;
public class Window extends JFrame
{
private int cols, rows;
GridLayout windowGrid = new GridLayout(1,1);
public Window(String t, int c, int r)
{
super(t);
cols = c;
rows = r;
windowGrid.setColumns(c);
windowGrid.setRows(r);
}
public void addComponentsToPane(final Container pane)
{
final JPanel compsToExperiment = new JPanel();
compsToExperiment.setLayout(windowGrid);
JPanel controls = new JPanel();
controls.setLayout(new GridLayout(cols,rows));
int countCard = (cols * rows) / 2;
/**
* Add buttons to experiment with Grid Layout.
* This is where I'd like to be able to loop through
* countCard and create the required number of buttons
* as well as put images on the buttons like so:
*
* ImageIcon image1 = new ImageIcon(getClass().getResource("card1.png"));
* through
* ImageIcon image1 = new ImageIcon(getClass().getResource("card" & cardCount & ".png"));
*
* Below is how I would attempt this in ColdFusion- I know
* the variable of variables syntax is invalid, it is just
* to show you what I mean.
*/
// for(int i = 0; i < countCard; i++;)
// {
// compsToExperiment.add(new JButton("../img/card" & i & ".png"));
// ImageIcon variables["image" & i] = new ImageIcon(getClass().getResource("card" & i & ".png"));
// imageButton.setIcon(variables["image" & i]);
// etc. with ButtonClickEventHandler, haven't gotten that far yet
// }
pane.add(compsToExperiment, BorderLayout.NORTH);
pane.add(new JSeparator(), BorderLayout.CENTER);
}
}
Based on the code commented-out code that you posted so far, one approach could be like this:
public class Window extends JFrame
{
...
// A java.util.List that stores all the buttons, so
// that their icons may be changed later
private List<JButton> buttons = new ArrayList<JButton>();
// A java.util.List that stores all the ImageIcons that
// may be placed on the buttons
private List<ImageIcon> imageIcons = new ArrayList<ImageIcon>();
public void addComponentsToPane(final Container pane)
{
...
for(int i = 0; i < countCard; i++;)
{
// String concatenation is done with "+" in Java, not with "&"
String fileName = "card" + i + ".png";
// Create the icon and the button containing the icon
ImageIcon imageIcon = new ImageIcon(getClass().getResource(fileName));
JButton button = new JButton(imageIcon);
// Add the button to the main panel
compsToExperiment.add(button);
// Store the button and the icon in the lists
// for later retrieval
imageIcons.add(imageIcon);
buttons.add(button);
// Attach an ActionListener to the button that will
// be informed when the button was clicked.
button.addActionListener(createActionListener(i));
}
}
private ActionListener createActionListener(final int cardIndex)
{
return new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
clickedCardButton(cardIndex);
}
};
}
private void clickedCardButton(int cardIndex)
{
System.out.println("Pressed button for card "+cardIndex);
// Here you can change the icons of the buttons or so...
JButton button = buttons.get(cardIndex);
ImageIcon imageIcon = imageIcons.get(cardIndex);
....
}
You mentioned that this is your first attempt to build a GUI with Java. So I assume that this is only intended for "practicing". If your intention was to build a "real application", you should rather consider some Model-View-Controller (MVC) approach for this.