Java switching jpanels and new panel doesnt respond - java

I start my game with a JFrame which starts a JPanel. That JPanel then moves on to the next one when its ready. I can switch to the new JPanel but it does not respond to my keypresses. The second JPanel previously worked fine so I think the issue is the switch between them. (I removed some methods that are unrelated)
public class GameRunner extends JFrame
{
public GameRunner()
{
super("Scrolling Shooter");
Toolkit tk = Toolkit.getDefaultToolkit();
int width = ((int) tk.getScreenSize().getWidth());
int height = ((int) tk.getScreenSize().getHeight());
setSize(width, height);
TitleScreen title = new TitleScreen(this);
((Component)title).setFocusable(true);
getContentPane().add(title);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String args[])
{new GameRunner();}
}
public class TitleScreen extends JPanel implements KeyListener, Runnable
{
private JFrame frame; //the JFrame
private ImageItem background; //the background
private String name = ""; //the player's name
/**
* Constructs a title screen
* #param f the JFrame
*/
public TitleScreen (JFrame f)
{
frame = f;
ImageItem fix = new ImageItem();
fix.fixMainPath(); //fixes the main path for all the ImageItems
background = new ImageItem(0, 0, frame.getWidth(), frame.getHeight(), "splashscreen.png"); //makes background stretch between the top and bottom walls
setVisible(true);
addKeyListener(this);
new Thread(this).start();
}
/**
* Draws the stuff on the screen
* #param g some Graphics object
*/
protected void paintComponent(Graphics g)
{
background.draw(g);
if (!(name.equals("")))
{
g.setFont(g.getFont().deriveFont(80f));
g.drawString(name, frame.getWidth() / 3, frame.getHeight() - 60);
}
}
/**
* When a key is typed it is added to the name
* #param key the key typed
*/
public void keyTyped(KeyEvent key)
{
if (!(key.getKeyCode() == KeyEvent.VK_ENTER))
name += key.getKeyChar();
}
/**
* Enter makes moves to the game if the name is ok
* #param key the key pressed
*/
public void keyPressed(KeyEvent key)
{
if (key.getKeyCode() == KeyEvent.VK_ENTER)
{
boolean isValid = false;
if (name.length() > 20)
JOptionPane.showMessageDialog(frame, "That name is too long. Try again.");
if (!name.equals(""))
{
try {if (!hasBannedWord(name)) isValid = true;} //breaks the loop if there are no banned words in the name
catch (FileNotFoundException e) {e.printStackTrace();}
}
if (!isValid)
{
JOptionPane.showMessageDialog(frame, "Bad name. Try again.");
name = "";
}
if (isValid)
{
ScrollingShooter game = new ScrollingShooter(frame, name);
((Component)game).setFocusable(true);
frame.getContentPane().removeAll();
frame.getContentPane().add(game);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
}
public void run()
{
try
{
while(true)
{
Thread.currentThread().sleep(0);
repaint();
}
}
catch(Exception e){e.printStackTrace();}
}

Use the key bindings API instead of KeyListeners, it provides better control over the focus level required to generate key events
In order for KeyListener to generate a KeyEvent, the component it is registered to must be focusable AND have focus. There is no "easy" way to guarantee that a component can acquire/grab focus.
You should also consider using a CardLayout to move between your screens, it what it was designed for and will make life a lot easier
You should also call super.paintComponent to ensure that the component/Graphics context is prepared for painting

You're using a KeyListener and KeyListeners often have focus problems that are compounded if you try to swap them.
I suggest that you instead use Key Bindings which can help you get around the focus problems, and that you swap your JPanels with a CardLayout.

Related

JDialogPane with Focused password input field [duplicate]

When my application loads, which is made using netbeans, the first JTextField is automatically focused, and in this JTextField, I have written "Enter your Username", it will go away when the user clicks on this field, but when the application is loaded, this field is focused, means I can't see "Enter your Username", how to unfocus it on startup ?
A log-in would be best done in a modal dialog, but that introduces problems in that the method requestFocusInWindow() must be called after the component is visible, but that is blocked by the fact the dialog is modal!
This example uses Rob Camick's RequestFocusListener (as presented in Dialog Focus) to manage focus after the dialog is visible.
Note: That is how it appears before the user does anything. The password field is focused by default.
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
public class LoginRequired {
LoginRequired() {
JFrame f = new JFrame("Login Required");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setResizable(false);
f.setSize(400, 300); // not recommended, but used here for convenience
f.setLocationByPlatform(true);
f.setVisible(true);
showLogin(f);
}
private void showLogin(JFrame frame) {
JPanel p = new JPanel(new BorderLayout(5,5));
JPanel labels = new JPanel(new GridLayout(0,1,2,2));
labels.add(new JLabel("User Name", SwingConstants.TRAILING));
labels.add(new JLabel("Password", SwingConstants.TRAILING));
p.add(labels, BorderLayout.LINE_START);
JPanel controls = new JPanel(new GridLayout(0,1,2,2));
JTextField username = new JTextField("Joe Blogs");
controls.add(username);
JPasswordField password = new JPasswordField();
password.addAncestorListener(new RequestFocusListener(false));
controls.add(password);
p.add(controls, BorderLayout.CENTER);
JOptionPane.showMessageDialog(
frame, p, "Log In", JOptionPane.QUESTION_MESSAGE);
System.out.println("User Name: " + username.getText());
System.out.println("Password: " + new String(password.getPassword()));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new LoginRequired();
});
}
}
/**
* Convenience class to request focus on a component.
*
* When the component is added to a realized Window then component will
* request focus immediately, since the ancestorAdded event is fired
* immediately.
*
* When the component is added to a non realized Window, then the focus
* request will be made once the window is realized, since the
* ancestorAdded event will not be fired until then.
*
* Using the default constructor will cause the listener to be removed
* from the component once the AncestorEvent is generated. A second constructor
* allows you to specify a boolean value of false to prevent the
* AncestorListener from being removed when the event is generated. This will
* allow you to reuse the listener each time the event is generated.
*/
class RequestFocusListener implements AncestorListener
{
private boolean removeListener;
/*
* Convenience constructor. The listener is only used once and then it is
* removed from the component.
*/
public RequestFocusListener()
{
this(true);
}
/*
* Constructor that controls whether this listen can be used once or
* multiple times.
*
* #param removeListener when true this listener is only invoked once
* otherwise it can be invoked multiple times.
*/
public RequestFocusListener(boolean removeListener)
{
this.removeListener = removeListener;
}
#Override
public void ancestorAdded(AncestorEvent e)
{
JComponent component = e.getComponent();
component.requestFocusInWindow();
if (removeListener)
component.removeAncestorListener( this );
}
#Override
public void ancestorMoved(AncestorEvent e) {}
#Override
public void ancestorRemoved(AncestorEvent e) {}
}
textField.setFocusable(false);
textField.setFocusable(true);
If, and only if, textField had focus, the next component in TAB-order order will get focus automatically. The effect is the same as a TAB press.
(not tested in a GUI with just one focusable component :) )
Use requestFocusInWindow() to set focus on some other component rather then your JTextfield first.
But i'd suggest not to alter the native focus system, rather setText(String s) on the JTextField after initComponents() call in the constructor (assumed to be in netbeans).
Further optional reading: How to Use the Focus Subsystem
I think giving keyboard focus to the username field is the correct behavior, assuming that's what the user needs to do first. Instead of clearing on focus, why not clear only after the user types something?:
import java.awt.*;
import javax.swing.*;
import javax.swing.text.Document;
public class PlaceholderTextField extends JTextField {
public static void main(final String[] args) {
final PlaceholderTextField tf = new PlaceholderTextField("");
tf.setColumns(20);
tf.setPlaceholder("All your base are belong to us!");
final Font f = tf.getFont();
tf.setFont(new Font(f.getName(), f.getStyle(), 30));
JOptionPane.showMessageDialog(null, tf);
}
private String placeholder;
public PlaceholderTextField() {
}
public PlaceholderTextField(
final Document pDoc,
final String pText,
final int pColumns)
{
super(pDoc, pText, pColumns);
}
public PlaceholderTextField(final int pColumns) {
super(pColumns);
}
public PlaceholderTextField(final String pText) {
super(pText);
}
public PlaceholderTextField(final String pText, final int pColumns) {
super(pText, pColumns);
}
public String getPlaceholder() {
return placeholder;
}
#Override
protected void paintComponent(final Graphics pG) {
super.paintComponent(pG);
if (placeholder.length() == 0 || getText().length() > 0) {
return;
}
final Graphics2D g = (Graphics2D) pG;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(getDisabledTextColor());
g.drawString(placeholder, getInsets().left, pG.getFontMetrics()
.getMaxAscent() + getInsets().top);
}
public void setPlaceholder(final String s) {
placeholder = s;
}
}
If you really just want to remove focus, some options:
component.setFocusable(false);
KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();

JFrame does not draw content when called inside ActionListener

I am trying to make a set of 2 GUIs: one, when a button is clicked, calls another, which, based on which button is clicked in the second GUI, returns a value to the first GUI. Unfortunately, when called from the first GUI's actionPerformed method, the second GUI appears blank. This does not, however, happen when JOptionPane is used.
What does JOptionPane do that allows it to work inside the actionPerformed method, and why does my example code not work inside the actionPerformed method?
The code for the first GUI, which calls the second GUI, is as follows:
public class OpeningGUI extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private Container container;
private JButton btn, btn2;
/**
* Constructor for class OpeningGUI - establish the JFrame
* Loads the window and moves it to the center of the screen.
*/
public OpeningGUI() {
// when mama ain't happy, ain't nobody happy
super("Dominion Launcher");
//UI components get established here
container = getContentPane(); // Container is the abstract concept of the area inside a window
container.setLayout(new BorderLayout());
container.add(getCenterPanel(), BorderLayout.CENTER);
setSize(700, 300);
pack();
setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2 - this.getWidth()/2,
(int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()/2 - this.getHeight()/2);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/**
* Sets the game mode based on which button is clicked.
* Click stops return method from waiting.
*/
public void actionPerformed(ActionEvent e) {
if(e.getSource() == btn) {
SelectionDialog sd = new SelectionDialog("Select up to 3 buttons, then click done when selection complete", 3);
System.out.println(sd.getSelectedIndex());
}
if(e.getSource() == btn2) {
JOptionPane.showConfirmDialog(null, "See it works, right");
}
}
/**
* Sets up the center panel with buttons to select game mode.
* #return the center panel.
*/
public JPanel getCenterPanel() {
JPanel temp = new JPanel();
btn = new JButton("SelectionDialog tester");
temp.add(btn);
btn.addActionListener(this);
btn2 = new JButton("JOptionPane tester");
temp.add(btn2);
btn2.addActionListener(this);
return temp;
}
/**
* Main method of OpeningGUI. Used to run the program.
* #param args command-line arguments. Unused.
*/
public static void main(String[] args) {
new OpeningGUI();
}
}
The code for the second GUI is as follows:
public class SelectionDialog extends JFrame implements ActionListener {
private static final long serialVersionUID = 1L;
private Container container;
private JButton confirmBtn;
private JButton[] buttons;
private ArrayList<Integer> selectionIndecies;
private CountDownLatch wait;
private String message;
private int numNeeded;
private boolean isMaximum;
/**
* Constructor for the SelectionDialog class.
* Selects from an ArrayList of buttons.
* #param message Message to display.
* #param num number to select.
*/
public SelectionDialog(String message, int num) {
super("Please Select Buttons");
this.message = message;
numNeeded = num;
isMaximum = false;
setupUI();
}
/**
* Establishes the JFrame and sets values for some fields.
*/
private void setupUI() {
selectionIndecies = new ArrayList<Integer>();
wait = new CountDownLatch(1);
//UI components get established here
container = getContentPane(); // Container is the abstract concept of the area inside a window
container.setLayout(new BorderLayout());
container.add(getTopPanel(), BorderLayout.NORTH);
container.add(getCenterPanel());
pack();
setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2 - this.getWidth()/2,
(int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()/2 - this.getHeight()/2);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/**
* Changes color of buttons and adds or removes them from the selected arrays.
*/
public void actionPerformed(ActionEvent e) {
if(e.getSource() == confirmBtn) {
if((!isMaximum && selectionIndecies.size() <= numNeeded)
|| selectionIndecies.size() == numNeeded) {
wait.countDown();
dispose();
}
}
for(int i = 0; i < buttons.length; i++) {
if(e.getSource() == buttons[i]) {
if(!buttons[i].getBackground().equals(Color.ORANGE)) {
buttons[i].setBackground(Color.ORANGE);
buttons[i].setBorderPainted(false);
selectionIndecies.add(new Integer(i));
repaint();
}
else {
buttons[i].setBackground(Color.LIGHT_GRAY);
selectionIndecies.remove(new Integer(i));
repaint();
}
}
}
}
/**
* Creates the top panel of the GUI.
* Contains the prosperity check box, the number of players selector,
* and the card counter and confirm button.
* #return the top panel.
*/
private JPanel getTopPanel() {
JPanel topPanel = new JPanel();
JLabel temp = new JLabel(message + " ");
topPanel.add(temp);
confirmBtn = new JButton("Done");
topPanel.add(confirmBtn);
confirmBtn.addActionListener(this);
return topPanel;
}
/**
* Determines which buttons were selected.
* Waits until Ok has been clicked and a proper number of buttons had been selected.
* #return an array of indecies of the buttons selected.
*/
public ArrayList<Integer> getSelectedIndex() {
try {
wait.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Collections.sort(selectionIndecies);
return selectionIndecies;
}
/**
* Sets up center panel with ArrayList of buttons,
* and panels of buttons.
*/
private JScrollPane getCenterPanel() {
JPanel centerPanel = new JPanel();
buttons = new JButton[6];
for(int i = 0; i < 6; i++) {
JButton temp = new JButton("Button " + i);
temp.addActionListener(this);
temp.setVisible(true);
centerPanel.add(temp);
buttons[i] = temp;
}
return new JScrollPane(centerPanel);
}
/**
* Main method of the SelectionDialog class. For testing only.
* #param args command line arguments. Unused.
*/
public static void main(String[] args) {
SelectionDialog sd = new SelectionDialog("Select up to 3 buttons, then click done when selection complete", 3);
System.out.println(sd.getSelectedIndex());
}
}
This code is completely runnable with the two classes I have posted and appropriate import statements. The second GUI can also be run independently to show what should appear when called from the first GUI, and the first GUI contains an example JOptionPane that works normally.
Please help me figure out why the actionPerformed method stops only some GUIs from rendering, while others work normally!
You're blocking the EDT! actionPerformed is executed on the EDT, so getSelectedIndex is also and wait.await() blocks it. Notice that once this happens, the first frame doesn't respond also (and minimizing and un-minimizing the frames will not even paint them). Even if the 2nd frame were to show, it would not respond to user interaction because the first actionPerformed did not return.
I don't understand why you need the CountDownLatch. getSelectedIndex can only execute once confrimBtn is pressed, so just return the selected buttons at that point. This isn't the only solution - your design will eventually dictate the interaction between the classes.
In SelectionDialog's actionPerformed write:
if (e.getSource() == confirmBtn) {
if ((!isMaximum && selectionIndecies.size() <= numNeeded) || selectionIndecies.size() == numNeeded) {
Collections.sort(selectionIndecies);
OpeningGUI.publishSelectedIndex(selectionIndecies);
dispose();
}
}
and remove the getSelectedIndex method.
In OpeningGUI, add the following method
public static void publishSelectedIndex(ArrayList<Integer> list) {
System.out.println(list);
}
and remove from its actionPerformed the call to getSelectedIndex.
Notes:
Instead of the screen size calculation for setLocation, you can use setLocationRelativeTo(null).
Calling setSize when you call pack right after it makes the first call redundant.
No need to specify the generic type on the right-hand-side:
selectionIndecies = new ArrayList<>();
Swing should be started on the EDT (see here).
You would probably do better with a dialog instead of another JFrame.
Use different ActionListeners for buttons that function differently instead of checking the source with each call.

Multiple JLabel doesn't print on screen

I want to print multiple label according to the number(no string allowed) you wrote in a text field first. I want it to be dynamical. I want it to change every time you type something in the text field.
So far it can read if it's a number or a string and throw exception if the text doesn't match the requirement.
I've try multiple thing to print multiple Jlabel on the screen, but it didn't work so far.
Here's the code: can you help me?
The main window class
public class MainWindow extends JFrame {
private MainPanel mp = new MainPanel();
public MainWindow()
{
this.setVisible(true);
this.setTitle("Calculateur sur 100");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(200, 400);
this.setLocationRelativeTo(null);
this.setContentPane(mp);
}}
The mainPanel class
public class MainPanel extends JPanel implements ActionListener, MouseListener, KeyListener {
private JTextField tI = new JTextField("Pourcentage");
private JOptionPane jop3 = new JOptionPane();
public MainPanel()
{
this.add(tI);
tI.addKeyListener(this);
tI.addMouseListener(this);
}
//Mathematic calculation
private double onHundred(int tot, int now)
{
return (tot / 100) * now;
}
public void keyReleased(KeyEvent e)
{
boolean ok = true;
try
{
int numbs = Integer.parseInt(tI.getText());
}
catch(Exception s)
{
tI.setText("");
jop3.showMessageDialog(null, "Veuillez entrer seulement des chiffres", "Erreur", JOptionPane.ERROR_MESSAGE);
ok = false;
}
if(ok)
{
System.out.print("Supposed to print");
JLabel[] label = new JLabel[Integer.parseInt(tI.getText())];
for(int i = Integer.parseInt(tI.getText()); i <= 0; i--)
{
label[i] = new JLabel(i + " = " + Math.ceil(onHundred(Integer.parseInt(tI.getText()), i)));
label[i].setVisible(true);
this.add(label[i]);
}
}
}
You MainWindow class should look something like this:
public class MainWindow extends JFrame {
private MainPanel mp = new MainPanel();
public static void main(String[] args) {
new MainWindow();
}
public MainWindow() {
setContentPane(mp);
setTitle("Calculateur sur 100");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
}
Note the order: setContentPane then pack then setVisible. pack replaces setSize as it determines the preferred size of the window based on its components.
I modified your MainPanel class:
public class MainPanel extends JPanel {
private JTextField tI = new JTextField("Pourcentage");
JPanel labelPanel = new JPanel();
public MainPanel() {
setLayout(new BorderLayout());
tI.getDocument().addDocumentListener(new MyDocumentListener());
add(tI, BorderLayout.PAGE_START);
add(labelPanel);
}
private int check() {
int numL;
try {
numL = Integer.parseInt(tI.getText());
} catch (NumberFormatException exc) {
return 0;
}
return numL > 100? 100 : numL;
}
private void update(int numL) {
labelPanel.removeAll();
for (int i = 0; i < numL; i++)
labelPanel.add(new JLabel(String.valueOf(i+1)));
JFrame mainWindow = ((JFrame) SwingUtilities.getWindowAncestor(this));
mainWindow.pack();
mainWindow.repaint();
}
class MyDocumentListener implements DocumentListener {
#Override
public void insertUpdate(DocumentEvent e) {
update(check());
}
#Override
public void removeUpdate(DocumentEvent e) {
update(check());
}
#Override
public void changedUpdate(DocumentEvent e) {
}
}
}
Explanation:
The main panel has the text field separately from another panel which updates dynamically to contain the labels.
The text field uses a DocumentListener instead of a KeyListener to listen to changes in its contents. This is the correct approach for many reasons I will not get into here unless really necessary.
Whenever the text changes, a check method verifies that the input is a number. If it's not it returns 0. If it's more than 100 it returns 100. You can change this behavior as you need.
The value from check is passed to update which clears all the previous labels and reconstructs them. (You can do a bit of optimization here if you want by keeping labels in memory but not displaying them. If the cap is 100 as in my example this won't be noticeable.). The main frame then recalculates the space it needs for all the labels and then repaints.
The labels appear next to each other because the default layout for JPanel is FlowLayout. You can change this as needed.
First - you have Integer.parseInt(tI.getText()) a number of times within the same keyReleased function. When you have done the first check to assign it to int numbs, then use numbs from then on, instead of referring back to tI.getText(). Theoretically the user input can change while you are processing your array, which will cause runtime exceptions or undesired results. Hint - declare numbs directly under ok.
Second - after you add controls programmatically, you need to invalidate the control on to which you are adding them, ie your MainPanel. The invalidate directive tells the control that it is not drawn correctly and needs to be repainted (do this at the completion of your loop). Look through the documentation for JPanel for invalidate and paint.

JFrame and GlassPane - Trouble with repaint()

This question may be a simple matter of me lacking a fundamental understanding of Java Swing or Graphics, and if so, I apologize.
I'm trying to develop a GUI application using Java Swing that can be controlled by an external device that sends pitch, yaw, and roll values via bluetooth to the Application. My idea is to create a cursor (perhaps an empty circle) that moves around when the external device moves around. I have no problems with receiving the data from the device, just the part where I need to actually paint something over all of my components.
I figured that a GlassPane was the easiest way to show a cursor over the entire application, and have it move around when the external device is moved around. I use a Thread to capture the data, and I'm trying to call repaint() afterwards, but it doesn't seem to be triggering.
Here is the relevant code:
JFrame:
public class Frame extends JFrame {
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
//Thread myoHandlerThread = new Thread(myoHandler);
//myoHandlerThread.start();
Frame frame = new Frame();
GlassPane glassPane = new GlassPane();
glassPane.setVisible(true);
frame.setGlassPane(glassPane);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Frame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(50, 50, 1000, 650);
/* Code to add and place components */
}
}
And my GlassPane:
public class GlassPane extends JComponent {
private static double pitch;
private static double yaw;
private static double roll;
Point point;
public void setPoint(Point p) {
this.point = p;
}
public void paintComponent(Graphics g) {
if (point != null) {
System.out.println("Test print statement");
g.setColor(Color.red);
g.fillOval(point.x - 10, point.y - 10, 20, 20);
}
}
public GlassPane() {
Thread handler = new Thread(deviceHandler);
handler.start();
}
private Runnable deviceHandler = new Runnable() {
#Override
public void run() {
Hub hub = new Hub("com.garbage");
System.out.println("Attempting to find device...");
Device externalDevice = hub.waitForDevice(10000);
if (externalDevice == null) {
throw new RuntimeException("Unable to find device!");
}
System.out.println("Connected");
DataCollector dataCollector = new DataCollector();
hub.addListener(dataCollector);
while (true) {
hub.run(1000/20); //gathers data and stores in dataCollector
roll = dataCollector.getRoll();
pitch = dataCollector.getPitch();
yaw = dataCollector.getYaw();
Point p = new Point();
p.setLocation(Math.abs(pitch) * 10, Math.abs(yaw) * 10);
setPoint(p);
repaint();
}
}
};
}
What I would like to happen is for a red circle to be drawn somewhere on the GUI depending on the orientation of the external device. At this point, my "test print statement" doesn't fire even once.
My guess is that I'm lacking some sort of basic understanding of Java's GlassPane or even how paint, paintComponent, and repaint even works. Could anyone point out what I'm doing wrong?
The likely cause of your frustration is trying to set the glass pane visible (Swing components are visible by default), before setting it as the frames GlassPane.
The JFrame is likely resetting the glass pane to be invisible, meaning that it won't be painted (no point painting something that's not visible)
Try setting the glass pane visible AFTER you apply it to the frame

Trying to display a variable created in one jpanel and display it in another jpanel

I'm a student programming a frogger game, when the frog collides with an object or reaches the end zone either the score is incremented or lives decremented and the frog returned to the start position. this section works and the decrement and increment work when outputting them to the console, I try to pass the variable to the other jpanel and display it there but it doesnt update and display the variable in the textField.
Game Panel
public GamePanel() {
super();
setFocusable(true);
addKeyListener(new KeyList());
System.out.println("GAME PANE FOCUS:" + this.isFocusOwner());
scores.setVisible(true);
lives = p.STARTLIVES;
scores.setCurrentLives(lives);
txtTest.setText("Hello");
txtTest.setVisible(true);
add(scores,new AbsoluteConstraints(0,550,50,800));
Boolean displayable = scores.isDisplayable();
System.out.println("Displayable" + displayable);
scores.setEnabled(false);
scores.revalidate();
scores.repaint();
scores.setVisible(true);
System.out.println("Displayable" + displayable);
car1.start();
car2.start();
car3.start();
car4.start();
Log1.start();
Log2.start();
Log3.start();
Log4.start();
Log5.start();
Log6.start();
Log7.start();
Log8.start();
//check for collisions
}
final public void winZone(Rectangle object){
if(myFrog.frogArea().intersects(object)){
currentScore = currentScore + 100;
System.out.println("current Score " + currentScore);
p.setScore(currentScore);
scores.myScore().setText("hello");
myFrog.lostLife();
}
scores panel
public class jplScores extends JPanel {
Properties p = new Properties();
int currentLives;
int i;
/** Creates new form jplScores */
public jplScores() {
initComponents();
}
public void setCurrentLives(int Lives){
currentLives = Lives;
}
public String getCurrentLives(){
String L = Integer.toString(currentLives);
return L;
}
public JTextField myScore(){
return txtScore;
}
Currently it will display the jpanel from the frame that they are both in but i have tried to make it so its a panel within a panel but i cant get the panel to display from within the game panel.
Any help would be great thanks
public FroggerGame() {
initComponents();
setFocusable(true);
//repaint();
// p.setHeight(550);
// p.setWidth(800);
// p.setLives(3);
// p.setScore(0);
PANELHEIGHT = p.getHeight();
PANELWIDTH = p.getWidth();
welcomePanel();
/*
Toolkit tool = Toolkit.getDefaultToolkit();
imgBackground = tool.getImage(imageBackground);
background = new ImageIcon(imgBackground);
//setDefaultCloseOperation(EXIT_ON_CLOSE);
*/
jps.myScore().addPropertyChangeListener(new java.beans.PropertyChangeListener() {
public void propertyChange(java.beans.PropertyChangeEvent evt) {
// txtScorePropertyChange(evt);
jps.myScore().setText(Integer.toString(gp.currentScore()));
System.out.println(Integer.toString(gp.currentScore()));
jps.getScore(gp.currentScore());
System.out.println(" main score " + gp.currentScore());
}
});
}
....
private void btnEnterActionPerformed(ActionEvent evt) {
welcomePanel.setVisible(false);
getContentPane().setLayout(new AbsoluteLayout());
getContentPane().add(gp,new AbsoluteConstraints(0,0,800,550));
getContentPane().add(jps,new AbsoluteConstraints(0,550,800,100));
//gp.setSize(800, 550);
// gp.setBounds(0, 0, 800, 550);
gp.setVisible(true);
gp.requestFocusInWindow();
jps.setVisible(true);
gp is the game panel and jps is the score panel.
This really has little to do with "panels" or Swing GUI coding and all to do with the basic OOPS issue of passing information from one class to another. One way to solve this is to give your Scores panel a public method, say
public void changeScore(int value) {
// in here add the new value to the currently
// displayed value and display the new value.
}
Then the main class, the one with a Scores panel reference, you can call this method, passing in 1 if score is to increase or -1 if it is to decrease.
I think of this as the "push" solution, where one class pushes information into the other class. Another way to solve this is via listeners where the Scores class listens to critical properties of the other class and then changes its own score when an appropriate event occurs, and this often involves using PropertyChangeListeners or other more Swing-specific listener classes. This is sometimes a nicer solution, but I consider it a slightly more advanced concept.

Categories

Resources