How do I resize and dispose my JFrame window? - java

So I'm taking my first course Java and I'm stumped on my final project. I had to create the game Sokoban from the ground up given a levelReader from my prof. Now my entire game works correctly; tiles are painted, player and boxes move correctly, etc.
However, I have two issues that are minor. These can practically be ignored for final submission but I want to figure this out so I have a more solid understanding.
So my two issues are
a) after the last level is completed (level == totalLevels where level 1 is index 0) the window is disposed and
b) I want every new level generated by initLevel to resize the window.
public void initLevel(int level) {
if(level == totalLevels) { this.dispose(); } //incorrect, unsure what to use
/*
.
. BODY
.
*/
this.setPreferredSize(new Dimension(50*currentLevel.length, 50*currentLevel[0].length));
//sets the window size initially but succeeding levels don't resize
repaint();
}
public static void main(String args[]) {
JFrame f = new JFrame("Sokoban");
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLayout(new FlowLayout());
f.add(new Sokoban("levels.txt"));
f.pack();
f.setVisible(true);
}
Unrelated code was removed from both classes.

Related

Can you make a JPanel randomly generate each time a button is clicked?

Basically just started coding in Java using Eclipse and as my first "serious" project I'm trying to code a simple quiz game. I already set up all the graphics and the answering system but I'm getting stuck at the part where, if you click the right answer, the JPanel restarts with a new question.
I already tried some solutions I've seen online including a do/while method, which proved worthless and calling the main method ( the one where all the code is) which seems impossible.
Here's the method I'm talking about:
public static void main(String []args) throws IOException
{
//here was unnecessary stuff i cut out
ImageIcon image = new ImageIcon (Imagetesting.class.getResource(i+".jpg"));
JLabel label = new JLabel (image);
JFrame f = new JFrame("Quiz");
JLabel x1 = new JLabel(question);
JButton x2 = new JButton(answer1);
//+ other graphic stuff
f.getContentPane().add(MyPanel, "Center"); // Paste MyPanel in center
// of the contentPane
f.setExtendedState(JFrame.MAXIMIZED_BOTH);
f.setVisible(true);
x3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(answer2.equals("therightanswer")){
score = score +1;
x1.setText("Right answer Punteggio:"+String.valueOf(punteggio)
// what am I supposed to put here?
);
;
}
}});
So what am I supposed to do? Is it even possible to call the main method to make it restart? Am I doing something wrong?
You can pass the labels into the actionPerformed function to change the values of those objects when the answer is correct.

JLabel does not fully allign with JFrame

I have a JFrame with a JLabel on top called "coloredLabel", an instance of the class it's in is running on both of them. a random amount of objects move around on the frame and label and don't directly interact with them.
The only problem is that there is a bit of the frame visable above the label, what I want is that the label fully alligns with the frame, without pasting over the objects (which are painted in with an override paint method and mentioned as "game.newBall" and "game.moveBall". "test" is the name of the class.
Here is how my main thread looks, the frame and the label are declared within it:
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame("Bounce 2.0");
JLabel coloredLabel = new JLabel("");
test game = new test();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
coloredLabel.setOpaque(true);
coloredLabel.setBackground(game.backgroundColor);
coloredLabel.setPreferredSize(new Dimension(1000000,1000000));
frame.getContentPane().add(coloredLabel,BorderLayout.LINE_START);
game.add(coloredLabel);
for(int a = randInt(0,9); a<10; a++)
game.newBall(randInt(0,300),randInt(0,400));
while (true) {
double height = frame.getContentPane().getSize().getHeight();
double width = frame.getContentPane().getSize().getWidth();
int n = 0;
while(game.exists(n)==true){
game.moveBall(n,width,height);
n++;
}
game.repaint();
Thread.sleep(10);
}
}
So my question is:
How do I allign the JLabel with the JFrame? so there is no space in between the JLabel and the frame.
I searched for this on this site, but couldn't find the same problem or something similar enough so I could fix this.
solved - game.setBackground(...);
The only problem is that there is a bit of the frame visable above the label,
game.add(coloredLabel);
I'm guessing "game" is a JPanel. By default a JPanel uses a FlowLayout and by default the FlowLayout has horizontal and vertical gaps of 5 pixels.
Get rid of the gap in the FlowLayout. Read the API for the constructors/methods of the FlowLayout to customize its behaviour.
But of course the bigger issue is the design of your app. I don't understand your point of using the label and attempting to take up all the space of the frame. Just set the background of the game panel by using:
game.setBackground(...);
Also class names should:
start with an upper case character and
be descriptive.
"test" is neither.

visualizing JPanel change within a loop

I am new to Java swing programming. I want to make a frame which will appear red and blue in turn one after another. So, I took 2 child JPanel, 1 for red and other for blue, and a for-loop. On each iteration I remove one panel from parent panel and add another. But, when I run the program it only shows the last state of the frame.
Can anyone explain why? And what's the intended approach to make a program work like that?
My code:
public class Test2 extends JFrame {
public Test2() {
JPanel Red = new JPanel(new BorderLayout());
JPanel Blue = new JPanel(new BorderLayout());
//...initialize Red and Blue
Red.setBackground(Color.red);
Blue.setBackground(Color.blue);
Red.setPreferredSize(new Dimension(200,200));
Blue.setPreferredSize(new Dimension(200,200));
JPanel panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(200,200));
add(panel);
pack();
setTitle("Border Example");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
int M = 1000000; //note that, I made a long iteration to not finish the program fast and visualize the effect
for(int i=0;i<M;i++)
{
if(i%(M/10)==0) System.out.println(i); //to detect whether the program is running
if(i%2==0)
{
panel.removeAll();
panel.repaint();
panel.revalidate();
panel.add(Red,BorderLayout.CENTER);
}
else
{
panel.removeAll();
panel.repaint();
panel.revalidate();
panel.add(Blue,BorderLayout.CENTER);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test2 ex = new Test2();
ex.setVisible(true);
}
});
}}
Don't use a loop. Swing will only repaint the frame once the entire loop has finished executing.
Instead you need to use a Swing Timer. When the Timer fires you invoke your logic. Read the section from the Swing tutorial on How to Use Swing Timers.
Here is a simple example of a Timer that simply displays the time every second: Update a Label with a Swing Timer
Also, don't remove/add panels. Instead you can use a Card Layout and sway the visible panel. Again read the tutorial on How to Use CardLayout.
Basically you don't need to use a while (or any other) loop, Swing only paints once it has finished that loop then repaint the GUI.
As stated before by #camickr on his answer, you could try a Swing Timer; here's an example that does exactly what you want.
From your comment on another answer:
Could you please explain why "repaint" does not work in a loop? And why is the Timer working without a "repaint"?
Swing is smart enough to know it doesn't needs to repaint in a loop, instead it will repaint once it the loop finishes, if you read the tutorial on Swing Custom Paint on the step 3 it says:
"Swing is smart enough to take that information and repaint those sections of the screen all in one single paint operation. In other words, Swing will not repaint the component twice in a row, even if that is what the code appears to be doing."
And Timer will repaint it, because it's not running on the EDT but in it's own Thread
I would suggest to take in one step at a time.
First make it run without changing panels / colors.
Now it doesn't because this
public final void Test2() {
is a method (which is never used) and not a constructor.
Change to a constructor declaration like :
public Test2() {
to make the program do something. Then you can go to the next step.
Also use Java naming conventions (like blue instead of Blue).

Some JPanels are not showing in my CardLayout Panels

I'm using card layout to show and hide every panel I made. For the first couple of days, it has been working fine for the first 5 panels I've made. The weird thing is, all of a sudden, my new, 6th panel does not seem to be appearing. There is no syntax error anywhere, I went through all my codes again to look out for any typos, misspellings, failed copy pastes, but can't seem to be able to find anything out of the ordinary... I tried moving on to making the 7th panel today, but the 7th panel was not showing up either.
public ViewController(int width, int height){
this.WIDTH = width;
this.HEIGHT = height;
bgColor = new Color(255,204,153);
mainFrame = new JFrame ("Mei Centre");
mainFrame.setPreferredSize(new Dimension(WIDTH,HEIGHT));
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainPanel = new JPanel();
mainPanel.setLayout (new CardLayout(0,0));
mainPanel.setBackground(bgColor);
mainPanel.setVisible(true);
}
public void makePanels (){
// make most panels
mainPage = new MainPagePanel(this, WIDTH, HEIGHT, bgColor);
adminLoginPage = new AdminLoginPage(this, WIDTH, HEIGHT, bgColor);
playerLoginPage = new PlayerLoginPage(this, WIDTH, HEIGHT, bgColor);
playerLoginPrompt = new PlayerLoginPrompt (controller, this, WIDTH, HEIGHT, bgColor);
playerMainMenu = new PlayerMainMenu (controller, this, WIDTH, HEIGHT, bgColor);
gameSettings = new GameSettingPanel (controller, this, WIDTH, HEIGHT, bgColor);
dealerShuffle = new DealerShufflePanel (bgColor);
// add panels to frame in chronological order
mainPanel.add(mainPage, "MainPage"); // index 0
mainPanel.add(adminLoginPage, "Admin"); // index 1
mainPanel.add(playerLoginPage, "Player"); // index 2
mainPanel.add(playerLoginPrompt, "LoginPlayer"); // index 3
mainPanel.add(playerMainMenu, "PlayerMainMenu"); // index 4
mainPanel.add(gameSettings, "GameSetting"); // index 5
mainPanel.add(dealerShuffle, "DealerShuffle"); // index 6
mainFrame.add(mainPanel);
mainFrame.pack();
mainFrame.setVisible(true);
}
// make and add GamePlayPanel into mainPanel
public void makeGamePanel(Dealer dealer, GameTable table, ArrayList<GamePlayerInterface> gamePlayers) {
System.out.println("Making gamePlayPanel");
gamePlay = new GamePlayPanel (controller, this, WIDTH, HEIGHT, bgColor, dealer, table, gamePlayers);
mainPanel.add(gamePlay, "GamePlay"); // index 7
mainPanel.repaint();
}
This is my ViewController (class that controls the main flow of my GUI). I made a main panel and set layout to CardLayout, and made all my other panels and added them into the main panel. The 7th panel was added in later, outside the constructor (inside makeGamePanel method)
public void showPanel(String page) {
System.out.println("Showing panel -> " + page);
CardLayout cl = (CardLayout)(mainPanel.getLayout());
cl.show(mainPanel, page);
}
This is my method used to control which panel to show. It works from panel in index 0 up to 5 (list in screenshot above)
private class changePanel implements ActionListener{
String page;
public changePanel(String page){
this.page = page;
}
public void actionPerformed(ActionEvent e){
System.out.println(page + " is clicked");
vController.showPanel(page);
}
}
When I click on some Jbuttons in any of the panels above, I will assign this action listener with the appropriate panel name, so that it may call the method to show the appropriate panel.
private void startRound(GameTable table, ArrayList<GamePlayerInterface> gamePlayers, GamePlayer human) {
// GAME START! dealer shuffles cards
dealer.shuffleCards();
view.showPanel("DealerShuffle");
/* insert some delayer here*/
/*does some game logic action*/
// make game play GUI
view.makeGamePanel(dealer, table, gamePlayers);
view.showPanel("GamePlay");
My issue is with the 6th and 7th index panel (DealerShuffle, and GamePlay), which are called in my game controller (class which handles all game logic running) .
I've checked to make sure that my controller and my view are both linked to each other, so it doesn't seem to be an issue of different instances.
Enter Choice --> Player is clicked.
Showing panel -> Player.
LoginPlayer is clicked.
Showing panel -> LoginPlayer.
Player Login information entered, checking information
username input got is : maggie
password input got is : joey
Showing panel -> PlayerMainMenu
Play game button clicked
Showing panel -> GameSetting
Game start button clicked!
Setting game with 1 opponents, 1 difficulty, 1 size.
Game Start
Showing panel -> DealerShuffle
Dealer deals cards onto table
Making gamePlayPanel
Game Play Panel has been created
Showing panel -> GamePlay
These are the results of a normal run. In the bottom few lines, it shows that my program is running properly, and that its even trying to show the DealerShuffle panel and GamePlay shuffle, but what actually happens on screen is: right as the changing panel method is called to show DealerShuffle, the previous panel (GameSettings) is actually disabled, but DealerShuffle doesn't appear, so the screen is stuck at an after-image of the GameSetting panel, with nothing for me to click on or interact with. Needless to say, my GamePlay panel afterwards wasn't showing up either.
If anybody wants to check out my whole program to run, here is the link to my zipped files:
Program zip file
The codes will be in a quite a mess, as I've only started implementing GUI on a program which was previously running off on console.
Thank you for your time and help!
Nvm, I may not have fixed the issue with the way my codes are currently structured or learnt what was causing the issue in the first place, but I managed to get it to work after building it from scratch again and restructuring my codes. This time instead of creating the JPanels in the viewController and adding them inside, I've build the JPanels in the Controller instead and passed them into the viewController to add to the JFrames. So anyways, problem solved. Thanks to all who helped!

Updating the edge weight displayed without being "cluncky"

I am using Jgrapht to build a simulation environment based on a directed weighted graph. I now want to display the simulation using Jgraph.
While I have figured out how to display the graph and update it as the simulation runs, I have noticed that when the edge weights update, the entire window flickers. Presently I an calling frame.paintComponents() to update the window.
I believe that I can get it to only update the individual edges that are changing, but I am not familiar with java.awt.
public static void main(String [] args) throws InterruptedException
{
Simulation newSim = new Simulation(31, .01);//extends ListenableDirectedWeightedGraph
SimulationViewer applet = new SimulationViewer(newSim);//extends JApplet
applet.init();
JFrame frame = new JFrame();
frame.getContentPane().add(applet);
frame.setTitle("Simulation Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
//run simulation
for (;newSim.getStep() < newSim.getMAX_STEP(); newSim.incrementStep()) {
BreadthFirstIterator<SimulationBlock, Signal> iter =
new BreadthFirstIterator<SimulationBlock, Signal>(newSim, newSim.head);
while (iter.hasNext()) {
iter.next().execute(newSim);
//update graphics
frame.paintComponents(applet.getGraphics());//looks clunky
Thread.sleep(500);
}
}
}
Looks like I needed to call the update method for applet. Replaced:
frame.paintComponents(applet.getGraphics());//looks clunky
With:
applet.update(applet.getGraphics());
This looks a little funky and maybe I need to refactor this code so that is within the SimulationViewer class.

Categories

Resources