I am trying to get this code to work, such that I have a cardlayout container and each panel be defined in its own class and actual file. This code is not 100% my own and is a modified version of my previous stuff by another Stack overflow user. It is more or less what I need, but I need it such that it isn't automated and I can write 15 different panels with decisions made inside each one. The Main and Arrow class was modified by said user, and Imagepanel is my attempt to write a class that will be accepted by the working part of the code. The issue is the Imagepanel I insert into the container will register as existing, but nothing shows up on the panel, it's blank. The commented out portion in ImagePanel is my code that I set on the back burner in favor of the established stuff previously used in the Arrow class.
Here is the Main class
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.*;
import javax.swing.*;
public class Main extends JPanel {
private Arrow arrow = new Arrow(); //creates a new Arrow object
public Main() {
JPanel btnPanel = new JPanel();
btnPanel.add(new JButton(new NextAction("Next")));
setLayout(new BorderLayout());
add(arrow, BorderLayout.NORTH);
add(btnPanel, BorderLayout.PAGE_END);
}
private class NextAction extends AbstractAction {
public NextAction(String name) {
super(name);
}
#Override
public void actionPerformed(ActionEvent e) {
arrow.next(); // *** call arrow's public next method that you created
// no need to make a new CardLayout instance
}
}
private static void createAndShowGui() {
Main mainPanel = new Main();
JFrame frame = new JFrame("Iowa Budget Simulation");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Here is the Arrow class where the container is created
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import javax.swing.*;
class Arrow extends JPanel {
private static final long serialVersionUID = 1L;
private CardLayout cardLayout = new CardLayout(); // make me a field
private JPanel cardHolder = new JPanel(cardLayout); //creates a master JPanel
public Arrow() {
for (int i = 0; i < 5; i++) {
cardHolder.add(createCard(i), "card " + i);
}
ImagePanel pear = new ImagePanel();
cardHolder.add(pear, "Pear");
setLayout(new BorderLayout());
add(cardHolder, BorderLayout.NORTH);
}
// public method that other objects can call
public void next() {
cardLayout.next(cardHolder); // call next on the correct object
}
// simply creates a "pretty" new JPanel
private JComponent createCard(int i) {
JLabel label = new JLabel("Card " + i);
label.setFont(label.getFont().deriveFont(Font.BOLD, 50f));
float h = (float)Math.random();
Color c = Color.getHSBColor(h, 1f, 1f);
label.setForeground(c.darker());
JPanel panel = new JPanel(new GridBagLayout());
panel.add(label);
panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
panel.setBackground(c.brighter().brighter());
panel.setPreferredSize(new Dimension(400, 300));
return panel;
}
Here is ImagePanel, my attempt at a 3rd, individual panel/class
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import javax.swing.*;
class ImagePanel extends JPanel {
private static final long serialVersionUID = 1L;
private String imgString;
private JLabel imgLabel;
public JComponent ImagePanel() {
/*
setName("Pear");
JLabel john = new JLabel("Pear");
float h = (float)Math.random();
Color c = Color.getHSBColor(h, 1f, 1f);
john.setForeground(c.darker());
JPanel panel = new JPanel(new GridBagLayout());
panel.add(john);
panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
panel.setBackground(c.brighter().brighter());
// Ensure size is correct even before any image is loaded.
setPreferredSize(new Dimension(400, 300));
return panel;
*/
JLabel label = new JLabel("Pear");
label.setFont(label.getFont().deriveFont(Font.BOLD, 50f));
float h = (float)Math.random();
Color c = Color.getHSBColor(h, 1f, 1f);
label.setForeground(c.darker());
JPanel panel = new JPanel(new GridBagLayout());
panel.add(label);
panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
panel.setBackground(c.brighter().brighter());
panel.setPreferredSize(new Dimension(400, 300));
return panel;
}
There is no error to post, it simply displays a blank panel. Thank you for any assistance I might receive, and I apologize in advance as I am learning Java Swing GUI through YouTube and stack overflow.
public JComponent ImagePanel() { isn't a constructor, it's a method, to make it work in your code you would have to change ImagePanel pear = new ImagePanel(); to JComponent pear = new ImagePanel().ImagePanel();, but frankly that just doesn't make much sense.
Instead, change public JComponent ImagePanel() { to public ImagePanel() {, now it's the class's constructor
Next, change...
JPanel panel = new JPanel(new GridBagLayout());
panel.add(label);
panel.setBorder(BorderFactory.createLineBorder(c.darker(), 20));
panel.setBackground(c.brighter().brighter());
panel.setPreferredSize(new Dimension(400, 300));
return panel;
to
setLayout(new GridBagLayout());
add(label);
setBorder(BorderFactory.createLineBorder(c.darker(), 20));
setBackground(c.brighter().brighter());
//panel.setPreferredSize(new Dimension(400, 300));
//return panel;
Don't get me started on why setPreferredSize is a bad idea
Now you can simply use
ImagePanel pear = new ImagePanel();
cardHolder.add(pear, "Pear");
Related
I'm trying to figure out how to position my buttons in the center right position. I added what Ive done so far and I'll add a drawing of how I want it to be.
I'm trying to understand how to determine the position I want in Swing, can't really understand the advantages of each layout.
My code so far:
package Game;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JToolBar;
import javax.swing.Timer;
public class MainWindow extends JFrame implements ActionListener {
private JButton exit;
private JButton start_Game;
private ImageIcon puzzleBackground;
// private JLabel back_Label;
// private GridBagConstraints grid = new GridBagConstraints();
private JPanel menu;
public MainWindow()
{
super("Welcome");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setSize(450,300);
setLocationRelativeTo(null);
this.setLayout(new FlowLayout(FlowLayout.RIGHT));
menu = new JPanel();
menu.setLayout(new BorderLayout());
//setResizable(false);
//===== Background =====
puzzleBackground = new ImageIcon("MyBackground.jpg");
setContentPane(new JLabel(puzzleBackground));
exit = new JButton("Exit");
menu.add(exit, BorderLayout.CENTER);
exit.addActionListener(this);
start_Game = new JButton("Start to play");
menu.add(start_Game, BorderLayout.SOUTH);
exit.addActionListener(this);
start_Game.addActionListener(this);
//
// back_Label = new JLabel(puzzleBackground);
// back_Label.setLayout(new BorderLayout());
//===== Buttons =====
// back_Label.add(exit,BorderLayout.CENTER);
//
// back_Label.add(start_Game,BorderLayout.EAST);
//
add(menu);
setVisible(true);
}
public static void main(String args[])
{
MainWindow a = new MainWindow();
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == exit)
{
System.exit(0);
}
else
{
//open start up window.
}
}
}
A better way to add a BG image is to use a custom painted JPanel. Then set the layout of the panel and add other panels or components to it. Note that here the buttons are not appearing largely because they are being added to a JLabel.
Here is an alternative that works along the same lines, with the red panel being the panel which custom paints the background image and the menu panel being set to transparent (look for the opaque method).
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.*;
public class MainWindow extends JFrame {
private JPanel menu;
private JPanel contentPane = new JPanel(new BorderLayout(4,4));
public MainWindow() {
super("Welcome");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//setSize(450, 300); // use pack() instead
setContentPane(contentPane);
contentPane.setBorder(new EmptyBorder(8,8,8,8));
contentPane.setBackground(Color.RED);
contentPane.add(new JLabel(new ImageIcon(
new BufferedImage(400,200,BufferedImage.TYPE_INT_RGB))));
menu = new JPanel(new GridLayout(0,1,10,10));
menu.add(new JButton("Exit"), BorderLayout.CENTER);
menu.add(new JButton("Start to play"), BorderLayout.SOUTH);
JPanel menuCenterPanel = new JPanel(new GridBagLayout());
menuCenterPanel.add(menu);
add(menuCenterPanel, BorderLayout.LINE_END);
pack();
setLocationRelativeTo(null); // do AFTER pack()
setMinimumSize(getSize());
setVisible(true);
}
public static void main(String args[]) {
MainWindow a = new MainWindow();
}
}
So, your basic problem boils down the following lines...
this.setLayout(new BorderLayout());
//...
//===== Background =====
puzzleBackground = new ImageIcon("MyBackground.jpg");
setContentPane(new JLabel(puzzleBackground));
Can you tell me what the layout manager in use actually is now? Wrong. The layout manager is now null, because JLabel doesn't actually have a default layout manager.
So, the "simple" answer would be to move the setLayout call to below the setContentPane call, but this would be a short sighted answer, as JLabel calculates it's preferred based on the icon and text properties only, not it's contents of child components.
A better solution would be to do something demonstrated in How to set a background picture in JPanel (see the second example)
This means that if the image is smaller then the required space, the components will disappear off the screen.
I went through and cleaned up the code slightly, only with the intention of getting the layout to work
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainWindow extends JFrame implements ActionListener {
private JButton exit;
private JButton start_Game;
private JPanel menu;
public MainWindow() {
super("Welcome");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
this.setLayout(new BorderLayout());
menu = new JPanel();
menu.setLayout(new GridBagLayout());
exit = new JButton("Exit");
exit.addActionListener(this);
start_Game = new JButton("Start to play");
exit.addActionListener(this);
start_Game.addActionListener(this);
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.fill = gbc.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
menu.add(exit, gbc);
menu.add(start_Game, gbc);
// This is just a filler, it can be removed, but it helps prove the point
add(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
});
add(menu, BorderLayout.EAST);
pack();
setVisible(true);
}
public static void main(String args[]) {
MainWindow a = new MainWindow();
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == exit) {
System.exit(0);
} else {
//open start up window.
}
}
}
I'd also like to point out that extending directly from JFrame is also short sighted, it's locking you into a single use container and you're not actually adding any new functionality to the class.
Example of better structure...
The following is a simple example of a possibly better structure. It's missing the concept of a "controller", which controls stuff and "model" which maintains the state information which is used by the UI to display "stuff", but gives a starting point
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String args[]) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Welcome");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MainPane extends JPanel {
public MainPane() {
setLayout(new BorderLayout());
// This is just a filler, it can be removed, but it helps prove the point
add(new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
});
add(new MenuPane(), BorderLayout.EAST);
}
}
public class MenuPane extends JPanel {
private JButton exit;
private JButton start_Game;
private JPanel menu;
public MenuPane() {
menu = new JPanel();
menu.setLayout(new GridBagLayout());
ActionHandler actionHandler = new ActionHandler();
exit = new JButton("Exit");
exit.addActionListener(actionHandler);
start_Game = new JButton("Start to play");
start_Game.addActionListener(actionHandler);
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.fill = gbc.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
menu.add(exit, gbc);
menu.add(start_Game, gbc);
}
public class ActionHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == exit) {
System.exit(0);
} else {
//open start up window.
// This should be used to notifiy a controller class
// that some new action needs to take place, the controller
// is then responsible for making it happen
}
}
}
}
}
Doing UI in Java is not advised, but ignoring that.
You get (calculate) the height and width of the screen. Then start drawing buttons depending on that. Drawing a button on screens 50% of pixel value width and 50% of pixel value of height will center the button.
Simply crate buttons with variable location that is calculated from main screen px size and place them where ever you want.
I'm making a small game and at the beginning i want to have JCheckBox for choosing the language(after that they are few more of them for setting the game) and above that a jlabel with picture with name of the game OR draw an image there, the problem is that i dont know any other way how to center the panel with checkboxes then to use GridBagLayout and when i use this, i cannot draw anything to the frame, id like to also remove those grey lines around the checkboxes if its possible, appreciate any help, thanks.
This is my second question here and i cant add images yet so here is a link to the picture :
here is code for the frame
private GamePlan plan;
private JFrame frame;
private String language;
private JPanel panel;
private JCheckBox englishBox;
private JCheckBox germanBox;
public Settings(GamePlan plan){
this.plan = plan;
frame = new JFrame();
frame.setSize(600, 500);
frame.setLocation(200, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.setResizable(false);
frame.setVisible(true);
panel = new JPanel(new GridLayout(2, 1));
englishBox = new JCheckBox("English", false);
germanBox = new JCheckBox("German", false);
englishBox.addActionListener(new EnglishLanguage());
germanBox.addActionListener(new GermanLanguage());
panel.add(englishBox);
panel.add(germanBox);
englishBox.setOpaque(false);
germanBox.setOpaque(false);
panel.setOpaque(false);
frame.add(panel);
frame.getContentPane().setBackground(new Color(216,252,202));
}
" the problem is that i dont know any other way how to center the panel with checkboxes then to use GridBagLayout and when i use this, i cannot draw anything to the frame"
I can't really tell what you're doing wrong without a complete example. I don't even see where you're trying to add the image. But don't try and draw on the frame. Draw on a JPanel instead.
Here is an example you may be able to gain some insight from.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
public class ImageByDrawing {
public ImageByDrawing() {
ImagePanel imagePanel = new ImagePanel();
imagePanel.setBorder(new TitledBorder("Drawn Image onto JPanel"));
JCheckBox germanBox = new JCheckBox("German");
germanBox.setOpaque(false);
JCheckBox englishBox = new JCheckBox("English");
englishBox.setOpaque(false);
JPanel boxPanel = new JPanel();
boxPanel.setBorder(new TitledBorder("JPanel with default FlowLayout"));
boxPanel.setOpaque(false);
boxPanel.add(germanBox);
boxPanel.add(englishBox);
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.add(imagePanel, BorderLayout.CENTER);
centerPanel.add(boxPanel, BorderLayout.SOUTH);
centerPanel.setBorder(new TitledBorder("JPanel with BorderLayout"));
centerPanel.setOpaque(false);
JPanel mainPanel = new JPanel(new GridBagLayout());
mainPanel.add(centerPanel);
mainPanel.setBorder(new TitledBorder("JPanel with GridBagLayout"));
mainPanel.setBackground(new Color(216,252,202));
JFrame frame = new JFrame();
frame.add(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class ImagePanel extends JPanel {
BufferedImage img;
int dWidth;
int dHeight;
public ImagePanel() {
try {
img = ImageIO.read(getClass().getResource("/resources/stackblack.jpg"));
dWidth = img.getWidth();
dHeight = img.getHeight();
} catch (IOException ex) {
Logger.getLogger(ImageByDrawing.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, img.getWidth(), img.getHeight(), this);
}
#Override
public Dimension getPreferredSize() {
return (img == null) ? new Dimension(300, 300) : new Dimension(dWidth, dHeight);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new ImageByDrawing();
}
});
}
}
Also I don't know why you prefer to draw the image. The same can be easily done with a JLabel and ImageIcon
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridBagLayout;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
public class ImageByDrawing {
public ImageByDrawing() {
ImageIcon icon = new ImageIcon(getClass().getResource("/resources/stackblack.jpg"));
JLabel label = new JLabel(icon);
label.setBorder(new TitledBorder("JLabel with ImageIcon"));
JCheckBox germanBox = new JCheckBox("German");
germanBox.setOpaque(false);
JCheckBox englishBox = new JCheckBox("English");
englishBox.setOpaque(false);
JPanel boxPanel = new JPanel();
boxPanel.setBorder(new TitledBorder("JPanel with default FlowLayout"));
boxPanel.setOpaque(false);
boxPanel.add(germanBox);
boxPanel.add(englishBox);
JPanel centerPanel = new JPanel(new BorderLayout());
centerPanel.add(label, BorderLayout.CENTER);
centerPanel.add(boxPanel, BorderLayout.SOUTH);
centerPanel.setBorder(new TitledBorder("JPanel with BorderLayout"));
centerPanel.setOpaque(false);
JPanel mainPanel = new JPanel(new GridBagLayout());
mainPanel.add(centerPanel);
mainPanel.setBorder(new TitledBorder("JPanel with GridBagLayout"));
mainPanel.setBackground(new Color(216, 252, 202));
JFrame frame = new JFrame();
frame.add(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ImageByDrawing();
}
});
}
}
The last part of your question, as #Jere pointed out you can use setFocusPainted for the check box germanBox.setFocusPainted(false);
I have been writing and refactoring the code that I started with for Hangman game. I have basically two classes now. One is that launch the hangman (contains main) and other is the getting the panel plugged in with various components. In total, I will have one frame and one Panel, few buttons and a Label and textfield. I have pasted my two bits of code below. I wanted to have all the pushed down to the frame, The label and textfield in the center and I need empty space on the top to put more stuff. I tried BorderLayout.SOUTH, but did not help. The border title is spreading all over, but I would like it to have it surround just the radio buttons. Kindly run the code to see what I mean.
Thanks
Code1 : with Main method
import javax.swing.*;
import javax.swing.text.MaskFormatter;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.text.ParseException;
public class HangmanGUI {
DetailsPanel myPanel;
public HangmanGUI() throws ParseException {
myPanel = new DetailsPanel();
JFrame myframe = new JFrame();
myframe.getContentPane().setLayout(new BorderLayout());
myframe.getContentPane().add(myPanel, BorderLayout.SOUTH);
myframe.setTitle("Hangman Game");
myframe.setVisible(true);
myframe.setLocationRelativeTo(null);
myframe.pack();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) throws ParseException {
new HangmanGUI();
}
}
code 2: with panel and components
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.text.MaskFormatter;
public class DetailsPanel extends JPanel {
public DetailsPanel() {
setPreferredSize(new Dimension(400, 600));
setBorder(BorderFactory.createTitledBorder(" ciick here "));
createFormattedPanel();
for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
String buttonText = String.valueOf(alphabet);
JButton letterButton = new JButton(buttonText);
letterButton.addActionListener(clickedbutton());
this.add(letterButton, BorderLayout.CENTER);
}
}
private ActionListener clickedbutton() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
System.out.println("actionCommand is: " + actionCommand);
}
};
}
public void createFormattedPanel() {
MaskFormatter formatter = null;
try {
JLabel label = new JLabel("Guesss");
formatter = new MaskFormatter("? ? ? ? ? ? ?");
formatter.setPlaceholderCharacter('?');
JFormattedTextField input = new JFormattedTextField(formatter);
input.setColumns(20);
this.add(label);
this.add(input);
} catch (java.text.ParseException exc) {
System.err.println("formatter is bad: " + exc.getMessage());
System.exit(-1);
}
}
}
I would use an image JPanel to hold your hangman drawing, and to act as a placeholder and place it in the JFrame in the BorderLayout.CENTER position. I would also clean up the south JPanel by using layout managers and not relying on default FlowLayout. For instance a BorderLayout for the south Jpanel, put the guess in the page start slot and the buttons in the center slot, and put the buttons into a GridLayout JPanel. For example:
import javax.swing.*;
import javax.swing.text.MaskFormatter;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.text.ParseException;
public class HangmanGUI {
private DetailsPanel myPanel;
private ImagePanel imagePanel = new ImagePanel();
public HangmanGUI() throws ParseException {
myPanel = new DetailsPanel();
JFrame myframe = new JFrame();
// myframe.getContentPane().setLayout(new BorderLayout());
myframe.getContentPane().add(imagePanel, BorderLayout.CENTER);
myframe.getContentPane().add(myPanel, BorderLayout.SOUTH);
myframe.setTitle("Hangman Game");
// myframe.setVisible(true);
// myframe.setLocationRelativeTo(null);
myframe.pack();
myframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myframe.setLocationRelativeTo(null);
myframe.setVisible(true);
}
public static void main(String[] args) throws ParseException {
new HangmanGUI();
}
}
class ImagePanel extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final String TITLE = "Hangman Image";
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public ImagePanel() {
setBorder(BorderFactory.createTitledBorder(TITLE));
}
}
class DetailsPanel extends JPanel {
public DetailsPanel() {
setLayout(new BorderLayout());
setBorder(BorderFactory.createTitledBorder(" ciick here "));
add(createFormattedPanel(), BorderLayout.PAGE_START);
JPanel letterPanel = new JPanel(new GridLayout(0, 5));
for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
String buttonText = String.valueOf(alphabet);
JButton letterButton = new JButton(buttonText);
letterButton.addActionListener(clickedbutton());
letterPanel.add(letterButton, BorderLayout.CENTER);
}
add(letterPanel, BorderLayout.CENTER);
}
private ActionListener clickedbutton() {
return new ActionListener() {
public void actionPerformed(ActionEvent e) {
String actionCommand = e.getActionCommand();
System.out.println("actionCommand is: " + actionCommand);
}
};
}
public JPanel createFormattedPanel() {
JPanel panel = new JPanel();
MaskFormatter formatter = null;
try {
JLabel label = new JLabel("Guesss");
formatter = new MaskFormatter("? ? ? ? ? ? ?");
formatter.setPlaceholderCharacter('?');
JFormattedTextField input = new JFormattedTextField(formatter);
input.setColumns(20);
// this.add(label);
// this.add(input);
panel.add(label);
panel.add(input);
} catch (java.text.ParseException exc) {
System.err.println("formatter is bad: " + exc.getMessage());
System.exit(-1);
}
return panel;
}
}
Also, don't set the position of a component or set it visible until after adding all and packing all. Don't set a component's size but rather let the preferred sizes and the layout managers set the sizes for you.
Edit
You ask:
first of all thank you for helping out. This is the solution I wanted. I have some basic questions though. why did you comment out // myframe.getContentPane().setLayout(new BorderLayout());
The JFrame's contentPane already uses BorderLayout by default so it would be unnecessary to explicitly set it to this layout.
also you created three panels, which is nice. for imagepanel, you specified the dimension. but for detailsPanel, you did not specify the dimension. does it mean?
I figure that the image will have a definite size, and so I override its getPreferredSize so that it will be big enough to show the image. All other components, I let them size themselves based on their component's preferred sizes and their layout managers.
if I have many panels and I specify dimension(size) for one panel, all others will get that default on the frame.
Again, all others will have their own preferred sizes based on the preferred sizes of their components and their layout managers.
"IF" I understand correctly, why not just add the buttons to their own panel and set the title border on it instead, for example...
public DetailsPanel() {
setPreferredSize(new Dimension(400, 600));
createFormattedPanel();
JPanel buttons = new JPanel();
buttons.setBorder(BorderFactory.createTitledBorder(" ciick here "));
for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
String buttonText = String.valueOf(alphabet);
JButton letterButton = new JButton(buttonText);
letterButton.addActionListener(clickedbutton());
buttons.add(letterButton, BorderLayout.CENTER);
}
add(buttons);
}
You count create a GridLayout for your buttons like so:
public DetailsPanel() {
setPreferredSize(new Dimension(400, 600));
createFormattedPanel();
JPanel buttons = new JPanel();
buttons.setBorder(BorderFactory.createTitledBorder(" ciick here "));
buttons.setLayout(new GridLayout(5,6));
for (char alphabet = 'A'; alphabet <= 'Z'; alphabet++) {
String buttonText = String.valueOf(alphabet);
JButton letterButton = new JButton(buttonText);
letterButton.addActionListener(clickedbutton());
buttons.add(letterButton);
}
add(buttons);
}
Then I also added an extra dummy Panel in your main with just a label, change this label to what ever component you want:
myPanel = new DetailsPanel();
JFrame myframe = new JFrame();
JPanel aDummy = new JPanel();
aDummy.add(new JLabel("Extra text"));
myframe.getContentPane().setLayout(new BorderLayout());
myframe.getContentPane().add(aDummy, BorderLayout.CENTER);
myframe.getContentPane().add(myPanel, BorderLayout.SOUTH);
//...etc
Comes out like this
I have JPanel with a border, the problem is that when I add the panel on the JFrame it takes the panel size although I set the preferred size for the panel using setPreferredSize. The layout of the frame is 'BoxLayout' and here's the code:
public class ActionForm extends JFrame {
JPanel namePanel;
JPanel descPanel;
JLabel actionName;
JLabel nameLabel;
JTextField nameTextField, descTextField;
FlowLayout toolBarLayout = new FlowLayout();
public ActionForm() {
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS));
TitledBorder nameBorder= BorderFactory.createTitledBorder(
"Change Description");
nameBorder.setTitleJustification(TitledBorder.LEFT);
namePanel = new JPanel(toolBarLayout);
namePanel.setPreferredSize(new Dimension(150, 150));
nameLabel = new JLabel("ButtonName");
nameTextField = new JTextField("Action's Name", 50);
namePanel.add(nameLabel);
namePanel.add(nameTextField);
namePanel.setBorder(nameBorder);
namePanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
this.add(namePanel);
}
public static void main(String[] args) {
ActionForm form = new ActionForm();
form.setVisible(true);
form.setSize(970, 500);
form.setResizable(false);
}
}
Why the size of the panel doesn't change?
BoxLayout accepting Min/Max/preferredSize that came from JComponents layed by this LayoutManager
(I'm don't want to comment something, because my answer will be so long) please to compare your code with this code example, there are implemented all good (required and important) Swing rulles
for example
import java.awt.ComponentOrientation;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
public class ActionForm {
private static final long serialVersionUID = 1L;
private JFrame frame;
private JPanel namePanel;
private JLabel nameLabel;
private JTextField nameTextField;
private FlowLayout toolBarLayout = new FlowLayout();
public ActionForm() {
TitledBorder nameBorder = BorderFactory.createTitledBorder(
"Change Description");
nameBorder.setTitleJustification(TitledBorder.LEFT);
namePanel = new JPanel(toolBarLayout);
namePanel.setPreferredSize(new Dimension(150, 150));// hardCoded sizing
namePanel.setMaximumSize(new Dimension(250, 150)); // hardCoded sizing
namePanel.setMinimumSize(new Dimension(150, 150)); // hardCoded sizing
nameLabel = new JLabel("ButtonName");
nameTextField = new JTextField("Action's Name", 10);
namePanel.add(nameLabel);
namePanel.add(nameTextField);
namePanel.setBorder(nameBorder);
namePanel.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
frame = new JFrame("Mix / Max / PreferredSize for BoxLayout");
frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),
BoxLayout.Y_AXIS)); // otherwise nice exceptions java.awt.AWTError:
// BoxLayout can't be shared
frame.add(namePanel);
frame.setPreferredSize(new Dimension(970, 500));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ActionForm form = new ActionForm();
}
});
}
}
I'm trying to figure out how to create a vertical TitledBorder in a JPanel.
I've got this situation:
I'd like to have "Actuators st..." placed vertically, so user can read it.
Is there a way to do it, or should I implement my own customized JPanel & TitledBorder?
maybe crazy idea but is possible with JSeparator too :-)
required proper LayoutManager, maybe GridBagLayout (JComponent placed without GBC can take PreferrredSize from JComponent, but isn't resiziable), not GridLayout
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
public class NestedLayout {
private JFrame frame = new JFrame();
private JPanel leftPanel = new JPanel();
private JSeparator sep = new JSeparator();
private JLabel label = new JLabel("<html> L<br>a<br>b<br>e<br>l<br></html>");
public NestedLayout() {
label.setOpaque(true);
sep.setOrientation(JSeparator.VERTICAL);
sep.setLayout(new GridLayout(3, 1));
sep.add(new JLabel());
sep.add(label);
sep.add(new JLabel());
leftPanel.setLayout(new BorderLayout());
leftPanel.setBorder(BorderFactory.createEmptyBorder(
10, //top
10, //left
10, //bottom
10)); //right
leftPanel.add(sep, BorderLayout.CENTER);
leftPanel.setPreferredSize(new Dimension(40, 220));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(leftPanel, BorderLayout.WEST);
//frame.add(label);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
NestedLayout nestedLayout = new NestedLayout();
}
});
}
}
As shown in How to Use Borders, you can create a compound border using an empty border and a titled border.
Addendum: As an alternative, you can use the border's getMinimumSize() method to ensure that the title is visible. See also this related Q&A.
f.add(createPanel("Actuator status"), BorderLayout.WEST);
f.add(createPanel("Indicator result"), BorderLayout.EAST);
...
private Box createPanel(String s) {
Box box = new Box(BoxLayout.Y_AXIS);
TitledBorder title = BorderFactory.createTitledBorder(null, s,
TitledBorder.CENTER, TitledBorder.DEFAULT_POSITION);
box.setBorder(title);
for (int i = 0; i < 6; i++) {
JButton b = new JButton(null, UIManager.getIcon("html.pendingImage"));
b.setAlignmentX(JButton.CENTER_ALIGNMENT);
box.add(b);
}
box.validate();
Dimension db = box.getPreferredSize();
int max = Math.max(title.getMinimumSize(box).width, db.width);
box.setPreferredSize(new Dimension(max, db.height));
return box;
}