Here is my program.This program simply creates a frame using swings in java and create a grid first and adds button to that frame:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class one {
private static void createAndShowGUI() {
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400,400);
frame.getContentPane().setPreferredSize(new Dimension(500,500));
frame.pack();
frame.setVisible(true);
Container pane=frame.getContentPane();
pane.setLayout(new GridLayout(5,6));
JButton[] buttons = new JButton[26];
String b[]={"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
for(int i = 0; i<buttons.length; i++) {
buttons[i] = new JButton(b[i]);
buttons[i].setSize(80, 80);
buttons[i].setActionCommand(b[i]);
buttons[i].addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
String choice = e.getActionCommand();
JOptionPane.showMessageDialog(null, "You have clicked: "+choice);
}
});
System.out.println("adding button\n");
pane.add(buttons[i]);
}
}
public static void main(final String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
The program compiles fine.But the button creation i can see only one button that is "A" and rest of the buttons i am not able to see in the pane.
It turns out that this seems to be a race condition and/or system dependent type issue, since it works for others. In any case, the Javadoc for java.awt.Container.add() states:
This method changes layout-related information, and therefore,
invalidates the component hierarchy. If the container has already been
displayed, the hierarchy must be validated thereafter in order to
display the added component.
You should therefore call pane.validate() after you have added all components (or, as MadProgrammer says, execute the setVisible() call after you have added all your components).
There are, essentially two ways to fix this problem.
The first, is call frame.setVisible(true) AFTER you have completed adding the buttons to the pane.
The second is to call
pane.invalidate();
pane.repaint();
After you have added all the buttons to the pane
I can see buttons(A-Z). I could not reproduce your problem.
Related
I am a fairly new user with programming in Java with about a week and a bit experience, as of before I have been using python for about 3 years but thought to give java a try.
I have been trying to develop my skills by creating small projects and applications and am now creating a small GUI counter.
I have achieved creating the GUI with 2 buttons and a label and have tested the maths behind the application but I am struggling to work out how the ActionListener works as it feels a lot different to python when making a button have a action.
This is My Code;
package gui;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
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;
import javax.swing.JTextField;
import javax.swing.*;
public class GUI{
//This creates a frame or panel to contain things
public static void main(String[] args) {
//Maths To The Counter
int Counter = 0;
System.out.println(Counter);
Counter =+ 1;
System.out.println(Counter);
//Creating The Frame
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.WHITE);
frame.getContentPane().add(panel);
//Creating The Label
JLabel label3 = new JLabel("Counter: ");
panel.add(label3);
//Button Which should have a funtion to add and display the number
JButton button = new JButton("Click Here.");
panel.add(button);
//Button to reset the counter
JButton buttonReset = new JButton("Reset Counter.");
panel.add(buttonReset);
//Set Size Of Window
frame.setSize(new Dimension(500, 400));
//Set Starting Position to centre
frame.setLocationRelativeTo(null);
//Setting a default close action
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Set Title
frame.setTitle("Counter");
//Disable Resize
frame.setResizable(false);
//Setting if its visible
frame.setVisible(true);
//Fits frame to fit everything
frame.pack();
}
}
enter code here
I know that in python a action is in a function so that has been my logic to this problem however I have seen that I need to use the actionlistener instead and I am struggling to get my head around it.
If Someone could show me how this type of action should be implemented it would be great help, I have watch some youtube videos and done a bit of research but im still struggling to understand in my situation how to do it.
For any confussion im sorry, overall my question is how do I add a action to a button in my program that can implement my maths at the start.
As well any feedback on the structure of my code would be welcomed as I am just starting in java and I do know poor structure can lead to mistakes.
This code should work:
Basically, in the main method I am creating an instance of the class and calling a method to create the gui.
I also created an instance variable as the counter, otherwise you won't be able to update the variable in your action listener.
public class Gui {
private int counter;
// This creates a frame or panel to contain things
public static void main(String[] args) {
Gui gui = new Gui();
gui.create();
}
private void create() {
// Creating The Frame
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.WHITE);
frame.getContentPane().add(panel);
// Creating The Label
JLabel label3 = new JLabel("Counter: ");
panel.add(label3);
// Button Which should have a funtion to add and display the number
JButton button = new JButton("Click Here.");
panel.add(button);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(counter++);
}
});
// Button to reset the counter
JButton buttonReset = new JButton("Reset Counter.");
panel.add(buttonReset);
buttonReset.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
counter = 0;
}
});
// Set Size Of Window
frame.setSize(new Dimension(500, 400));
// Set Starting Position to centre
frame.setLocationRelativeTo(null);
// Setting a default close action
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Set Title
frame.setTitle("Counter");
// Disable Resize
frame.setResizable(false);
// Setting if its visible
frame.setVisible(true);
// Fits frame to fit everything
}
}
With Lambda expressions, you can simplify your action listeners as follows:
button.addActionListener(a -> System.out.println(counter++));
buttonReset.addActionListener(a -> counter = 0);
If you want to write more than 1 statement, then you can just put your code in curly brackets:
button.addActionListener(a -> {
System.out.println(counter++);
System.out.println("doing more stuff...");
});
JButton has a function called addActionListener. You can pass on an action listener by doing this:
button.addActionListener(() -> {
// Do some logic here
});
Here, I use a lambda expression as an action listener. Within the lambda expression you can place whatever logic you want to have.
Also note that you can add multiple different action listeners to the same button. In a nutshell, the way the JButton interacts with the ActionListeners is based on the observer-pattern.
Imagine this: When the JButton is pressed, it will notify all of it's observers saying "Hey, I have been pressed". Each observer can then independently decide what to do. In case of the JButton, all observers are ActionListeners. If you add multiple ActionListeners then the JButton will notify all of them, and as a result all of their actionPerformed(ActionEvent e) functions are executed. In the example above, I used a lambda expression which then by java is interpreted as an ActionListener.
Other ways to achieve the exact same functionality are:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Do some logic here
}
});
In the example above, you use an anonymous class as an actionlistener.
public class MyClass {
public MyClass() {
JButton button = new JButton("press me");
button.addActionListener(new MyActionListener());
}
private class MyActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// Do some logic here
}
}
}
In the example above, an inner class is used.
In a nutshell, there is a ton of ways you can make your button have functionality. Above are just a few examples of how to do so.
Does this clarify it a bit more, or do you have some remaining questions?
I'm just new to Java GUI Programming and I'm having a problem that the components inside my panel is missing when I place the setVisible()function at the beginning of the function called by the constructor but it works fine when it is at the end. See code below:
public static void main(String[] args)
{
new MainClass();
}
public MainClass()
{
setFrame();
}
private void setFrame()
{
JFrame frame = new JFrame();
frame.setSize(400,400);
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Some area where the object of my components inside the panel is created and initialized.
// If I just place a label and a button, it will appear on the panel. However if I add the JTextArea, all the components in my panel is gone. Just like the code below.
textArea1 = new JTextArea(20,34);
textArea1.setWrapStyleWord(true);
textArea1.setLineWrap(true);
JScrollPane scroll =
new JScrollPane(textArea1,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scroll);
frame.add(panel);
// Works fine when setVisible(true); it placed here.
}
What could the problem possibly be with regard to placing the setVisible() function to the beginning or to the end of the method.
As already pointed out in the comments and the other answer:
You should call setVisible(true) at the end, after all components have been added.
This does not directly answer your question. The answer to your question is: Yes, it makes a difference. If you call setVisible before all compoents have been added, it may work, in some cases, with some programs, on some PCs, with some Java versions, with some operating systems - but you always have to expect that it may not work as expected in some cases.
You will find dozens of related questions here on stackoverflow and elsewhere. The usual symptoms of these problems are that some components are not displayed properly, and then suddenly appear when the window is resized. (Resizing a window basically triggers a layout and a repaint).
The likeliness of unexpected behavior is increased when you violate the threading rules of Swing. And, in some sense, you did violate the threading rules of Swing: You should always create the GUI on the Event Dispatch Thread!
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class SomeSwingGUI
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
// This method may (and will) only be called
// on the Event Dispatch Thread
private static void createAndShowGUI()
{
JFrame f = new JFrame();
// Add your components here
f.setVisible(true); // Do this last
}
}
And by the way: Timothy Truckle pointed out in a comment that you should not invoke setVisible from the constructor. This is true. More importantly: You should usually not directly create a class that extends JFrame. (In some (rare!) cases, this is appropriate, but the general guideline should be to not extend JFrame)
The components cannot be shown, because you add them after you call the setVisible() method of the Frame.
The Componet's add() method changes layout-related information, and invalidates the component hierarchy. If the container has already been displayed, the hierarchy must be validated thereafter in order to display the added component, as pointed here
.
So in order to show the items, you should either call the revalidate() method of the frame or call setVisible() after all your components are added.
Unless there is no special need, you should call setVisible() after you have added every other component.
public class TestMain extends JFrame {
public static void main(String[] args) {
JFrame test = new TestMain();
//if the setVisible() is called too early, you have to revalidate
test.revalidate();
}
public TestMain() {
setFrame();
}
private void setFrame() {
setSize(400,400);
setResizable(false);
setLayout(new FlowLayout());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel(new FlowLayout());
setVisible(true);
JTextArea textArea1 = new JTextArea(25,15);
textArea1.setWrapStyleWord(true);
textArea1.setLineWrap(true);
panel.add(textArea1);
JScrollPane scroll =
new JScrollPane(panel,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// this method invalidates the component hierarchy.
getContentPane().add(scroll);
}
}
I have a frame, where i load a panel into. It works fine, but nothing has focus when it loads. Pressing tab doesn't help. I have to use the mouse to press a textfield.
I've tried: jtextfield1.requestFocus(); and jtextfiel1.requestFocusInWindow(); But it doesn't work.
What am I doing wrong?
The constructor in the JPanel:
public OpretOpdater(BrugerHandler brugerHandler, ReklamationHandler reklamationsHandler) {
initComponents();
jTextFieldOrdnr.requestFocusInWindow();
this.brugerHandler = brugerHandler;
this.rekH = reklamationsHandler;
startUp();
}
Putting the panel in the frame in the GUI:
public static void opret(ReklamationHandler reklamationHandler) {
rHandler = reklamationHandler;
SwingUtilities.invokeLater(opret);
}
static Runnable opret = new Runnable() {
#Override
public void run() {
JFrame f = jframe;
f.getContentPane().removeAll();
JPanel opret = new OpretOpdater(bHandler, rHandler);
f.getContentPane().add(opret);
f.pack();
f.setLocationRelativeTo(null);
}
};
You should call requestFocusInWindow() only when components are visible/shown on a container or after pack() has been called and all components are added to the container or else it wont work.
Also please be sure to create Swing components on Event Dispatch Thread. If you haven't already have read on Concurrency in Swing.
The reason I mention the above is not creating and manipulating Swing components on the EDT can cause random artifacts in the code. i.e focus is not being given etc.
This code below was created to show how calling requestFocusInWindow before a component is visible will not work but calling it after its visible works as expected.
Also note that removing the SwingUtilities block will cause the requestFocusInWindow not to work as expected (i.e we might be given focus or not depending on our luck :P):
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JTextField f1 = new JTextField(10);
JTextField f2 = new JTextField(10);
//f2.requestFocusInWindow(); //wont work (if uncomment this remember to comment the one after setVisible or you wont see the reults)
JButton b = new JButton("Button");
JPanel p = new JPanel();
p.add(f1);//by default first added component will have focus
p.add(f2);
p.add(b);
frame.add(p);
//f2.requestFocusInWindow();//wont work
frame.pack();//Realize the components.
//f2.requestFocusInWindow();//will work
frame.setVisible(true);
f2.requestFocusInWindow();//will work
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {//if we remove this block it wont work also (no matter when we call requestFocusInWindow)
#Override
public void run() {
new Test();
}
});
}
}
I would suggest a read on How to Use the Focus Subsystem.
Often it is nice to indicate which field you want to have focus when you create the field and not separate the code by adding the request focus when the frame becomes visible.
Take a look at Dialog Focus which has a solution that is also applicable in this case. Using this approach your code would look like:
JTextField f2 = new JTextField(10);
f2.addAncestorListener( new RequestFocusListener() );
I am developing a tool for my laptop. I want to disable minimize button in the JFrame. I have already disabled maximize and close button.
Here is the code to disable maximize and close button:
JFrame frame = new JFrame();
frame.setResizable(false); //Disable the Resize Button
// Disable the Close button
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
Please, tell me how to disable minimize button.
Generally, you can't, what you can do is use a JDialog instead of JFrame
As #MadProgrammer said (+1 to him), this is definitely not a good idea you'd rather want to
use a JDialog and call setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); to make sure it cannot be closed.
You could also use a JWindow (+1 to #M. M.) or call setUndecorated(true); on your JFrame instance.
Alternatively you may want to add your own WindowAdapater to make the JFrame un-minimizable etc by overriding windowIconified(..) and calling setState(JFrame.NORMAL); from within the method:
//necessary imports
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Test {
/**
* Default constructor for Test.class
*/
public Test() {
initComponents();
}
public static void main(String[] args) {
/**
* Create GUI and components on Event-Dispatch-Thread
*/
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Test test = new Test();
}
});
}
private final JFrame frame = new JFrame();
/**
* Initialize GUI and components (including ActionListeners etc)
*/
private void initComponents() {
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setResizable(false);
frame.addWindowListener(getWindowAdapter());
//pack frame (size JFrame to match preferred sizes of added components and set visible
frame.pack();
frame.setVisible(true);
}
private WindowAdapter getWindowAdapter() {
return new WindowAdapter() {
#Override
public void windowClosing(WindowEvent we) {//overrode to show message
super.windowClosing(we);
JOptionPane.showMessageDialog(frame, "Cant Exit");
}
#Override
public void windowIconified(WindowEvent we) {
frame.setState(JFrame.NORMAL);
JOptionPane.showMessageDialog(frame, "Cant Minimize");
}
};
}
}
If you don't want to allow any user action use JWindow.
You may try to change your JFrame type to UTILITY. Then you will not see both minimize btn and maximize btn in your program.
I would recommend you to use jframe.setUndecorated(true) as you are not using any of the window events and do not want the application to be resized. Use the MotionPanel that I've made, if you would like to move the panel.
I am trying to make a box in Swing that has a label of "user", a text field for the username, and a button "sign in". This is my code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.*;
public class Engine
{
JFrame frame;
public void go()
{
setUpGui();
userNameScreen();
}
public void setUpGui()
{
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void userNameScreen()
{
JPanel background = new JPanel();
frame.getContentPane().add(background);
JLabel labelUserName = new JLabel("User:");
background.add(labelUserName);
System.out.println(labelUserName.getHeight()); // 0
JTextField textFieldUserName = new JTextField();
System.out.println(labelUserName.getHeight()); // 16
textFieldUserName.setPreferredSize(new Dimension(110,labelUserName.getHeight()));
background.add(textFieldUserName);
JButton buttonSignIn = new JButton("Sign In");
background.add(buttonSignIn);
/*
background.add(labelUserName);
background.add(textFieldUserName);
background.add(buttonSignIn);
frame.getContentPane().add(background);
*/
frame.pack();
}
}
My driver class just creates an instance of engine, then runs the method go().
I read that Swing components do not have attributes of height/width until they are added (because that is for the layout manager to decide how much room they have), so it makes sense that in the method userNameScreen(), adding in all components at the end* (commented out here) makes the textFieldUserName variable have no height.
However, you can see in that same method userNameScreen(), I have it do
System.out.println(labelUserName.getHeight());
twice. The first time, it is 0. The second, it is 16. I don't understand why the first time, it would register it as 0. It has already been added to the panel (in the line before), and there doesn't seem to be anything that would change its height between that first println() and the next. So why is the value 0 in the first one, and why does it change to 16 almost immediately after?
*I should note, when I say adding in all the stuff commented out at the end, it also includes removing/commenting out all the same commands done elsewhere in the code.
It is a side effect from not creating/modifying your Swing components on the EDT. Now the EDT is busy doing the layout while you are adding components in another thread.
Your main method should look like:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Engine().go();
}
});
}
I'm not sure why this is happening but may be because the addition of the component maybe on a background thread and might not have been updated till the next statement is called and its updated a few millisecs later and appears when you call it second time.