JFrame Screen Replacing Questions - java

The problem that I am having is when I try to replace the main screen with a second one and it deletes the old one but is stuck placing in the new one. If I maximize the screen I can see the new Panels. Another question I had was how to take up spaces in a grid layout without using all of the filler jpanels that I have to do. The code is below:
package home.personalprojects.jordan.ArrayGame;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GuiMain extends JFrame
{
private JButton Inventory, Store, Up, Down, Left, Right, Move, GameInfo, Back = new JButton("Back");
private JLabel pstats, roominfo;
private JPanel Filler1,Filler2,Filler3,Filler4,Filler5,Filler6,Filler7,Filler8,Filler9,Filler10,Filler11;
private JPanel Controls, Main = new JPanel(), BackPanel;
PlayerTraits pt = new PlayerTraits();
Rooms rm = new Rooms();
public GuiMain(){
super("Dungeon Crawler v 0.0.1 Created By: Jordan Savage");
Main.setLayout(new GridLayout(4,3));
//mainbuttons
Inventory = new JButton("Inventory");
Inventory.setToolTipText("Gives you access to all of your items and lets you manage them");
Store = new JButton("Store");
Store.setToolTipText("The marketplace where you can buy and sell items such as swords and armor");
Move = new JButton("Move");
Move.setToolTipText("Choose where you want to move next");
GameInfo = new JButton("Game Information and Settings");
GameInfo.setToolTipText("All the info for the game including instructions, version info, and settings");
//main labels
pstats = new JLabel(pt.name + ": " + pt.gold + " Gold, " + pt.health + " Health, and Level is " + pt.lvl);
roominfo = new JLabel("You are at: (" + pt.x + "," + pt.y + ") In room: " + rm.name);
//fillers for grid layout
Filler1 = new JPanel();Filler2 = new JPanel();Filler3 = new JPanel();Filler4 = new JPanel();Filler5 = new JPanel();Filler6 = new JPanel();Filler7 = new JPanel();Filler7 = new JPanel();Filler8 = new JPanel();Filler9 = new JPanel();Filler10 = new JPanel();Filler11 = new JPanel();
//action listeners
Move.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
ControlScheme();
BackToMain();
getContentPane().removeAll();
getContentPane().add(Controls, BorderLayout.CENTER);
getContentPane().add(BackPanel, BorderLayout.SOUTH);
getContentPane().doLayout();
update(getGraphics());
}
});
Back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
getContentPane().removeAll();
getContentPane().add(Main);
getContentPane().doLayout();
update(getGraphics());
}
});
Main.add(Inventory);
Main.add(Filler1);
Main.add(Store);
Main.add(Filler2);
Main.add(pstats);
Main.add(Filler3);
Main.add(Filler4);
Main.add(roominfo);
Main.add(Filler5);
Main.add(Move);
Main.add(Filler6);
Main.add(GameInfo);
add(Main);
}
public void BackToMain(){
BackPanel = new JPanel();
BackPanel.setLayout(new FlowLayout());
BackPanel.add(Back);
}
public void ControlScheme(){
Up = new JButton("Up");
Down = new JButton("Down");
Left = new JButton("Left");
Right = new JButton("Right");
Controls = new JPanel();
Controls.setLayout(new GridLayout(3,3));
Controls.add(Filler7);
Controls.add(Up);
Controls.add(Filler8);
Controls.add(Left);
Controls.add(Filler9);
Controls.add(Right);
Controls.add(Filler10);
Controls.add(Down);
Controls.add(Filler11);
}
public static void main(String[] args)
{
GuiMain gm = new GuiMain();
gm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gm.setSize(800, 600);
gm.setVisible(true);
gm.setLocationRelativeTo(null);
}
}
Any Help Is Appreciated :)

The short answer would be to call revalidate on the frame.
The better answer would be to use a CardLayout, which was designed to do exactly what you are trying to do...
As to your second question, it can't be done with GridLayout, in fact, you might find it difficult to achieve even with GridBagLayout which gives you control over the placement of components within the virtual grid.
What you might be able to do, is use the fill the grid with empty panels, keeping them in some kind of matrix lookup (ie getComponentAt(gridx, gridy)) and use these to place your components onto instead.
So, for example. If you wanted to place a panel at grid 2x3, you would simply look at the panel at that grid location and place your components onto it.
ps- While I think about, you might also need repaint after revalidate if revalidate along doesn't work...

Related

Adding JPanel into another JPanel using JButton with addActionListener

The commented codes are the problem. When I am using them, panels are added successfully, but I don't need these commented code anymore but same code is not working after I remove or comment those blocks.
Those codes that I have commented need to be removed. Without those commented codes, program runs but does not add panels. I use IntelliJ for my Java Project.
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
public class Test extends JFrame{
JPanel panel;
JButton send;
JTextField text;
JPanel chatArea;
boolean typing;
Test(){
setSize(365,515);
setLocation(50,100);
setLayout(null);
panel = new JPanel();
panel.setLayout(null);
panel.setBounds(0,0,350,60);
panel.setBackground(new Color(90000000));add(panel);
JLabel name = new JLabel("IRONMAN");
name.setFont(new Font("SAN_SERIF", Font.PLAIN,14));
name.setForeground(Color.white);
name.setBounds(110,35,120,20);panel.add(name);
text = new JTextField();
text.setBounds(15,430,260,40);
text.setFont(new Font("SAN_SERIF",Font.PLAIN,14));
text.setForeground(Color.BLUE);
// Timer timer = new Timer(1, event -> {
// if (!typing){
// name.setText("IRONMAN");
// }
// });
// timer.setInitialDelay(2000);
// text.addKeyListener(new KeyAdapter() {
// #Override
// public void keyPressed(KeyEvent e) {
// name.setText("IRONMAN typing...");
// timer.stop();
// typing = true;
// }
// #Override
// public void keyReleased(KeyEvent e) {
// typing = false;
// if (!timer.isRunning()){
// timer.start();
// }
// }
// });
add(text);
chatArea = new JPanel();
chatArea.setBounds(5,65,340,350);
add(chatArea);
send = new JButton("Send");
send.setBounds(280,430,65,30);
send.setBackground(new Color(200,120,255));
send.setForeground(new Color(7,95,75));
send.addActionListener(e -> {
String message = "STARK: "+text.getText();
JPanel p2 = formatLabel(message);
chatArea.add(p2);
text.setText("");
});
add(send);
}
private JPanel formatLabel(String message) {
JPanel p3 = new JPanel();
JLabel label1 = new JLabel("<html><p style = \"width : 150px\">" + message + "</p></html>");
label1.setBackground(new Color(200,120,255));
label1.setForeground(new Color(7,95,75));
label1.setFont(new Font("SAN_SERIF",Font.PLAIN,18));
label1.setOpaque(true);
label1.setBorder(new EmptyBorder(15,15,15,70));
p3.add(label1);
return p3;
}
public static void main(String[] args) {
Test t = new Test();
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.setVisible(true);
}
}
First off all some general comments:
label1.setBorder(new EmptyBorder(15,15,15,70));
Don't be afraid to use whitespace. For example
label1.setBorder(new EmptyBorder(15, 15, 15, 70));
It is easier for our eyes to see text with whitespace.
setLayout(null);
Don't use a null layout. Swing was designed to be used with layout managers. You can easily use the default BorderLayout of the JFrame. Add:
the top panel to BorderLayout.PAGE_START
the chat panel to BorderLayout.PAGE_CENTER
the bottom panel to BorderLayout.PAGE_END
after I remove or comment those blocks.
That code is not the solution or the problem.
The problem is that a component has a size of (0, 0) so there is nothing to paint.
In your existing code try resizing the frame by making it wider. The panel will appear. This is because the resizing will cause the layout manager to be invoked which will give the panel a size so it can be painted.
In your code you need to use:
chatArea.add(p2);
chatArea.revalidate();
The revalidate() will automatically invoke the layout manager.

Java Layout Frustration

I need guidance with GUI Layouts
To narrow it down to main points:
I have three main JPanels (info section, operations and data
structure)
I cannot populate these without the JLabels being shifted
I need a sub-panel for operations with a grid layout (cannot get this
to work and it's really annoying me now)
I need it to look like the picture below
Red separator lines are optional to make it a bit more neater
My next step is to implement a stack but I want to first make it look normal.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class StackPanel extends JPanel {
JPanel west, westSub1, east, south, southSub1;
JTextArea infoText, popText, pushText, peekText, resultText;
JLabel aTitle, bTitle, cTitle, Result;
JButton push, pop, peek, test;
public StackPanel() {
// Creating JPanels
setLayout(new BorderLayout());
west = new JPanel();
westSub1 = new JPanel(new GridLayout(3,2));
east = new JPanel();
south = new JPanel();
west.add(westSub1);
// Creating JLabels / JTextArea
aTitle = new JLabel("Operations");
bTitle = new JLabel("Data Structure Contents");
cTitle = new JLabel("Information");
infoText = new JTextArea("This is where commands will be displayed.");
pushText = new JTextArea("pushtxt");
popText = new JTextArea("poptxt");
peekText = new JTextArea("g");
resultText = new JTextArea("");
west.add(aTitle);
westSub1.add(pushText);
westSub1.add(popText);
westSub1.add(peekText);
westSub1.add(resultText);
east.add(bTitle);
south.add(cTitle);
south.add(infoText);
// Creating & Adding JButtons
push = new JButton("PUSH");
pop = new JButton("POP") ;
peek = new JButton("PEEK");
test = new JButton("TEST");
westSub1.add(push);
westSub1.add(pop);
westSub1.add(peek);
westSub1.add(test);
// Setting the placements of GUI objects
add(west, BorderLayout.WEST);
add(east, BorderLayout.CENTER);
add(south, BorderLayout.SOUTH);
// Declaring JPanel sizes // Width|Height
west.setPreferredSize(new Dimension(200,200));
east.setPreferredSize(new Dimension(400,100));
south.setPreferredSize(new Dimension(100,150));
// Setting black borders for JPanels
west.setBorder(BorderFactory.createLineBorder(Color.black));
east.setBorder(BorderFactory.createLineBorder(Color.black));
south.setBorder(BorderFactory.createLineBorder(Color.black));
// Setting JPanel background colours
west.setBackground(new Color(234,237,242));
east.setBackground(new Color(255,255,255));
south.setBackground(new Color(240,240,240));
}
}
Maybe instead of using labels at the top of each of the west/east/south panels you can use a TitledBorder. This will put a rectangular line around the panel with a title at the top.
Read the section from the Swing tutorial on How to Use Borders for more information and working examples.
If you don't want to do this then you will probably need to change the default FlowLayout or each of the panels to another layout. For example you could use a BorderLayout. Then add the label to the PAGE_START and the other components to the CENTER. The main point is you can nest panels with different layout to achieve your desired layout.
Here is something to get you started. Please read comments and don't hesitate to ask for clarifications as needed.
I did not do all needed layout changes: I did just about to demonstrate waht should be done, so you get the idea.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;
public class StackPanel extends JPanel {
JPanel west, westSub1, east, south, southSub1;
JTextArea infoText, popText, pushText, peekText, resultText;
JLabel aTitle, bTitle, cTitle, Result;
JButton push, pop, peek, test;
public StackPanel() {
// Creating JPanels
setLayout(new BorderLayout());
// Creating JLabels / JTextArea
aTitle = new JLabel("Operations");
bTitle = new JLabel("Data Structure Contents");
west = new JPanel();
//you need to set layout manager to the panel, to lay out its components
west.setLayout(new BorderLayout());
west.setPreferredSize(new Dimension(200,200));
west.setBorder(BorderFactory.createLineBorder(Color.black));
west.setBackground(new Color(234,237,242));
add(west, BorderLayout.WEST);
west.add(aTitle, BorderLayout.NORTH);//use panel's layout manager
//you have 4 rows so GridLayout(3,2) is wrong
westSub1 = new JPanel(new GridLayout(4,2));
//for a grid layout: add components in the right order
push = new JButton("PUSH");
westSub1.add(push);
pushText = new JTextArea("pushtxt");
westSub1.add(pushText);
pop = new JButton("POP") ;
westSub1.add(pop);
popText = new JTextArea("poptxt");
westSub1.add(popText);
peek = new JButton("PEEK");
westSub1.add(peek);
peekText = new JTextArea("g");
westSub1.add(peekText);
test = new JButton("TEST");
westSub1.add(test);
resultText = new JTextArea("");
westSub1.add(resultText);
west.add(westSub1, BorderLayout.CENTER);//use panel's layout manager
east = new JPanel();
east.setPreferredSize(new Dimension(400,100));
east.setBorder(BorderFactory.createLineBorder(Color.black));
east.setBackground(new Color(255,255,255));
east.add(bTitle);
add(east, BorderLayout.CENTER);
south = new JPanel();
//you need to set layout manager to the panel, to lay out its components
south.setLayout(new BorderLayout());
south.setPreferredSize(new Dimension(100,150));
south.setBorder(BorderFactory.createLineBorder(Color.black));
south.setBackground(new Color(240,240,240));
add(south, BorderLayout.SOUTH);
cTitle = new JLabel("Information");
south.add(cTitle, BorderLayout.NORTH); //use panel's layout manager
infoText = new JTextArea("This is where commands will be displayed.");
south.add(infoText, BorderLayout.CENTER);
}
public static void main(String[] args){
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new StackPanel());
frame.pack();
frame.setVisible(true);
}
}
The code has all the imports it needs, as wall as a main to run it.
For more information about how a code should be posted, please read :
https://stackoverflow.com/help/mcve
It's a long time ago that I worked with Swing. But I had the same troubles with the default layouts of Swing. My tip is to change to the TableLayout. It's really easy to use and you can get exact results.
Please check the tutorial: http://www.clearthought.info/sun/products/jfc/tsc/articles/tablelayout/Simple.html
Not perfect but I would chance your code like this
public class StackPanel extends JPanel {
JPanel west, east, south, southSub1;
JTextArea infoText, popText, pushText, peekText, resultText;
JLabel aTitle, bTitle, cTitle, Result;
JButton push, pop, peek, test;
public StackPanel() {
// Creating JPanels
double size[][] = {{0.3, 0.7}, {TableLayout.FILL, 70}};
setLayout(new TableLayout(size));
double sizeWest[][] = {{0.5, 0.5}, {20, 20, 20, 20, 20, 20}};
setLayout(new TableLayout(size));
west = new JPanel(new TableLayout(sizeWest));
east = new JPanel();
south = new JPanel();
// Creating JLabels / JTextArea
aTitle = new JLabel("Operations");
bTitle = new JLabel("Data Structure Contents");
cTitle = new JLabel("Information");
infoText = new JTextArea("This is where commands will be displayed.");
pushText = new JTextArea("pushtxt");
popText = new JTextArea("poptxt");
peekText = new JTextArea("g");
resultText = new JTextArea("");
west.add(aTitle, "0,0,1,0");
west.add(pushText, "0,1");
west.add(popText, "0,2");
west.add(peekText, "0,3");
west.add(resultText, "0,4");
east.add(bTitle);
south.add(cTitle);
south.add(infoText);
// Creating & Adding JButtons
push = new JButton("PUSH");
pop = new JButton("POP") ;
peek = new JButton("PEEK");
test = new JButton("TEST");
west.add(push, "1,1");
west.add(pop,"1,2");
west.add(peek,"1,3");
west.add(test, "1,4");
// Setting the placements of GUI objects
add(west, "0,0");
add(east, "1,0");
add(south, "0,1, 1,1");
// Declaring JPanel sizes // Width|Height
west.setPreferredSize(new Dimension(200,200));
east.setPreferredSize(new Dimension(400,100));
south.setPreferredSize(new Dimension(100,150));
// Setting black borders for JPanels
west.setBorder(BorderFactory.createLineBorder(Color.black));
east.setBorder(BorderFactory.createLineBorder(Color.black));
south.setBorder(BorderFactory.createLineBorder(Color.black));
// Setting JPanel background colours
west.setBackground(new Color(234,237,242));
east.setBackground(new Color(255,255,255));
south.setBackground(new Color(240,240,240));
}}
Hope this works for you!
The basic Swing layout managers are either very rudimentary or very complicated to use.
Therefore maybe FormLayout or MigLayout may be an option to use, which are sophisticated, but not too complicated to use.

How can set location and size for card layout?

I've been working on this small trivia game as a project to keep me busy, but I can't figure out how to make it look good. preferably, the buttons would be at the top and the question would be towards the bottom with a set window size. Although setSize() or setPreferredSize() aren't working. So the window is very thin and the buttons and question are all at the top.
package mainPackage;
import javax.swing.JFrame;
public class MainGame{
public static void main(String[] args) {
new WindowComp();
}
}
package mainPackage;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class WindowComp extends JComponent implements ActionListener {
JFrame frame = new JFrame("trivia game");
static JButton [] buttons;
static JLabel question;
JPanel panelCont = new JPanel();
JPanel panelStartScreen= new JPanel();
JPanel panelGame = new JPanel();
JButton startGame = new JButton("Start Trivia");
CardLayout cl = new CardLayout();
public WindowComp(){
question = new JLabel("default");
buttons = new JButton[4];
panelCont.setLayout(cl);
buttons[0] = new JButton("Answer 1 : " + "default");
buttons[1] = new JButton("Answer 2 : " + "default");
buttons[2] = new JButton("Answer 3 : " + "default");
buttons[3] = new JButton("Answer 4 : " + "default");
buttons[0].addActionListener(this);
buttons[1].addActionListener(this);
buttons[2].addActionListener(this);
buttons[3].addActionListener(this);
startGame.addActionListener(this);
addAll();
panelCont.add(panelStartScreen, "1");
panelCont.add(panelGame, "2");
frame.add(panelCont);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(300, 300);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == buttons[0]){
setQuestion("button 1");
setAnswers( "start", "start", "start", "start");
}
if(e.getSource() == buttons[1]){
setQuestion("button 2");
setAnswers("final", "final", "final", "final");
}
if(e.getSource() == buttons[2]){
setQuestion("button 3");
}
if(e.getSource() == buttons[3]){
setQuestion("button 4");
}
if(e.getSource()==startGame){
cl.show(panelCont, "2");
}
}
public void addAll(){
panelGame.add(buttons[0]);
panelGame.add(buttons[1]);
panelGame.add(buttons[2]);
panelGame.add(buttons[3]);
panelGame.add(question);
panelStartScreen.add(startGame);
}
public static void setAnswers( String ans1, String ans2, String ans3,String ans4){
buttons[0].setText("Answer 1 : " + ans1);
buttons[1].setText("Answer 2 : " + ans2);
buttons[2].setText("Answer 3 : " + ans3);
buttons[3].setText("Answer 4 : " + ans4);
}
public static void setQuestion(String q){
question.setText("Question: " + q);
}
}
Things to note:
1. Calling JFrame.pack() rearranges its components and resizes the JFrame.
2. It's easier (I find) to make a JPanel, call JPanel.setPreferredSize(new Dimension(width, height)), place components inside it, and add it to the JFrame. That way, you may still call JFrame.pack() and the JPanel stays its preferred size.
3. You can remove JFrame.pack(), call JFrame.setPreferredSize(new Dimension(width, height)), and/or JFrame.setResizable(false).
4. You can call JFrame.setMinimumSize(new Dimension(width, height)) to keep it from packing too tightly. Note that this method will not guarantee the specified dimensions when you call JFrame.pack(). In your case, the width stretches a bit due to JFrame.pack() being called afterwards.
5. For your program, I recommend you use JFrame.setLayout(new BorderLayout()), and make a JPanel with a FlowLayout/GridLayout and add your buttons. Then place the JPanel on the BorderLayout.NORTH area. Then create another JPanel, place your questions inside it using a layout of your choice, and add it to BorderLayout.CENTER area in the JFrame. After noting the minimum size that does not interfere with component visibility, configure JFrame.setMinimumSize(new Dimension(width, height)).
6. Layout managers get rid of all the headaches involved with component placements after resizing a window, but rare instances do exist where using setLayout(null) is the best option (see Fig1). If you don't care about users' ability to resize your app, calling JFrame.setResizable(false) will suffice. This will give rise to compatibility issues with lower resolution displays, however.
Figure 1. Placing buttons in this fashion required me to abandon layout managers and configure placement of these buttons according to the width and height variables that update upon resizing the window.
Good luck!

Random Name Generator (inside frame)

I'm trying to create a name generator that generates names by random.
Now when i click the button, it generates a name, but it shows up in the Eclipse console and not in the same window as the button, which is what I want it to do.
Eventually I would like to be able to have a specific picture for for the button and for the background (window/frame). Also, as a bonus I'm hoping to add a bit of music to it that can play in the background once you open the app.
Now, I'm fairly new to java and I've only watched a couple of tutorials, but it's gotten me this far and hopefully I can learn a thing or two from one of you guys.
So please be kind, Best regards leal.
import javax.swing.*;
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.*;
public class ClanNameGenerator {
public static void main (String[] args){
JFrame frame = new JFrame("ExETesT");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,350);
JPanel panel = new JPanel ();
frame.add(panel);
JButton button = new JButton("Click me");
panel.add(button);
button.addActionListener(new Action());
}
static class Action implements ActionListener{
public void actionPerformed (ActionEvent e){
String[] names = {"test", "Zero", "Club", "Moonkys", "znakes", "SeamOnster", "dnktwhm", "Rambo", "OmG", "siste"};
String[] names2 = {"Ylos", "zzzzz", "sdsd", "OK"};
String[] names3 = {"Hei", "ok", "jadd", "så drar vi", "det var det"};
int random = (int) (Math.random()*names.length);
int random2 = (int) (Math.random()*names2.length);
int random3 = (int) (Math.random()*names3.length);
System.out.println("Your clan name is: " + names[random] +" "+ names2[random2] +" "+ names3[random3]);
}
}
}
if you do something like this, the name will appear in JFrame:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class ClanNameGenerator {
private static JLabel label;
public static void main (String[] args){
JFrame frame = new JFrame("ExETesT");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,350);
JPanel panel = new JPanel ();
frame.add(panel);
JButton button = new JButton("Click me");
panel.add(button);
label = new JLabel();
panel.add(label);
button.addActionListener(new Action());
}
static class Action implements ActionListener{
public void actionPerformed (ActionEvent e){
String[] names = {"test", "Zero", "Club", "Moonkys", "znakes", "SeamOnster", "dnktwhm", "Rambo", "OmG", "siste"};
String[] names2 = {"Ylos", "zzzzz", "sdsd", "OK"};
String[] names3 = {"Hei", "ok", "jadd", "så drar vi", "det var det"};
int random = (int) (Math.random()*names.length);
int random2 = (int) (Math.random()*names2.length);
int random3 = (int) (Math.random()*names3.length);
label.setText("Your clan name is: " + names[random] +" "+ names2[random2] +" "+ names3[random3]);
}
}
}
There's a lot going on in your question without you actually asking any questions. As for your text problem though, System.out.println(); will always print to the console, wherever it may be. To add it to the JFrame, you have a variety of options. The one you probably want is to use a JLabel, unless you have a lot of text, in which case a JTextArea may be better suited, or if you intend to do something a little fancier than regular text you may want to draw it directly using the Graphics class and drawString(String).
How to add text to JFrame?
As for the other parts of your... "question," do some research and try things before asking for help on the Stack. This community is for assisting you when things don't work, not for writing your projects for you.
Add a JLabel to your UI, then call the setText method of that JLabel object.
jLabelObject.setText("Your clan name is: " +
names[random] +" "+ names2[random2] +" "+ names3[random3);

Java Swing recursive layout

I know this might seem like a duplicate, but I'm not getting anywhere with by experimenting on invalidate/validate/revalidate/repaint, so please bear with me. My panel structure looks something like this:
JPanel/GridBagLayout (1)
+-- JPanel/BorderLayout
+-- JPanel/GridBagLayout (2)
| +-- JTextField (3)
| +-- JComboBox
+-- JPanel/WhateverLayout
...
... and so forth. In my sub panel (2) I change the insets (right and bottom), and I want to layout the whole top panel (1). Is there some easy way to layout everything (preferably from top panel (1) and down, but anything that works is okey). Right now I've tried combinations of invalidate/validate/revalidate/repaint on all levels, but nothing seems to work (in fact nothing changes at all). Thanks!
Edit: I found out that GridBagLayout clones the GridBagConstraints as components are added, so the reason my code didn't work by running revalidate and friends was that I updated the wrong constraints. I found and added a solution to this problem below.
for re_layout whole JFrame(JDialog e.i.) is there JFrame#pack()
for fill available area in the container (after remove / add) is there revalidate() and repaint()
you have to decide for which of containers in the Components hierarchy
code example about pack() & (re)validate() & repaint()
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class AddComponentsAtRuntime {
private JFrame f;
private JPanel panel;
private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;
public AddComponentsAtRuntime() {
JButton b = new JButton();
b.setBackground(Color.red);
b.setBorder(new LineBorder(Color.black, 2));
b.setPreferredSize(new Dimension(600, 10));
panel = new JPanel(new GridLayout(0, 1));
panel.add(b);
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel, "Center");
f.add(getCheckBoxPanel(), "South");
f.setLocation(200, 200);
f.pack();
f.setVisible(true);
}
private JPanel getCheckBoxPanel() {
checkValidate = new JCheckBox("validate");
checkValidate.setSelected(false);
checkReValidate = new JCheckBox("revalidate");
checkReValidate.setSelected(false);
checkRepaint = new JCheckBox("repaint");
checkRepaint.setSelected(false);
checkPack = new JCheckBox("pack");
checkPack.setSelected(false);
JButton addComp = new JButton("Add New One");
addComp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton b = new JButton();
b.setBackground(Color.red);
b.setBorder(new LineBorder(Color.black, 2));
b.setPreferredSize(new Dimension(600, 10));
panel.add(b);
makeChange();
System.out.println(" Components Count after Adds :" + panel.getComponentCount());
}
});
JButton removeComp = new JButton("Remove One");
removeComp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int count = panel.getComponentCount();
if (count > 0) {
panel.remove(0);
}
makeChange();
System.out.println(" Components Count after Removes :" + panel.getComponentCount());
}
});
JPanel panel2 = new JPanel();
panel2.add(checkValidate);
panel2.add(checkReValidate);
panel2.add(checkRepaint);
panel2.add(checkPack);
panel2.add(addComp);
panel2.add(removeComp);
return panel2;
}
private void makeChange() {
if (checkValidate.isSelected()) {
panel.validate();
}
if (checkReValidate.isSelected()) {
panel.revalidate();
}
if (checkRepaint.isSelected()) {
panel.repaint();
}
if (checkPack.isSelected()) {
f.pack();
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
}
});
}
}
GridBagLayout clones the GridBagConstraints as components are added (that's why changing my original once had no effect on the layout), so I extended GridBagLayout to be able to update the actual constraints runtime. The code below sets the layout margins depending on type of component, and if "expanded", which is what I use to toggle between two modes:
public class ExpandableGridBagLayout extends GridBagLayout {
public void setExpand(boolean expanded) {
for (Map.Entry<Component, GridBagConstraints> entry : comptable.entrySet()) {
setExpandedMargin(entry.getKey(), entry.getValue(), expanded);
}
}
private void setExpandedMargin(Component component, GridBagConstraints constraints, boolean expanded) {
constraints.insets.right = 2;
if (component instanceof JLabel) {
constraints.insets.top = expanded ? 3 : 0;
constraints.insets.bottom = expanded ? 3 : 0;
} else {
constraints.insets.bottom = expanded ? 8 : 5;
}
}
}
Then all I had to do was to call panel.revalidate() on (1) and layouting works as expected.
Still not entirely sure about your exact context, but judging from your "answer" you seem to be changing component constraints on the fly. To trigger a re-layout of the effected parts, you need to
invalidate the child/ren whose constraints had been changed (note: it's not enough to invalidate the parent), this will bubble up the hierarchy as needed
validate an appropriate container up the hierarchy
Snippet:
ExpandableGridBagLayout bag = panel2.getLayout();
bag.setExpand(true);
for(Component child: panel2.getComponents())
child.invalidate();
panel1.validate();
There is no public api to recursively invalidate everything below a given container (invalidateTree is package private). A quick hack is to temporarily toggle the font of the parent container (which internally messages invalidateTree)
/**
* Invalidates the component hierarchy below the given container.<p>
*
* This implementation hacks around package private scope of invalidateTree by
* exploiting the implementation detail that the method is internally
* used by setFont, so we temporary change the font of the given container to trigger
* its internal call.<p>
*
* #param parent
*/
protected void invalidateTree(Container parent) {
Font font = parent.getFont();
parent.setFont(null);
parent.setFont(font);
}
EDIT
Don't know which part of this answer you exactly mean by incorrect - obviously I couldn't solve your problem without any detailed knowledge about it ;-)
Curious me is wondering how a revalidate up in the hierarchy would lead to a re-layout of valid grand/children: validate/Tree clearly stops at a valid component. Below is a code-snippet to play with
it's a two-level hierarchy, a parent with two children
the action changes layout-effecting properties of the sister under its feet (we change v/hgap of the layout) and revalidate the parent
The outcome varies, depending f.i. on the LayoutManager of the parent
with FlowLayout nothing happens ever,
with BoxLayout it may be validated, depending on
whether the horizontal or vertical gap was changed and
the direction of the Box
Looks like a relayout of a valid child might be (or not) a side-effect of a relayout higher up - without any guarantee to happen and hard to predict. Nothing I want to rely on ;-)
final JComponent sister = new JPanel();
final Border subBorder = BorderFactory.createLineBorder(Color.RED);
sister.setBorder(subBorder);
sister.add(new JTextField(20));
sister.add(new JButton("dummy - do nothing"));
JComponent brother = new JPanel();
brother.setBorder(BorderFactory.createLineBorder(Color.GREEN));
brother.add(new JTextField(20));
// vary the parent's LayoutManager
final JComponent parent = Box.createVerticalBox();
// final JComponent parent = Box.createHorizontalBox();
// final JComponent parent = new JPanel();
parent.add(sister);
parent.add(brother);
// action to simulate a change of child constraints
Action action = new AbstractAction("change sub constraints") {
#Override
public void actionPerformed(ActionEvent e) {
FlowLayout layout = (FlowLayout) sister.getLayout();
layout.setHgap(layout.getHgap() * 2);
// layout.setVgap(layout.getVgap() * 2);
// sister.invalidate();
parent.revalidate();
}
};
brother.add(new JButton(action));
JFrame frame = new JFrame("play with validation");
frame.add(parent);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);

Categories