I'm fairly new to Swing, so I've been using windowbuilder to try and put together a basic GUI. The design screen works fine, but when I return to the code, it's written it in a way I'm unfamiliar with and I'm struggling to actually get it to run.
The code it generates is:
public class GUIControls extends JFrame{
public GUIControls() {
getContentPane().setLayout(new CardLayout(0, 0));
JPanel panel = new JPanel();
getContentPane().add(panel, "name_36737116256884");
panel.setLayout(null);
JButton InsertionSortButton = new JButton("Insertion Sort");
InsertionSortButton.setBounds(32, 16, 101, 56);
panel.add(InsertionSortButton);
JPanel panel_1 = new JPanel();
getContentPane().add(panel_1, "name_36737137352442");
InsertionSortButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
CardLayout cardLayout = (CardLayout) getContentPane().getLayout();
cardLayout.show(getContentPane(), "name_36737137352442");
}
});
}
(With the action taken when the button is mouseclicked being written by me, I haven't tested it because I can't run the thing)
Normally I'd do:
public void runGUI(){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createGUI();
}
});
}
With createGUI being the method I used to create a (completely horrible) GUI without windowbuilder, but I can't use GUIControls in this because it doesn't work with runnable (in fact, I'm not even sure what it is when something doesn't a return value, is it still a method?).
Does anyone know how I go about running it?
Thanks
You need to instantiate an instance of GUIControls and make it visible, for example...
public void runGUI(){
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
GUIControls guiControls = new GUIControls();
guiControls.pack();
guiControls.setLocationRelativeTo(null);
guiControls.setVisible(true);
}
});
}
ps- I know Window Builder likes to make use of null layouts, but I would avoid them wherever possible - IMHO
Related
I read about the constructer that a constructor is something that is used to set up the components of the container. So i wrote the following program which works well but only problem is that the label is not at the specified location i.e. 125,300. When I wrote the line label.setLocation(125,300) in the public run() then the code works well. Why it is not working when I write the line in the constructor? Basically it should work as the constructor is used to set up the components of the JFrame.
If not then What exactly is a constructor?
The Code:
public class RealGame extends JFrame implements Runnable, KeyListener{
JLabel label = new JLabel("I am a JLabel");
RealGame(){
setVisible(true);
requestFocus();
setContentPane(new JPanel());
getContentPane().setSize(640, 480);
setSize(640, 480);
label.setSize(50,50);
label.setOpaque(true);
label.setVisible(true);
label.setFont(new Font("Arial", Font.PLAIN, 18));
getContentPane().add(label);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new RealGame());
}
#Override
public void run() {
label.setLocation(125,300); //THIS IS IMPORTANT
JOptionPane.showMessageDialog(null, "Hello");
System.out.println("Done");
System.exit(0);
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
}
}
And also is the structure of the program correct? i.e. in many programs I saw that people use
SwingUtilities.invokeLater(new Runnable(){
public run(){
}
});
But instead I instantiated the main class. Will it give any problems in future?
but only problem is that the label is not at the specified location i.e. 125,300.
What is special about (125, 300). Don't use magic numbers in your program.
Swing uses layout managers to position components in a panel. The layout manager will determine the size and location of your component.
Read the section from the Swingtutorial on Layout Managers for more information and examples.
in many programs I saw that people use
Yes all GUI components should be updated on the Event Dispatch Thread(EDT). All the tutorial examples show you how to do this. You can also read the section in the tutorial on Concurrency in Swing for reasons why this is important.
When I wrote the line label.setLocation(125,300) in the public run() then the code works well
The code is added to the end of the EDT, which means it executes AFTER the layout manager. However this is only temporary. Try resizing the frame and the label will go back to the position determined by the layout manager. Don't try to set the location manually!
my first post here. I'm currently in school and usually spend my time here on Stackoverflow looking for answers to homework, this time i'd thought that perhaps i'll put my code here and maybe i'll get help more precis and quicker! Anyways, my problem is that i've written a code which you can see below, and I'm new to swing, studied it for a few hours only. My problem is that I'm not quite sure how to proceed with my problem, I have 2 buttons, what i want is when you click on first button the panel will change to Red, second button the panel changes to blue, so far only Red works and I don't know how to implement it so that blue works aswell.
Would greatly appreciate your help! (Don't be shy about pointing out a few errors or help along the way that doesn't have with the buttons to do, as I said, I'm new :P)
public class FirstProgram extends JFrame {
public FirstProgram() {
initUI();
}
private void initUI() {
JPanel panel = new JPanel();
panel.setBackground(Color.yellow);
getContentPane().add(panel);
panel.setLayout(null);
JButton Colorbutton = new JButton("Red");
Colorbutton.setBounds(50, 60, 80, 30);
Colorbutton.setToolTipText("Panel changes to red");
Colorbutton.setBackground(Color.green);
JButton Colorrbutton = new JButton("Blue");
Colorrbutton.setBounds(1, 30, 90, 30);
Colorrbutton.setToolTipText("Panel changes to blue");
Colorrbutton.setBackground(Color.orange);
Colorbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.red);
}
});
panel.add(Colorbutton);
panel.add(Colorrbutton);
setTitle("Time to change colors");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
FirstProgram ex = new FirstProgram();
ex.setVisible(true);
}
});
}
}
you need another ActionListener. right now you just have one and it has just one behavior. create another one and tie to the 'Blue" button
JButton RedColorbutton = new JButton("Red");
RedColorbutton .setBounds(50, 60, 80, 30);
RedColorbutton.setToolTipText("Panel changes to red");
RedColorbutton.setBackground(Color.green);
JButton BlueColorbutton = new JButton("Blue");
BlueColorrbutton.setBounds(1,30,90,30);
BlueColorrbutton.setToolTipText("Panel changes to blue");
BlueColorrbutton.setBackground(Color.orange);
RedColorbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.red);
}
});
BlueColorbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.blue);
}
});
You've set an action listener for your Colorbutton, but not for Colorrbutton
Add this next to your other ActionListener
Colorrbutton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
panel.setBackground(Color.blue);
}
});
You are missing an ActionListener for the blue JButtton.
Similar to how you added the ActionListener to your ColorButton, your ColorrButton needs to have one registered. By the way, you may wish to change the ColorButton to redButton and the ColorrButton to blueButton or something like that to make things stick out better.
example:
Colorrbutton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
panel.setBackground(Color.blue);
}
});
For the sake of reducing duplicate code, you can simplify the logic even further by having your class implement ActionListener.
public class FirstProgram extends JFrame implements ActionListener {
Then, when you are instantiating your buttons, add a listener like so:
redButton.addActionListener(this);
blueButton.addActionListener(this);
And then in your implementation of actionPerformed you could do something like:
public void actionPerformed(ActionEvent e) {
switch (e.getSource()) {
case redButton:
panel.setBackground(Color.red);
break;
case blueButton:
panel.setBackground(Color.blue);
break;
}
}
Anytime the red or blue buttons performs an action, the actionPerformed will be triggered, and then the logic to determine which button was the source will take over from there. This will add a little bit of length to your code, but as(if?) your program grows, it will reduce complexity greatly
Why are the bounds on the panelFirst not working? It just displays everything at the top and it does not display the bounds in the order I have set them? The radio buttons should display in one under the other and the next button should display on the far right but it is not working?
public MyWizard() {
panelContainer.setLayout(c1);
panelFirst.add(btNext);
panelSecond.add(btNextTwo);
panelFirst.setBackground(Color.BLUE);
panelSecond.setBackground(Color.RED);
panelThird.setBackground(Color.GREEN);
panelContainer.add(panelFirst, "1");
panelContainer.add(panelSecond,"2");
panelContainer.add(panelThird,"3");
c1.show(panelContainer, "1");
btNext.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
c1.show(panelContainer,"2");
}
});
btNextTwo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
c1.show(panelContainer,"3");
}
});
RadioButtons();
Button();
frame.add(panelContainer);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setSize(600,360);
frame.setVisible(true);
}
public void RadioButtons() {
btLdap = new JRadioButton ("Ldap");
btLdap.setBounds(60,85,100,20);
panelFirst.add(btLdap);
btKerbegos = new JRadioButton ("Kerbegos");
btKerbegos.setBounds(60,115,100,20);
panelFirst.add(btKerbegos);
btSpnego =new JRadioButton("Spnego");
btSpnego.setBounds(60,145,100,20);
panelFirst.add(btSpnego);
btSaml2 = new JRadioButton("Saml2");
btSaml2.setBounds(60,175,100,20);
panelFirst.add(btSaml2);
}
public void Button() {
btNext.setBounds(400,260,100,20);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new MyWizard();
}
});
}
}
Assuming that panelFirst is (or extends from) something like JPanel, it will be under the control of a layout manager (in this case, most likely a FlowLayout).
It is highly recommended that you avoid setBounds, setLocation and setSize and instead rely on the layout managers
Graphical Interfaces are required to run on a variety of different platforms, each with unique rendering properties. To solve this issue, the developers of Java/Swing/AWT designed the LayoutManager API. This makes it easier to develop sophisticated user interfaces that will work on multiple different platforms
Take a look at Using Layout Managers and A Visual Guide to Layout Managers
If your radio buttons should be under each other, then create a panel for them, and set the panel's layout to BoxLayout like this:
JPanel p = new JPanel();
p.setLayout(new BoxLayout(p,BoxLayout.Y_AXIS));
p.add(...);
//then add p to the fram's container or to some other container
I've just started learning Swing/JFrame, basically making a GUI.
I've been doing Java for a month now, just using the console, making a sin/true or false games and it is pretty easy for me now.
I decided to take a further step, and I must say it's totally a pain, different logic.
That's what I've done so far:
Main.java:
import java.awt.*;
import javax.swing.*;
import java.io.*;
class Main {
public static void main(String[] args) {
final Gui gui = new Gui();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
gui.createMyGui();
}
});
}
}
gui.java
class Gui {
protected JFrame j = new JFrame("My First window");
protected JPanel p = new JPanel();
protected Container c;
public Gui() {
j.setSize(500, 400);
p.setSize(j.getSize());
this.c = j.getContentPane();
}
public void createMyGui() {
setButtons();
setGuiBackground();
j.setVisible(true);
p.setVisible(true);
this.c.add(p);
}
private void setGuiBackground() {
this.c.setBackground(Color.green);
}
private void setButtons() {
p.add(new JButton("Hey"));
}
}
Problem
I can't really get the button to show up, people are telling me to use setBounds but I am not really sure on how to start as I can't even place a button there. I've tried searching about my problem, but no luck actually.
Basically what happens is a 500x400 green GUI opens, and that's it.
Why won't the button show?
people are telling me to use setBounds
Dont! Layout managers are the correct way to go.
Your problem is you add your buttons to the "p" panel, but you never add it (p panel) to the contentPane
First of all: I know this question seems to have been asked a few million times, but none of the answers given to other questions seem to work with me.
Sometimes, when I run Message.popup(String, int) in the code below, the text displays correctly, but sometimes the JDialog is empty, like if the component wasn't added at all.
public class Message extends JDialog {
private int width;
private int height;
private JLabel content;
public Message(String _content, int _margin) {
super();
this.content = new JLabel(_content);
content.setFont(new Font("Monospaced", Font.BOLD, 20));
this.margin = _margin;
this.width = content.getPreferredSize().width + _margin;
this.height = content.getPreferredSize().height + _margin;
createComponents();
setProperties();
}
public static void popup(String _content, int _time) {
if (SwingUtilities.isEventDispatchThread()) {
runPopup(_content, _time);
}
else {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
runPopup(_content, _time);
}
});
}
}
private static void runPopup(String _content, int _time) {
final Message message = new Message(_content);
new Timer(_time, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
message.dispose();
}
}).start();
}
private void createComponents() {
setLayout(new BorderLayout());
Box box = Box.createHorizontalBox();
box.add(Box.createHorizontalGlue());
box.add(content, BorderLayout.CENTER);
box.add(Box.createHorizontalGlue());
add(box);
}
private void setProperties() {
setSize(width, height);
setLocation(Coordinator.calculateCenteredWindowLocation(width, height));
setUndecorated(true);
setResizable(false);
setTitle(content.getText());
setVisible(true);
update(getGraphics());
}
}
Without the update(getGraphics());, the frame is always empty, but with it, it depends of what direction the wind is blowing... (go figure!)
As mentioned by #Riduidel, it is important that anything Swing-related occur on the Event Dispatch Thread, or EDT. This is because Swing is not thread-safe. When invoking popup(), you ought to do the following
if(SwingUtilities.isEventDispatchThread()){
Message.popup(...);
}
else{
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
Message.popup(...);
}
});
}
This will ensure that the JFrame is created on the EDT. Also, from the code snippet you've posted, it would seem likely that Message should have a private constructor. In addition, since you're not doing any custom rendering, why not just make a JFrame member variable instead of extending the class? -- seems a bit superfluous to me.
Regardless, you should also never sleep in the EDT either, since this will make the GUI appear to "freeze" and blocks execution of other queued events. When performing long-running tasks, use either SwingWorker, or as #Riduidel mentioned, javax.swing.Timer. But if you prefer to use the java.util.Timer, use the SwingUtilities utility class as shown above to post the Runnable task on the EventQueue to be executed in the EDT.
EDIT
Here is what I'd do (and yes, it works)
public class Message {
// Private constructor to prevent external instantiation
private Message(){
}
public static void createAndShowDialog(final String content, final int time){
final JDialog dialog = new JDialog();
dialog.setLayout(new BorderLayout());
dialog.setUndecorated(true);
JLabel label = new JLabel(content);
label.setFont(new Font("Monospaced", Font.BOLD, 20));
Box b = Box.createHorizontalBox();
b.add(Box.createHorizontalGlue());
b.add(label, BorderLayout.CENTER);
b.add(Box.createHorizontalGlue());
dialog.add(b);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
// kick-off timer
Timer t = new Timer(time, new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
dialog.dispose();
}
});
t.setRepeats(false);
t.start();
}
}
And wherever you invoke createAndShowDialog(...), do the following
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
Message.createAndShowDialog("Content", 5000); // wait 5 seconds before disposing dialog
}
});
Are you sure your code is executing in the EDT ? indeed, if not (which is what I expect to be, since you sleep the current thread, what Swing would typically don't like), your frame will have trouble rendering.
To avoid those typical Swing threading issues, please take a look at the SwingUtilities class, which provide you methods to ensure you're running in EDT. Additionnaly, instead of directly sleeping your thread, you could repalce it with a Swing javax.swing.Timer (beware not to confuse it with the java.util.Timer).
update(getGraphics());
Never use the update() method or the getGraphics() method.
Invoking update() is used for AWT NOT Swing.
If you need to do custom painting then you override the paintComponent() method of your component which already has access to the graphics object.