I can't understand what's wrong.
I have a JFrame, with JTextFields and JComboBoxes. When I push a button, it has to take the values from the JTextFields and pass them to one of the methods, which is chosen in the JComboBox, but I can't get the index of the items within the JComboBox.
Here is my code:
public class eHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
if (e.getSource() == esc) {
bx.setText(null);
by.setText(null);
bt0.setText(null);
setVisible(false);
window window = new window("Расчет напряжений");
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setSize(600, 650);
}
if (e.getSource() == count) {
double x = Double.parseDouble(bx.getText());
double y = Double.parseDouble(by.getText());
double t0 = Double.parseDouble(bt0.getText());
Integer item = (Integer)ras.getSelectedIndex();
JOptionPane.showMessageDialog(null, item);
if (item == 0) {
double tens = linear(x, y, t0);
ltr.setText("Напряжение на данном периоде: " + tens + " Мпа");
}
if (item == 1) {
double tens = squard(x, y, t0);
ltr.setText("Напряжение на данном периоде: " + tens + " Мпа");
}
}
}//try
catch(Exception ex){
JOptionPane.showMessageDialog(null, "Введите корректные данные");
}
}
}
It's wrong in:
Integer item = (Integer)ras.getSelectedIndex();
JOptionPane.showMessageDialog(null, item);
Thanks for answers. But it is wrong that i try to use {Listener} for {ComboBox} in other {Listener}. I made a special {Listener} for {JComboBox}, and that has work. Best regards))
Related
So, I'm trying to program a Game of Life simulation (Conway), and I want to show it in a JFrame.
For this purpose, I've created a JPanel, and it works perfectly, until I try to actually show a new generation. With prints, I've figured out, that the list is actually correct inside the newGeneration() method, but when paint(Graphics g) gets called (aka, when I try to repaint the JFrame), the list isn't updating.
I'm sure I've missed something obvious, and I'm not well versed in Java, but it's just getting so annoying. I'd really appreciate your help.
Here's my code;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class Main {
public static void main(String[] args) {
new GameOfLife();
}
}
class GameOfLife {
// Initialising all class wide variables; sorted by type
JFrame frame = new JFrame("Game of Life");
JPanel panel;
Scanner gameSize = new Scanner(System.in);
String dimensions;
String splitHorizontal;
String splitVertical;
String confirmation;
Boolean accepted = false;
Integer split;
Integer horizontal;
Integer vertical;
Integer livingNeighbours;
int[][] cells;
int[][] newCells;
public GameOfLife() {
// Prompt for game Size
System.out.println("Please enter your game size in the following format; 'Horizontal,Vertical'");
// Run until viable game Size has been chosen
while (!accepted) {
dimensions = gameSize.nextLine();
// Check for correct format
if (dimensions.contains(",")) {
split = dimensions.indexOf(",");
splitHorizontal = dimensions.substring(0, split);
splitVertical = dimensions.substring(split + 1);
// Check for validity of inputs
if (splitHorizontal.matches("[0-9]+") && splitVertical.matches("[0-9]+")) {
horizontal = Integer.parseInt(dimensions.substring(0, split));
vertical = Integer.parseInt(dimensions.substring(split + 1));
// Check for game Size
if (horizontal > 1000 || vertical > 1000) {
System.out.println("A game of this Size may take too long to load.");
} else {
// Confirmation Prompt
System.out.println("Your game will contain " + horizontal + " columns, and " + vertical + " rows, please confirm (Y/N)");
confirmation = gameSize.nextLine();
// Check for confirmation, anything invalid is ignored
if (confirmation.matches("Y")) {
accepted = true;
System.out.println("Thank you for your confirmation. Please select live cells. Once your happy with your game, press Spacebar to start the Simulation.");
// Setting parameters depending on Size
frame.setSize(horizontal * 25 + 17, vertical * 25 + 40);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
}
}
// Prompt asking for new dimensions in case of invalid dimensions or non confirmation
if (!accepted) {
System.out.println("Please enter different dimensions.");
}
}
// Creating list of cells
cells = new int[horizontal][vertical];
// Showing the empty panel for selection of live cells
panel = new PaintCells(horizontal, vertical, cells);
frame.add(panel);
// Select live cells
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if (cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] == 1) {
cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] = 0;
} else {
cells[(int) Math.ceil(e.getX() / 25)][(int) Math.ceil(e.getY() / 25)] = 1;
}
frame.repaint();
}
});
// Simulation start
frame.addKeyListener(new KeyListener() {
#Override
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == ' ') {
newGeneration();
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
});
}
// Generating new generations
void newGeneration() {
newCells = new int[horizontal][vertical];
// Pause inbetween generations
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* Way of Life Rules:
* Living cells with 2 or 3 living neighbours live on to the next generation.
* Dead cells with exactly 3 living neighbours become living cells in the next generation.
* Every other living cell dies.
*/
// iterate through every cell
for (int l = 0; l < vertical; l++) {
for (int k = 0; k < horizontal; k++) {
livingNeighbours = 0;
// check amount of neighbours
if (k - 1 > -1) {
if (l - 1 > -1) {
if (cells[k - 1][l - 1] == 1) {
livingNeighbours++;
}
}
if (l + 1 < vertical) {
if (cells[k - 1][l + 1] == 1) {
livingNeighbours++;
}
}
if (cells[k - 1][l] == 1) {
livingNeighbours++;
}
}
if (k + 1 < horizontal) {
if (l - 1 >= 0) {
if (cells[k + 1][l - 1] == 1) {
livingNeighbours++;
}
}
if (l + 1 < vertical) {
if (cells[k + 1][l + 1] == 1) {
livingNeighbours++;
}
}
if (cells[k + 1][l] == 1) {
livingNeighbours++;
}
}
if (l - 1 >= 0) {
if (cells[k][l - 1] == 1) {
livingNeighbours++;
}
}
if (l + 1 < vertical) {
if (cells[k][l + 1] == 1) {
livingNeighbours++;
}
}
// change cell value depending on amount of neighbours
if (cells[k][l] == 1) {
if (livingNeighbours < 2 || livingNeighbours > 3) {
newCells[k][l] = 0;
} else {
newCells[k][l] = 1;
}
} else {
if (livingNeighbours == 3) {
newCells[k][l] = 1;
}
}
}
}
cells = newCells;
frame.validate();
frame.paint(frame.getGraphics());
newGeneration();
}
}
// Our canvas
class PaintCells extends JPanel {
private Integer horizontal;
private Integer vertical;
private int[][] newOriginalCells;
// Get our X and Y from the original prompts
public PaintCells(Integer originalHorizontal, Integer originalVertical, int[][] originalCells) {
this.horizontal = originalHorizontal;
this.vertical = originalVertical;
this.newOriginalCells = originalCells;
}
#Override
public void paint(Graphics g) {
for (int i = 0; i < vertical; i++) {
for (int j = 0; j < horizontal; j++) {
// Check cell value
if (newOriginalCells[j][i] == 1) {
g.setColor(Color.black);
} else {
g.setColor(Color.white);
}
// paint according to value
g.fillRect(j * 25, i * 25, 25, 25);
if (newOriginalCells[j][i] == 1) {
g.setColor(Color.white);
} else {
g.setColor(Color.black);
} // maybe change style?
g.drawRect(j * 25, i * 25, 25, 25);
}
}
}
}
I'm guessing, the problem is somewhere in newGeneration(), but other than that, I really have no idea anymore.
You have a common problem which I had myself a few months ago.
Java Swing GUI system works in thread called Event Dispatch Thread (EDT). This thread handle events like mouse clicks, typing etc. and paint the components to the screen. You should use this thread not as your main thread, but as sub-thread which working only once a certain time/when event happens, and not let him run continuously. In your code, since the user choose the cell to live, this thread run non-stop (because you started the program inside a listener, which is part of the EDT), and your GUI stuck, because it's updating only at the end of the thread.
You can solve this by using javax.swing.Timer. Timer is an object that allows you do tasks once a while, and it is perfect to this problem.
Use code like this:
ActionListener actionListaner = new ActionListener(){
public void actionPerformed(ActionEvent e){
//Put here you ne genration repeating code
}
};
int delay = 1000;//You delay between generations in millis
Timer timer = new timer(delay, actionListener);
The code in the actionPerformed method will repeat every second (or any other time you want it to repeat), and every operation of the timer will recall EDT instead of let it run non-stop.
I have to add add recursion inside ActionListener to calculate fibonacci sequence of a given number, i've tried to add recursion in this way, but it didn't work.
fibonacci.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
try {
int a = Integer.parseInt(input1.getText());
if(a == 0)
result.setText(String.valueOf("0"));
else if(a == 1)
result.setText(String.valueOf("1"));
else
result.setText(String.valueOf(fibonacci(a - 1) + fibonacci(a - 2)));
} catch (Exception f) {
JOptionPane.showMessageDialog(rootPane, "ERROR: " + (f.getMessage()));
}
String aField = input1.getText();
if (e.getSource() == fibonacci) {
if ("".equals(aField)) {
String emptyFieldWarning;
emptyFieldWarning = "One or more fields is/are empty!";
JOptionPane.showMessageDialog(rootPane, emptyFieldWarning);
}
}
}
});
The recursion should happen within it's own method, the ActionListener should stand as the initiation of that recursion.
Something along the lines of
fibonacci.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
String fibonacciStr = fibonacciRecursion(0, 1, 10);
}
}
String fibonacciRecursion(int value0, int value1, int depth){
StringBuilder fibStr = new StringBuilder();
if(depth > 0){
fibStr.append(fibonacciRecursion(value1, value0 + value1, depth-1));
}
return fibStr;
}
As you didn't mention any limit, the depth parameter is meant so your recursion has a way of stopping, as to avoid a SO.
I haven't tested this, but it should be enough to get you closer to a solution of your own design.
Edit
As per #Tom Hawtin - tackline 's comment, this can also be done via lambda expression
fibonacci.addActionListener(actionEvent->
System.our.println(fibonacciRecursion(0, 1, 10)));
I have one JFrame where I enter parameters of a matrix, after those parameters being entered, the user is supposed to click a button to start a simulation. The problem is, the button is supposed to be clicked twice instead of once in order to open the JOption pane where a message is written. I just can't figure out why this happens. This is the function that is called from the simulation button's action performed function:
private void setMatrixParameters(){
if(tfTouristNumber.getText().equals("") || tfRowNumber.getText().equals("") || tfColumnNumber.getText().equals("") || tfMinimal.getText().equals("")){
JFrame frame = new JFrame();
JOptionPane.showMessageDialog(frame, "All fields must be filled", "Error!", JOptionPane.ERROR_MESSAGE);
}
//check the matrix dimensions
else if(min + touristNumber > Integer.parseInt(tfRowNumber.getText()) * Integer.parseInt(tfColumnNumber.getText())){
int dimension= min + touristNumber;
JFrame frame = new JFrame();
JOptionPane.showMessageDialog(frame, "Matrix dimensions too small. Need to be at least:" + dimension, "Enlarge matrix!", JOptionPane.ERROR_MESSAGE);
}
else{
this.touristNumber = Integer.parseInt(tfTouristNumber.getText());
int row = Integer.parseInt(tfRowNumber.getText());
int column = Integer.parseInt(tfColumnNumber.getText());
this.matrix = new Object[row][column];
this.min = Integer.parseInt(tfMinimal.getText());
}
}
Your problem in this case is that you are not checking the text field values in the second if-condition. The following should do the trick.
private void setMatrixParameters(){
if(tfTouristNumber.getText().equals("") || tfRowNumber.getText().equals("") || tfColumnNumber.getText().equals("") || tfMinimal.getText().equals("")){
JFrame frame = new JFrame();
JOptionPane.showMessageDialog(frame, "All fields must be filled", "Error!", JOptionPane.ERROR_MESSAGE);
return;
}
// Read values here. (Should probably add a try-catch block around this, in case it can't be parsed as number)
int inTouristNumber = Integer.parseInt(tfTouristNumber.getText());
int inRow = Integer.parseInt(tfRowNumber.getText());
int inColumn = Integer.parseInt(tfColumnNumber.getText());
int inMin = Integer.parseInt(tfMinimal.getText());
//check the matrix dimensions
if(inMin + inTouristNumber > inRow * inColumn){
int dimension= inMin + inTouristNumber;
JFrame frame = new JFrame();
JOptionPane.showMessageDialog(frame, "Matrix dimensions too small. Need to be at least:" + dimension, "Enlarge matrix!", JOptionPane.ERROR_MESSAGE);
}
else{
this.touristNumber = inTouristNumber;
this.matrix = new Object[inRow][inColumn];
this.min = inMin;
}
}
So i'm working on something that will find the locations of Jlabels on the screen so i can use these positions to generate data later at these points depending on what type of point it is.
To keep track of specific points, i have set the tooltip of the important labels to certain text so i can add them to a Map<String, Rectangle>. The rectangle will give its location on the screen, as well as the size of the label. This will be used to generate the positioning for my data points.
The problem right now is that I am not getting any strings that ive set, using the getToolTipText() on the JLabels.
public Map<String, Rectangle> positions() {
Map<String, Rectangle> ioPoints = new HashMap<>();
return positions(mainPanel, ioPoints);
}
// Runs through each component starting from the mainPanel which contains everything
// Only labels have tooltips
public Map<String, Rectangle> positions(Container p1, Map<String, Rectangle> ioPoints) {
for (Component p : p1.getComponents()) {
if (p instanceof JLabel) {
try {
if (((JLabel) p).getToolTipText() != null) {
// Never hit at all???
System.out.println("Has a tooltip:" + ((JLabel) p).getToolTipText());
Rectangle r = p.getBounds();
Component par = p;
while (par.getParent() != mainPanel) {
par = par.getParent();
}
r = SwingUtilities.convertRectangle(par, r, mainPanel);
//Point spot = ((JLabel) p).getLocation();
((JLabel) p).setText("x=" + r.getX() + ", y=" + r.getY());
Rectangle oldRect = ioPoints.put(((JLabel) p).getToolTipText(), r);
if (oldRect != null) {
System.out.println("Replaced " + ((JLabel) p).getToolTipText()
+ ".\nOld rectangle " + oldRect.toString()
+ "\nNew rectangle: " + r.toString());
}
//System.out.println("Position: " + spot.toString() + "\tr: " + r.toString());
}
} catch (NullPointerException | IllegalComponentStateException e) {
System.out.println("Error with " + ((JLabel) p).getName());
}
} else {
if (p instanceof JPanel) {
return positions((Container) p, ioPoints);
}
}
}
return ioPoints;
}
Example code of where i set tooltips.
tooltip = new String[]{"Comp Amps Temp " + rack.getName() + " `%sgname` `%compname`"};
for (int i = 0; i < numSg; i++) {
for (int j = 0; j < comp[i]; j++) {
label = new JLabel("");
label.setToolTipText(tooltip[0]
.replace("`%sgname`", rack.getSuctionGroupNameIndex(i))
.replace("`%compname`", rack.getSuctionGroupIndex(i).getCompressorNameIndex(j)));
label.setFont(font);
label.setOpaque(true);
label.setBorder(border);
label.setBackground(Colours.BlueLight.getCol());
panel.add(label, c);
c.gridx += 1;
}
}
Any ideas why jlabel.getToolTipText(); wont give me any values for tool tips I've clearly set.
I suggest you just create a class that extends JLabel like so:
public class ToolTippedJLabelOrWhateverYouWantToCallIt extends JLabel {
String tooltip = null;
#Override
public void setToolTipText(String text) {
tooltip = text;
super.setToolTipText(text);
}
#Override
public String getToolTipText() {
return tooltip;
}
}
There might be another way to get the tooltip text, but this is just a simple way.
I'm having some trouble getting a JButton to update repeatedly (used with a timer) in a do-while loop. I'm working on a simple game, played on a 10 * 10 grid of tile objects which correspond to a JButton arrayList with 100 buttons.
This part of the program handles simple pathfinding (i.e. if I click on character, then an empty tile, the character will move through each tile on its way to the destination). There is a delay between each step so the user can see the character's progress.
In the current state of things, the movement is correct, but the JButton is only updated when the character reaches the destination, not on intermediate steps.
public void move(int terrainTile)
{
int currentPosition = actorList.get(selectedActor).getPosition();
int movementValue = 0;
int destination = terrainTile;
int destinationX = destination / 10;
int destinationY = destination % 10;
do
{
currentPosition = actorList.get(selectedActor).getPosition(); // Gets PC's current position (before move)
System.out.println("Old position is " + currentPosition);
int currentX = currentPosition / 10;
int currentY = currentPosition % 10;
if(actorList.get(selectedActor).getCurrentAP() > 0)
{
movementValue = 0;
if(destinationX > currentX)
{
movementValue += 10;
}
if(destinationX < currentX)
{
movementValue -= 10;
}
if(destinationY > currentY)
{
movementValue += 1;
}
if(destinationY < currentY)
{
movementValue -= 1;
}
int nextStep = currentPosition + movementValue;
myGame.setActorIdInTile(currentPosition, -1); //Changes ActorId in PC current tile back to -1
scrubTiles(currentPosition);
actorList.get(selectedActor).setPosition(nextStep); // Sets new position in actor object
System.out.println("Actor " + selectedActor + " " + actorList.get(selectedActor).getName() + " position has been updated to " + nextStep);
myGame.setActorIdInTile(nextStep, selectedActor); // Sets ActorId in moved to Tile
System.out.println("Tile " + nextStep + " actorId has been updated to " + selectedActor);
buttons.get(nextStep).setIcon(new ImageIcon(actorList.get(selectedActor).getImageName()));
// If orthagonal move AP-4
if(movementValue == 10 || movementValue == -10 || movementValue == 1 || movementValue == -1)
{
actorList.get(selectedActor).reduceAP(4);
}
// If diagonal move AP-6
else
{
actorList.get(selectedActor).reduceAP(6);
}
System.out.println(actorList.get(selectedActor).getName() + " has " + actorList.get(selectedActor).getCurrentAP() + " AP remaining");
try
{
Thread.sleep(500); // one second
}
catch (Exception e){}
buttons.get(nextStep).repaint();
}
else
{
System.out.println(actorList.get(selectedActor).getName() + " has insufficient AP to move");
break;
}
}while(destination != (currentPosition + movementValue));
What I've tried:
buttons.get(nextStep).repaint(); (Tried putting a command to repaint the button after setting the imageIcon. No change.
buttons.get(nextStep).revalidate(); (No 100% sure what this does - it came up as a potential solution, but doesn't work.
Steps 1 & 2 combined
Looked into the swing timer class - movement doesn't occur everytime an actionEvent is fired, (only if character is selected and target tile is empty) so not sure how I could get this to work
Any help would be greatly appreciated!
I really dont' know exactly what you wanted to know in your comments, though +1 to the answer above, seems to me that's the real cause. Have a look at this example program, simply add your call to the move(...) method inside the timerAction, seems like that can work for you. Here try this code :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridExample
{
private static final int SIZE = 36;
private JButton[] buttons;
private int presentPos;
private int desiredPos;
private Timer timer;
private Icon infoIcon =
UIManager.getIcon("OptionPane.informationIcon");
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
buttons[presentPos].setIcon(null);
if (desiredPos < presentPos)
{
presentPos--;
buttons[presentPos].setIcon(infoIcon);
}
else if (desiredPos > presentPos)
{
presentPos++;
buttons[presentPos].setIcon(infoIcon);
}
else if (desiredPos == presentPos)
{
timer.stop();
buttons[presentPos].setIcon(infoIcon);
}
}
};
public GridExample()
{
buttons = new JButton[SIZE];
presentPos = 0;
desiredPos = 0;
}
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Grid Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridLayout(6, 6, 5, 5));
for (int i = 0; i < SIZE; i++)
{
final int counter = i;
buttons[i] = new JButton();
buttons[i].setActionCommand("" + i);
buttons[i].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
desiredPos = Integer.parseInt(
(String) buttons[counter].getActionCommand());
timer.start();
}
});
contentPane.add(buttons[i]);
}
buttons[presentPos].setIcon(infoIcon);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(1000, timerAction);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new GridExample().createAndDisplayGUI();
}
});
}
}
This is because you are doing your do { } while in the UI thread. To solve this, you should use a SwingWorker, or a javax.swing.Timer