JFrame blinking when change its contents and pack() - java

I have a display that just shows a score on a page:
for example:
JIMBOB
Total Score: 22
When a point is scored an event is triggered that updates the score and redraws the new score on the page:
public void showScore(String username, int score)
{
contentPane.remove(layout.getLayoutComponent(BorderLayout.CENTER));
score.setText("<html>" + username + "<br/>Total Hits: " + totalHits + "</html>");
contentPane.add(score, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
Every time a point is scored this function is called, it removes the old score message adds an new one then packs and redraws.
The problem is that the window flickers when drawing the updated frame. And it seems for a split second to be displaying the info unformatted
contentPane is a Container
and frame is a JFrame

Invoking pack() will completely re-render the JFrame, a top-level, heavyweight container owned by the host platform. Instead, update the JComponent used to display the revised score. A complete example is cited here. Excerpted form RCStatus,
public class RCStatus extends JPanel implements Observer {
/** Update the game's status display. */
public void update(Observable model, Object arg) {
// invoke setText() here
}
}
See this answer for more on the observer pattern.

First of all, I would recommend to take a look at how to use JPanels and other GUI components in Swing. You could use a JPanel to be added to the contentPane of your JFrame. Add a desired LayoutManager that is fitting for your need and use it to position a JLabel according to your wishes.
When you call your showScore() method, use setText(String text) on a JLabel instead of the int score that you supply as parameter.
In order to set the text using a String, you need to transform your int score. You can do either of the following two things (but use the first option):
label.setText(String.valueOf(score));
label.setText("" + score);
If you want the score label to appear or disappear, add/ remove it from the JPanel that you added to the JFrame. After adding it, call setText() on the label to display the score. Then, since you reset the text of the label, you should call repaint() on the JPanel. If you choose to add/ remove the JLabel instead of just changing its text you should also call revalidate() on the JPanel.
So all in all the function should look something like this (this is incomplete), assuming totalHits is actually your score.
// declare instance fields before constructor
// both variables are reachable by showScore()
private JPanel scorePanel;
private JLabel scoreLabel;
// in constructor of your class
scorePanel = new JPanel(); // initialize the JPanel
scorePanel.setLayout(new BorderLayout()); // give it a layout
scoreLabel = new JLabel(); // initialize the label
frame.add(scorePanel); // add JPanel to your JFrame
// method obviously outside constructor
public void showScore(String username, int score)
{
// clear the JPanel that contains the JLabel to remove it
scorePanel.removeAll();
scoreLabel.setText("<html>" + username + "<br/>Total Hits: " + String.valueOf(score) + "</html>");
scorePanel.add(label, BorderLayout.CENTER);
scorePanel.revalidate();
scorePanel.repaint();
}
You could also declare and initialize the JPanel and JLabel in the showScore() method, making it more local. But then you would also need to call pack() on the JFrame and clear the previous JPanel from it every time you call the function.
.

Related

java GUI multiple buttons output display error?

I am beginner in Java. This is my first project.
The GUI of the code keeps changing every time I run the code.
Sometimes output doesn't even load completely.
This is the code for just initializing a chess board 8X8 jbuttons.
I have put down the images do checkout the hyperlinks below.
Is there any solution that shows the same output every time the code executes?
package chess;
import game.*;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.util.*;
public class board{
static JButton [][] spots =new JButton [8][8];
public static void main(String[] args){
board b =new board();
b.initializeboard(spots);
}
public void initializeboard(JButton [][] spots){
JFrame f = new JFrame("CHESS");
f.setVisible(true);
f.setSize(800,800);
GridLayout layout =new GridLayout(8,8,1,1);
f.setLayout(layout);
for(int ver=0;ver<8;ver++){
for(int hor=0;hor<8;hor++){
JButton button = new JButton();
if((ver+hor)%2==0){
button.setBackground(Color.WHITE); }
else{
button.setBackground(new Color(255,205,51)); }
pieces p =new pieces();
spots[ver][hor] = button;
p.setButton(button);
f.add(button);
}
}
} //initialize board
} // close board
Improper Execution
Correct Execution
Incomplete Execution
I am beginner in Java.
First of all, class names SHOULD start with an upper case character. Have you even seen a class in the JDK that does not start with an upper case character? Learn by example from the code in your text book or tutorial.
Is there any solution that shows the same output every time the code executes?
All components should be added to the frame BEFORE the frame is made visible.
When the frame is made visible the layout manager is invoked and the components are given a size/location. If you add components to a visible panel, then you need to invoke revalidate() and repaint() on the panel to make sure the layout manager is invoked.
Must admit I'm not sure why you get this random behaviour. Some components are getting a size/location and other are not even though the layout manager is not invoked.
I would suggest you restructure your code something like:
JPanel chessboard = new JPanel( new GridLayout(8, 8, 1, 1) );
// add buttons to the panel
JFrame frame = new JFrame("CHESS")
frame.add(chessboard, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
Other comments:
Don't set the size of the frame. Using 800 x 800 will not make each button 100 x 100. The frame size also include the title bar and borders, so each button size will be less than you expect.
Instead you can create a variable outside of your loops:
Dimension buttonSize = new Dimension(100, 100)
Then when you create the button you use:
button.setPreferredSize( buttonSize );
Now when pack() method is invoked is will size the frame at the preferred size of all the components added to the frame.
All Swing components should be create on the Event Dispatch Thread (EDT). Read the section from the Swing tutorial How to Make Frames. The FrameDemo.java code shows you one way to structure your class so that the invokeLater(…) method is used to make sure code executes on the EDT.
Don't make your variables static. This indicates incorrect class design. Check out the MenuLook.java example found in How to Use Menus for a slightly different design where your ChessBoard becomes a component created in another class. You can then define your instance variables in that class.

Struggling with BoxLayout in Java Swing

Whats up guys I'm struggling to understand how to implement BoxLayout or any layout in java swing. I have been looking at tutorials on oracle and others but i just can't get it to work. This is for an assignment in college so I would appreciate not giving me the solution straight up but maybe just point me in the right direction. I think the problem is my code is different to what is in the tutorials so I'm not sure what goes where.
import javax.swing.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.BoxLayout;
class Window extends JFrame implements ActionListener
{
JPanel panel = new JPanel();
JTextField input = new JTextField(10);
JButton but1 = new JButton ("Convert");
JLabel label = new JLabel();
JTextArea output = new JTextArea(1, 20);
public static void main(String[] args)
{
Window gui = new Window();
String[] days = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
}
public Window()
{
super("Swing Window");
setSize(500, 200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
panel.add(input);
but1.addActionListener(this);
add(panel);
panel.add(output);
label.setText ("please enter celsius to be converted to Fahrenheit");
panel.add(but1);
panel.add(label);
setVisible(true);
}
public void actionPerformed(ActionEvent event)
{
String inputStr = input.getText();
inputStr = inputStr.trim();
double input = Double.parseDouble(inputStr);
double fahrenheit = input * 1.8 + 32;
if (event.getSource() == but1)
{
output.setText("Here is degrees celsius " + input + " converted `to Fahrenheit: " + fahrenheit);`
}
}
}
There is the executable code.
I skimmed your code, but did not execute it. As others already mentioned in the comments, it is helpful for you to describe what the program does and to describe what you expect/want it to do. Otherwise we are just guessing as to what is wrong and what would be correct.
From my reading of your code, I think you see nothing displayed. Correction: you did call add(); as indicated in one of your more recent comments Here are some notes/explanations:
Your method addComponentsToPane() is never called, thus you never create any BoxLayout objects
Recommendation: variable names begin with lowercase, and don't name a variable the same as a class; it easily creates confusion when reading the code. Thus don't name the argument Window.
Your method addComponentsToPane(), if it were called, creates a Layout object and sets it on the component passed to it but does not actually add any components. The name is thus misleading.
A JFrame's content pane has a BorderLayout by default. When components are added without any additional constraints, the BorderLayout chooses to place the components in a certain order (starting with BorderLayout.CENTER). See documentation of the JFrame class where it says the default is BorderLayout.
A JPanel, when created with the default constructor has a FlowLayout by default.
Since your program never changed the panel's layout manager, this is what gives you the left-to-right flow that you observed.
You want to set the panel's layout to a vertical BoxLayout before you add components to it

Java JComboBox repaint error

So I am working with JComboBox in my new program, but for some reason every time something is selected it repaints. I do not want it to repaint the entire program when something is selected, just the boxes specified. See the code below.
The first section here is from the class that contains the panel.
First here are the declarations for the JComboBox's and the Labels they edit once selected:
private JComboBox crewview = new JComboBox(SpaceGame.stuffselector);
private JComboBox resourceview = new JComboBox(SpaceGame.stuffselector1);
private JLabel crewmember, crewmember1, crewmember2;
private JLabel resourcev, resourcev1, resourcev2;
where stuff selector is an array of number digits 1 to 10
My paint method containts these, as it does not work unless I have these here:
resourceview.setLocation(400,80);
resourcev.setLocation(455,85);
resourcev1.setLocation(455,95);
resourcev2.setLocation(455,105);
crewview.setLocation(400, 20);
crewmember.setLocation(455,25);
crewmember1.setLocation(455,35);
crewmember2.setLocation(455,45);
And here are my action listeners:
private class crewviewListener implements ActionListener{
public void actionPerformed(ActionEvent e){
lifeForm temp = SpaceGame.playership.getCrewat(crewview.getSelectedIndex());
crewmember.setText("Name: " + temp.getName()); //set the text to the crew member
crewmember1.setText("Race: " + temp.getRace());
crewmember2.setText("Worth: " + temp.getWorth());
}
}
private class resourceviewListener implements ActionListener{
public void actionPerformed(ActionEvent e1){
Resource temp1 = SpaceGame.playership.getResourceat(resourceview.getSelectedIndex());
resourcev.setText("Name: " + temp1.getName()); //set the text to the crew member
resourcev1.setText("Worth: " + temp1.getWorth());
resourcev2.setText("Amount: " + temp1.getAmount());
}
}
So as you may tell be reading the code, I am trying to get it to only update the JLables when stuff in the box is selected, and not repaint everything.
JLabels are non-opaque by default. This means that whenever you change the text in the label, the background of the label must also be repainted. Therefore the panel that contains the label will also be repainted.
Swing will usually determine a clipped area of the panel to be repainted. That is the rectangular area that contains the 3 labels will be repainted, not the entire panel.
Post a SSCCE that demonstrates the problem if you need more help.

How to represent a Board Panel in Java for a game?

I wanna fix a 2D board for a game. I've already fixed other panels for the Gui and everything goes well. But the panel for the board cant be printed on the window. I'm a bit confused about it as i think i've followed the same ideas as for the others panels i need.
Here's what i've done:
EDIT:
what I'm trying to do is fix a board panel for the game according to the dimensions of the it,hold every square in an array in order to use it after wherever it;s needed. I draw each little square of it with the method draw and put it back to the panel. So, each square on the board is a panel. This is the idea. But as u can see. There are troubles/errors on it.
EDIT: code updated.
just found a part of the problem. i thought first that i had set background to squared, but i didnt. with this one it appears on the panel a wide black "column". Unfortunately,still none squares. :(
One More EDIT:
Also,i realized that draw method is never called. when i put the draw method in the following method i can see the squares but they remain small. I redefine them with setSize but still no change.
How can I use paint method to edit the panels properly???? As it is now it can't. Even it can't return an object(eg panel) as it's polymorphic void!
/**
*Method used to construct the square in the area of the
*gui's grid. In this stage a GUISquare array is being constructed,
* used in the whole game as
*a mean of changing a square graphical state.
*#param squares is the squares array from whom the gui grid will be
*constructed.
*#see getSquare about the correspondance beetween a squareModel and
* a GUISquare.
*/
private void initBoardPanel(SquareModel[][] squares){
BoardPanel.setLayout(new GridLayout(height ,width )); //set layout
SquareRenderer[][] Squares;
JPanel[][] grid;
Squares=new GUISquare[height][width()];
grid=new JPanel[height()][width()];
for (int i=0; i<height(); i++){
for (int j=0; j<width() ; j++){
SquareRenderer kou=new SquareRenderer(i,j);
kou.setSquare(myGame.getSquares()[i][j]);
//NOTE: THE FOLLOWING DRAW METHOD CANT BE CALLED!!!?
if (myGame.getSquares()[i][j] instanceof SimpleSq ){
kou .paintPanel(i,j,"");}
else if (myGame.getSquares()[i][j] instanceof ActionSq )
{ kou .paintPanel(i,j);
}
//JUST BECAUSE DRAW CANT BE CALLED I PUT ITS CODE HERE:
//JUST TO CHECK:
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JLabel label1 = new JLabel("Move To "+myGame.getSquares()[i][j].getGoTo());
JLabel label2 = new JLabel(""+myGame.getSquares()[i][j].getSquare());
panel.setBackground(Color.ORANGE);
panel.add(label2, BorderLayout.NORTH);
panel.add(label1, BorderLayout.CENTER);
panel.setSize(250,250);
///////// <--until here ---paint method<---
kou.add(panel);
kou.setVisible(true);
kou.setBackground(Color.BLACK);
Squares[i][j]= kou;
BoardPanel.add(kou);
BoardPanel.setVisible(true);
BoardPanel.setBackground(Color.WHITE);
}
}
this.add(BoardPanel,BorderLayout.WEST);
// this.pack(); //sets appropriate size for frame
this.setVisible(true); //makes frame visible
}
IMPLEMENTED BY SQUARERENDERER:
/**
* Transformer for Snake/Ladder
* <br>This method is used to display a square on the screen.
*/
public void paintPanel(int i,int j) {
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
JLabel label1 = new JLabel("Move To"+myGame.getSquares()[i][j].getGoTo());
JLabel label2 = new JLabel(""+myGame.getSquares()[i][j].getSquare());
JSeparator CellSeparator = new JSeparator(orientation);
panel.add(CellSeparator);
panel.setForeground(Color.ORANGE);
panel.add(label2, BorderLayout.NORTH);
panel.add(label1, BorderLayout.CENTER);
}
I see a couple things that are problematic:
When using a layout manager, you should avoid calling setSize. Most layout managers will simply override it. You should use setPreferredSize, setMinimumSize, and setMaximumSize instead, which provide hints to the layout manager.
It doesn't look like the draw method of SquareRenderer ever adds the panel you create to anything. You should either add panel to the SquareRenderer in the last line of draw or (better) add the sub-components directly to the SquareRenderer instead.

Add & remove JTextField at runtime in Java(Swings) program

how to add and remove components(JButons , JTextField etc) at runtime in a Swing program (Java ) , without using NetBeans ? which Layout should I use ?
I want the user to enter Username & Password and , when he clicks on Submit button , the new screen with new components(JButtons , JTextField etc) should appear , I am unable to achieve the transition at runtime.
You want to use two different panels to achieve this result. It's not a good idea to use the same panel and remove all of the first components and add all of the second ones.
Make a LoginPanel class which lays out the username and password fields, labels, and submit button. Then, when the submit button is pressed, after the login is authenticated, hide the login panel and display a new panel with the layout you want for the next screen.
This sort of approach makes it much easier to maintain the two panels, and clearly separates their layouts and functionality from each other.
You can center this new frame over the existing panel using this code:
public static void centerFrameOverComponent(JFrame frame, JComponent component) {
Window parent = SwingUtilities.getWindowAncestor(component);
Rectangle frameRect = frame.getBounds();
Rectangle parentRect = parent.getBounds();
int x = (int) (parentRect.getCenterX() - frameRect.getWidth() / 2);
int y = (int) (parentRect.getCenterY() - frameRect.getHeight() / 2);
frame.setLocation(x, y);
}
Another approach is to call setVisible(false) on the specific component when you wish to hide it.
In cases where I have wanted to add/remove an entire sub panel, I have used the following:
panel.remove(subPanel);
panel.revalidate();
panel.repaint();
You want to call the last two methods whenever you add/remove components.
One approach would be to use CardLayout. Your login button handler would check the credentials and use show() to reveal the second pane.
Addendum: For security, consider using JPasswordField for the password; for convenience, consdier setLocationRelativeTo() for positioning the frame.
you could create a new class for exsample MyFrame thath extends JFrame, that rapresetns your new windows, in the constructor of that class you have to add at the contentpanel your all contolr....
in this way you can add a jbutton to your JFrame.
class MyFrame extends JFrame{
private JButton jb= new JButton("hello");
public MyFrame(){
setSize(new Dimension(300,180)); //set the MyFrame size
getContentPane().add(jb); //add your Component at ContentPane
}
}
after the login you could show your new frame in this way:
new MyFrame().setVisible(true);

Categories

Resources