So I'm going into GUI's in Java, and am trying to create a simple main menu for a timer. All is well until I've attempted to add a background for the GUI. Adding the background works, however all other components are now gone, (the button). How could I fix this?
EDIT: Here is my new code.
public class MainMenu {
// JFrame = the actual menu / frame.
private JFrame frame;
// JLabel = provides text instructions or information on a GUI —
// display a single line of read-only text, an image or both text and an image.
private JLabel background;
// JButton = button.
private JButton alarmClockButton;
// Constructor to create menu
public MainMenu() {
frame = new JFrame("Alarm Clock");
alarmClockButton = new JButton("Timer");
// Add an event to clicking the button.
alarmClockButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// TODO: CHANGE TO SOMETHING NICER
JOptionPane.showMessageDialog(null, "This feature hasn't been implemented yet.", "We're sorry!",
JOptionPane.ERROR_MESSAGE);
}
});
// Creating the background
try {
background = new JLabel(new ImageIcon(ImageIO.read(getClass()
.getResourceAsStream("/me/devy/alarm/clock/resources/Background.jpg"))));
} catch (IOException e) {
e.printStackTrace();
}
frame.setLayout(new FlowLayout());
frame.setContentPane(background);
frame.add(alarmClockButton);
frame.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
frame.setVisible(true);
frame.setSize(450, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
alarmClockButton.setForeground(Color.RED);
}
}
Thank you!
frame.setContentPane(background);
You use the label as the content pane. The problem is that the label doesn't use a layout manager by default.
You need to add:
background.setLayout( new BorderLayout() ); // or whatever layout you want
frame.setContentPane(background);
Now you can add the button directly to the frame. You don't need the panel.
Or if you want to get fancy you can use the Background Panel which gives you the option to scale or tile the background image.
Instead of making the ContentPane as JLabel, you can wrap the JLabel in a JPanel, then add this JPanel as the ContentPane :
public class MainMenu {
public static void main(String[] args) {
new MainMenu();
}
// JFrame = the actual menu / frame.
private JFrame frame;
private JPanel panel;
private JPanel bkgPanel;
// JLabel = provides text instructions or information on a GUI —
// display a single line of read-only text, an image or both text and an
// image.
private JLabel background;
// JButton = button.
private JButton alarmClockButton;
// Constructor to create menu
public MainMenu() {
frame = new JFrame("Alarm Clock");
panel = new JPanel();
bkgPanel = new JPanel();
alarmClockButton = new JButton("Timer");
// Add an event to clicking the button.
alarmClockButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// TODO: CHANGE TO SOMETHING NICER
JOptionPane.showMessageDialog(null, "This feature hasn't been implemented yet.", "We're sorry!",
JOptionPane.ERROR_MESSAGE);
}
});
// Creating the background
try {
background = new JLabel(new ImageIcon(
ImageIO.read(getClass().getResourceAsStream("/me/devy/alarm/clock/resources/Background.jpg"))));
bkgPanel.add(background);
} catch (IOException e) {
e.printStackTrace();
}
frame.setContentPane(bkgPanel);
frame.add(panel);
panel.add(alarmClockButton);
frame.setVisible(true);
frame.setSize(450, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
alarmClockButton.setForeground(Color.RED);
}
}
Related
Im creating a programme using java. I want the user to enter some text, then push the button so the text entered shows in the label. However, I have 2 problems. First, the text are isn´t displaying when I execute the app. Second, I don´t know how to allow the user to type in the area. Im new in java so that´s why Im asking. Here is the code. Thank you.
import javax.swing.*;
import java.awt.event.*;
class Boton extends JFrame implements ActionListener {
JButton boton;
JTextArea textArea = new JTextArea();
JLabel etiqueta = new JLabel();
public Boton() {
setLayout(null);
boton = new JButton("Escribir");
boton.setBounds(100, 150, 100, 30);
boton.addActionListener(this);
add(boton);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == boton) {
try {
String texto = textArea.getText();
etiqueta.setText(texto);
Thread.sleep(3000);
System.exit(0);
} catch (Exception excep) {
System.exit(0);
}
}
}
}
public class Main{
public static void main(String[] ar) {
Boton boton1 =new Boton();
boton1.setBounds(0,0,450,350);
boton1.setVisible(true);
boton1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Problems:
You never add the JTextArea into your GUI, and if it doesn't show, a user cannot directly interact with it.
You are calling Thread.sleep on the Swing event thread, and this will put the entire application to sleep, meaning the text that you added will not show.
Other issues include use of null layouts and setBounds -- avoid doing this.
Solutions:
Set the JTextArea's column and row properties so that it sizes well.
Since your JTextArea's text is going into a JLabel, a component that only allows a single line of text, I wonder if you should be using a JTextArea at all. Perhaps a JTextField would work better since it allows user input but only one line of text.
Add the JTextArea to a JScrollPane (its viewport actually) and add that to your GUI. Then the user can interact directly with it. This is most easily done by passing the JTextArea into a JScrollPane's constructor.
Get rid of the Thread.sleep and instead, if you want to use a delay, use a Swing Timer. check out the tutorial here
For example:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Main2 {
public static void main(String[] args) {
// create GUI in a thread-safe manner
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
BotonExample mainPanel = new BotonExample();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
class BotonExample extends JPanel {
private JLabel etiqueta = new JLabel(" ");
private JButton boton = new JButton("Escribir");
// jtext area rows and column properties
private int rows = 5;
private int columns = 30;
private JTextArea textArea = new JTextArea(rows, columns);
public BotonExample() {
// alt-e will activate button
boton.setMnemonic(KeyEvent.VK_E);
boton.addActionListener(e -> {
boton.setEnabled(false); // prevent button from re-activating
String text = textArea.getText();
etiqueta.setText(text);
// delay for timer
int delay = 3000;
Timer timer = new Timer(delay, e2 -> {
// get current window and dispose ofit
Window window = SwingUtilities.getWindowAncestor(boton);
window.dispose();
});
timer.setRepeats(false);
timer.start(); // start timer
});
// create JPanels to add to GUI
JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
topPanel.add(new JLabel("Etiqueta:"));
topPanel.add(etiqueta);
JPanel bottomPanel = new JPanel();
bottomPanel.add(boton);
JScrollPane scrollPane = new JScrollPane(textArea);
// use layout manager and add components
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(scrollPane, BorderLayout.CENTER);
add(bottomPanel, BorderLayout.PAGE_END);
}
}
textarea.setText("Text"); // this will insert text into the text area
textarea.setVisable(true); // this will display the text area so you can type in it
textarea.setSize(500,500); // set size of the textarea so it actually shows
The user should be able to type in the TA when it is displayed and just do a getText to pull the text
I am creating a log in application for someones graduation, I need several text fields and a background, I have added the background and now need to add the text fields, the problem is that they won't seem to go on top of each other.
I have tried them each separately and without one another they both work perfectly but i can't get them to stack, I have seen several answers on this site to deal with a similar problem but for this application I need to put several text fields on the background as apposed to just one, here is what I have thus far...
//creates the frame with a title as a parameter
JFrame frame = new JFrame("Sign In Sheet");
//sets the size
frame.setSize(1000, 556);
//makes it so the application stops running when you close it
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//puts it in the center of the screen
frame.setLocationRelativeTo(null);
//makes it so you can't resize it
frame.setResizable(false);
//setting the background by looking for the image
try{
frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:/Users/Gabriel R. Warner/Desktop/clouds.png")))));
}catch(IOException e){
//and prints an error message if it's not found
System.out.println("well it didn't work");
}
//adding text fields with names apropriate to function
JTextField name1 = new JTextField();
name1.setPreferredSize(new Dimension(200, 15));
name1.setBackground(Color.WHITE);
frame.add(name1);
//makes frame visible
frame.setVisible(true);
Simply stated the text field won't show up with the background and all the results only offer answers for a single text field
The problem is in this line: frame.setContentPane(new JLabel(new ImageIcon(ImageIO.read(new File("C:/Users/Gabriel R. Warner/Desktop/clouds.png")))));
In this line you set a JLabel as the content pane of your JFrame. Then, you frame.add(name1); So you are adding a JTextField to a JLabel...Well this does not seem right, right?
The answer would be to create a new JPanel, add the background image to this panel, set the panel as the content pane of the frame and finally add the textfield to the panel/contentpane.
An example:
#SuppressWarnings("serial")
public class FrameWithBackgroundImage extends JFrame {
public FrameWithBackgroundImage() {
super("Sign In Sheet");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
try {
Image bgImage = loadBackgroundImage();
JPanel backgroundImagePanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(bgImage, 0, 0, null);
}
};
setContentPane(backgroundImagePanel);
} catch (IOException e) {
e.printStackTrace();
}
JTextField textField = new JTextField(10);
add(textField);
}
private Image loadBackgroundImage() throws IOException {
File desktop = new File(System.getProperty("user.home"), "Desktop");
File image = new File(desktop, "img.jpg");
return ImageIO.read(image);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new FrameWithBackgroundImage().setVisible(true);
});
}
}
Preview:
Worth to read question: Simplest way to set image as JPanel background
I'm trying to make a little game that will first show the player a simple login screen where they can enter their name (I will need it later to store their game state info), let them pick a difficulty level etc, and will only show the main game screen once the player has clicked the play button. I'd also like to allow the player to navigate to a (hopefully for them rather large) trophy collection, likewise in what will appear to them to be a new screen.
So far I have a main game window with a grid layout and a game in it that works (Yay for me!). Now I want to add the above functionality.
How do I go about doing this? I don't think I want to go the multiple JFrame route as I only want one icon visible in the taskbar at a time (or would setting their visibility to false effect the icon too?) Do I instead make and destroy layouts or panels or something like that?
What are my options? How can I control what content is being displayed? Especially given my newbie skills?
A simple modal dialog such as a JDialog should work well here. The main GUI which will likely be a JFrame can be invisible when the dialog is called, and then set to visible (assuming that the log-on was successful) once the dialog completes. If the dialog is modal, you'll know exactly when the user has closed the dialog as the code will continue right after the line where you call setVisible(true) on the dialog. Note that the GUI held by a JDialog can be every bit as complex and rich as that held by a JFrame.
Another option is to use one GUI/JFrame but swap views (JPanels) in the main GUI via a CardLayout. This could work quite well and is easy to implement. Check out the CardLayout tutorial for more.
Oh, and welcome to stackoverflow.com!
Here is an example of a Login Dialog as #HovercraftFullOfEels suggested.
Username: stackoverflow Password: stackoverflow
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
public class TestFrame extends JFrame {
private PassWordDialog passDialog;
public TestFrame() {
passDialog = new PassWordDialog(this, true);
passDialog.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new TestFrame();
frame.getContentPane().setBackground(Color.BLACK);
frame.setTitle("Logged In");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
}
});
}
}
class PassWordDialog extends JDialog {
private final JLabel jlblUsername = new JLabel("Username");
private final JLabel jlblPassword = new JLabel("Password");
private final JTextField jtfUsername = new JTextField(15);
private final JPasswordField jpfPassword = new JPasswordField();
private final JButton jbtOk = new JButton("Login");
private final JButton jbtCancel = new JButton("Cancel");
private final JLabel jlblStatus = new JLabel(" ");
public PassWordDialog() {
this(null, true);
}
public PassWordDialog(final JFrame parent, boolean modal) {
super(parent, modal);
JPanel p3 = new JPanel(new GridLayout(2, 1));
p3.add(jlblUsername);
p3.add(jlblPassword);
JPanel p4 = new JPanel(new GridLayout(2, 1));
p4.add(jtfUsername);
p4.add(jpfPassword);
JPanel p1 = new JPanel();
p1.add(p3);
p1.add(p4);
JPanel p2 = new JPanel();
p2.add(jbtOk);
p2.add(jbtCancel);
JPanel p5 = new JPanel(new BorderLayout());
p5.add(p2, BorderLayout.CENTER);
p5.add(jlblStatus, BorderLayout.NORTH);
jlblStatus.setForeground(Color.RED);
jlblStatus.setHorizontalAlignment(SwingConstants.CENTER);
setLayout(new BorderLayout());
add(p1, BorderLayout.CENTER);
add(p5, BorderLayout.SOUTH);
pack();
setLocationRelativeTo(null);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
jbtOk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (Arrays.equals("stackoverflow".toCharArray(), jpfPassword.getPassword())
&& "stackoverflow".equals(jtfUsername.getText())) {
parent.setVisible(true);
setVisible(false);
} else {
jlblStatus.setText("Invalid username or password");
}
}
});
jbtCancel.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
parent.dispose();
System.exit(0);
}
});
}
}
I suggest you insert the following code:
JFrame f = new JFrame();
JTextField text = new JTextField(15); //the 15 sets the size of the text field
JPanel p = new JPanel();
JButton b = new JButton("Login");
f.add(p); //so you can add more stuff to the JFrame
f.setSize(250,150);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Insert that when you want to add the stuff in. Next we will add all the stuff to the JPanel:
p.add(text);
p.add(b);
Now we add the ActionListeners to make the JButtons to work:
b.addActionListener(this);
public void actionPerforemed(ActionEvent e)
{
//Get the text of the JTextField
String TEXT = text.getText();
}
Don't forget to import the following if you haven't already:
import java.awt.event*;
import java.awt.*; //Just in case we need it
import java.x.swing.*;
I hope everything i said makes sense, because sometimes i don't (especially when I'm talking coding/Java) All the importing (if you didn't know) goes at the top of your code.
Instead of adding the game directly to JFrame, you can add your content to JPanel (let's call it GamePanel) and add this panel to the frame. Do the same thing for login screen: add all content to JPanel (LoginPanel) and add it to frame. When your game will start, you should do the following:
Add LoginPanel to frame
Get user input and load it's details
Add GamePanel and destroy LoginPanel (since it will be quite fast to re-create new one, so you don't need to keep it memory).
I am trying to draw a simple GUI (created with windowbuilder in eclipse), I want to have 2 buttons and a scrollable text area between them. I have created the following code to achieve the above:
public class Main extends JFrame implements ActionListener{
public Font font; //used for the font file
public JTextArea txtDataWillBe;
public Main() throws FontFormatException, IOException{
setTitle("Main title ");
setBounds(100, 100, 1200, 600);
getContentPane().setLayout(null);
txtDataWillBe = new JTextArea();
txtDataWillBe.setText("Your data will display here");
txtDataWillBe.setFont(new Font("Droid Sans", Font.BOLD, 18));
txtDataWillBe.setEditable(false);
txtDataWillBe.setColumns(1);
txtDataWillBe.setBounds(0, 40, 919, 484);
getContentPane().add(txtDataWillBe);
JButton button = new JButton("CLICK TO OPEN");
button.setBounds(0, 0, 940, 40);
button.setFont(new Font("Coalition", Font.PLAIN, 18));
getContentPane().add(button);
JButton btnPrint = new JButton("PRINT");
btnPrint.setBounds(0, 531, 940, 40);
btnPrint.setFont(new Font("Coalition", Font.PLAIN, 18));
getContentPane().add(btnPrint);
}
private final String JTextFile = null;
JFileChooser chooser;
String choosertitle;
public static File deletefile;
EDIT:
public static void main(String s[]) {
JFrame frame = new JFrame("Reader");
Main panel = null;
try {
panel = new Main();
} catch (FontFormatException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
File deleteme = new File (deletefile + "mx.txt");
deleteme.delete();
System.exit(0);
}
}
);
frame.getContentPane().add(panel,"Center");
frame.setSize(panel.getPreferredSize());
frame.setVisible(true);
}
I originally had the JTextarea inside of a JScrollPane (thinking that was the best way to get the scrolling I want working). I removed the JScrollPane thinking that was causing the console error, but I am still getting the error.
Console output is:
Exception in thread "main" java.lang.IllegalArgumentException: adding a window to a container
at java.awt.Container.checkNotAWindow(Container.java:439)
at java.awt.Container.addImpl(Container.java:1035)
at java.awt.Container.add(Container.java:923)
EDIT: Main added above.
What I am doing wrong with my GUI?
Do I need a JScrollPane and JTextArea to enable vertical scrolling of the loaded text?
Thanks for your help;
Andy
EDIT:
I have edited as per the suggestions below so my code now reads:
public Main() throws FontFormatException, IOException{
JFrame frame = new JFrame("Reader ");
frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
File deleteme = new File (deletefile + "mx.txt");
deleteme.delete();
System.exit(0);
}
}
);
frame.getContentPane().add(panel,"Center");
frame.setSize(getPreferredSize());
frame.setVisible(true);
The rest of the code is as before but all I am getting displayed is a blank grey frame without any of my components (although they are all showing in windowbuilder).
Thanks for the continued help.
The console output is describing exactly what is wrong here.
IllegalArgumentException: adding a window to a container
In the line frame.getContentPane().add(panel,"Center"); you add panel into your content pane, but panel itself is an instance of Main extends JFrame.
You should remove any reference to the outer frame at all and just add the window listener to the Main frame, i.e. the main code reduces to something like
JFrame frame = new Main();
frame.addWindowListener( ... );
frame.setVisible(true);
You may also want to move the addWindowListener part inside class Main.
i created two classes one class is just like form the other class is main class and having jmenu and jinternal frames i want to print the input from the form class on the jinternal frame but i cannot understand how i recall the jinternalframe in the form classes, please guide me in this regard or any hint or some piece of code or tutorial that can help me here is code of both the classes. Moreover both classes are working fine .
JTextArea text;
static int openFrameCount = 0;
public form(){
super("Insert Form");
Container panel=getContentPane();
JPanel cc = new JPanel();
cc.setLayout(new FlowLayout());
JButton b=new JButton("print");
b.setPreferredSize(new Dimension(140,50));
b.setBounds(1000,500,350,50);
cc.add(b);
.......................................................
JLabel label1=new JLabel(" Question"+(++openFrameCount));
cc.add(label1);
text=new JTextArea();
text.setLineWrap(true);
text.setWrapStyleWord(true);
text.setPreferredSize(new Dimension(750,50));
text.setBounds(80, 60,750,50);
cc.add(text);
JLabel symbol=new JLabel("Selection for Option?");
symbol.setBounds(200, 120,1000,100);
cc.add(symbol);
..................................................
JLabel op4=new JLabel("4th Option?");
JTextArea otext4=new JTextArea();
otext4.setLineWrap(true);
otext4.setWrapStyleWord(true);
otext4.setPreferredSize(new Dimension(750,50));
otext4.setBounds(10, 40,700,30);
cc.add( op4 ) ;
cc.add( otext4 ) ;
cc.revalidate();
validate();
............................................................
}
#Override
public void actionPerformed(ActionEvent ae) {
if ( e.getSource() == b1 ){
}
}
}
and the second class of jinternalframe is
public class Desktop1 extends JFrame
implements ActionListener {
Desktop p=new Desktop();
JDesktopPane desktop;
static int openFrameCount = 0;
public Desktop1() {
super("InternalFrameDemo");
//Make the big window be indented 50 pixels from each edge
//of the screen.
int inset = 50;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(inset, inset,
screenSize.width - inset*2,
screenSize.height - inset*2);
//Set up the GUI.
desktop = new JDesktopPane(); //a specialized layered pane
createFrame(); //create first "window"
setContentPane(desktop);
setJMenuBar(createMenuBar());
//Make dragging a little faster but perhaps uglier.
desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
}
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
//Set up the lone menu.
.................................................
return menuBar;
}
//React to menu selections.
public void actionPerformed(ActionEvent e) {
if ("new".equals(e.getActionCommand())) { //new
createFrame();
}
............................................
}
}
class MyInternalFrame extends JInternalFrame {
static final int xPosition = 30, yPosition = 30;
public MyInternalFrame() {
super("IFrame #" + (++openFrameCount), true, // resizable
true, // closable
true, // maximizable
true);// iconifiable
setSize(700, 700);
// Set the window's location.
setLocation(xPosition * openFrameCount, yPosition
* openFrameCount);
}
}
//Create a new internal frame.
protected void createFrame() {
Desktop1.MyInternalFrame frame = new Desktop1.MyInternalFrame();
JPanel panel=new JPanel();//to add scrollbar in jinternalpane insert jpanel
panel.setBackground(Color.white);//set background color of jinternal frame
JScrollPane scrollBar=new JScrollPane(panel,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
frame.add(scrollBar);
frame.setVisible(true);
desktop.add(frame);
try {
frame.setSelected(true);
frame.setMaximum(true);
} catch (java.beans.PropertyVetoException e) {}
}
public static void main(String[] args) {
Desktop1 d=new Desktop1();
d.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
d.setVisible(true);
}
}
i want to know hint about the work that come in this part of code to pass the value of form to internal frame when i click on print button
public void actionPerformed(ActionEvent ae) {
if ( e.getSource() == b1 ){
}
}
}
just call the constructor and pass the value
ClassName(parameter)
I guess you want to pass some text to your InternalFrame class on the button click from the main form.
Modify your createFrame() method to accept a String value
e.g-
protected void createFrame(String value){
//..your code
}
and when you call your InternalFrame class, pass this value to its constructor. e.g-
Desktop1.MyInternalFrame frame = new Desktop1.MyInternalFrame(value);
Parameterised constructor will solve your problem. Modify your InternalFrame constructor
e.g-
public MyInternalFrame(String value){
//..use this value
}