How can I make Eclipse WindowBuilder parse an inherited JFrame? - java

I have a class BaseWindow with a JFrame mainFrame, and a bunch of methods that work on mainFrame. Actual windows in my app are made by extending BaseWindow.
The class extending BaseWindow inherits mainFrame, and that somehow prevents window builder from "seeing" it when it parses the code. All I see in window builder's design tab is an empty window, but when I run the code everything works fine.
How can I make this approach work with window builder, or "trick" window builder into parsing mainFrame? Here is an example class extending BaseWindow:
package GUIApp;
//took out the imports to save space
class SampleWindowOne extends BaseWindow{
public JLabel txtSampleText;
public JButton btnMagicButton;
public SampleWindowOne() {
initialize();
}
public void run(){
mainFrame.setBounds(getCenteredBounds());
mainFrame.setVisible(true);
}
private void initialize() {
mainFrame = new JFrame();
mainFrame.setBounds(100,100,700,525);
mainFrame.setTitle("Sample Window One");
mainFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
mainFrame.getContentPane().setLayout(null);
txtSampleText = new JLabel();
txtSampleText.setFont(new Font("Dialog", Font.PLAIN, 25));
txtSampleText.setHorizontalAlignment(SwingConstants.CENTER);
txtSampleText.setText("Sample Window");
txtSampleText.setBounds(12, 50, 674, 51);
mainFrame.getContentPane().add(txtSampleText);
JTextArea txtrLoremIpsumDolor = new JTextArea();
txtrLoremIpsumDolor.setEditable(false);
txtrLoremIpsumDolor.setFont(new Font("Dialog", Font.PLAIN, 16));
txtrLoremIpsumDolor.setForeground(Color.DARK_GRAY);
txtrLoremIpsumDolor.setWrapStyleWord(true);
txtrLoremIpsumDolor.setLineWrap(true);
txtrLoremIpsumDolor.setText("Lorem ipsum dolor sit amet...");
txtrLoremIpsumDolor.setBounds(57, 131, 609, 296);
mainFrame.getContentPane().add(txtrLoremIpsumDolor);
btnMagicButton = new JButton("End Program");
btnMagicButton.setEnabled(false);
btnMagicButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
requestTerminate();
}
});
btnMagicButton.setBounds(257, 451, 175, 25);
mainFrame.getContentPane().add(btnMagicButton);
}
}

I'm sure you're past that now, but for others searching solution to this:
In eclipse go to:
Window -> Preferences -> Window Builder(tree) -> Swing -> Code Generation
Set initGUI method from the combo box of "Method name for new statements" at the top of the page. (you can also try to set another method name)
In "Variable generation" section, click once on third tab: "Init. Field" so that you can see its' square filled with v sign(and the other tabs have an empty square).
Click ok.
Restart eclipse.
Create a method named initGUI as follows:
private void initGUI() {
}
Copy all your code from the constructor to that method.
Call that method from your constructor:
public WindowTest()
{
initGUI();
}
Go to window builder design by clicking: "Design" at the bottom of the editor.
Click a lot of reparse if necessary.
Now add one component (JButton for instance) to the window, and watch it go into iniGUI method. Once you've seen that happens - it is safe to take out code lines that are not realted to GUI from that method and put them in the constructor if you want.

Okay, I found a way to trick window builder into working! I changed the constructor from:
public SampleWindowOne() {
initialize();
}
to:
public SampleWindowOne() {
JFrame mainFrame;
initialize();
}
Hopefully this helps someone with their own code.
Edit: not fully solved after all, see below. I will update if I find a better solution.
Edit2: Okay, after a good night's sleep the solution is pretty obvious. I now declare a separate JFrame at the beginning of the class. I add all my elements to this frame instead of mainFrame, and at the end of initialize I put
mainFrame = newFrame;

Related

How to close a Java JFrame based on action event from a JPanel

How would I go about closing a JFrame based on an ActionEvent from a button click within a JPanel?
I have a total of three classes:
Application: contains the main method and runs the program by creating a FrameStartUp object.
FrameStartUp: extends the JFrame class and displays the contents within StartUpPanel.
StartUpPanel: extends the JPanel class and has all the components and ActionEvents.
Within the StartUpPanel class, I have a button with an ActionEventListener waiting for the button to be clicked.
When the button is clicked I want the application to shut down completely. I know of a method called .dispose() for the JFrame class, but I can't use it because creating an object of FrameStartUp would just run another GUI (run by the constructor).
As I am new to programming and swing, I do not know any other way to fix this, other than getting rid of the StartUpPanel and just creating a JPanel within the FrameStartUp class.
Are there any methods provided by Swing that can access the current JFrame that the panel is on, so the program can close when the ActionEvent is triggered?
I know of a method called .dispose() for the JFrame class
This will work if you explicitly set setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Are there any methods provided by Swing that can access the current JFrame that the panel is on
Yes... SwingUtilities provides one called getWindowAncestor().
button.addActionListener(e -> {
SwingUtilities.getWindowAncestor((Component)e.getSource()).dispose();
});
... or more commonly, you can chose to reference a final variable to achieve the same effect...
final JFrame swingStuff = this; // or expose via a getter/setter
button.addActionListener(e -> {
swingStuff.dispose();
});
... however the final variable placement and setter/getter would need a small reproducible code example.
And finally, as others have mentioned, System.exit(0) works quite fantastically well too, so as long as it doesn't break the lifecycle of any of your other components.
My test class:
import javax.swing.*;
import java.awt.*;
public class SwingStuff extends JFrame {
// Our main JFrame
public SwingStuff() {
super();
// The button
JButton button = new JButton("Close");
button.addActionListener(e -> {
SwingUtilities.getWindowAncestor((Component)e.getSource()).dispose();
});
// The JPanel and nested components
JPanel startupPanel = new JPanel();
startupPanel.add(button);
add(startupPanel);
pack();
// Make sure the app exits when closed
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
// Just our entry point
public static void main(String ... args) {
SwingUtilities.invokeLater(() -> {
new SwingStuff().setVisible(true);
});
}
}

JTextBox and all following JComponents don't show up

I want do design a simple login format and in order to do so I want two JTextFields for Username/Password and a Login Button. The Login button is display as expected but when I add the JTextField, nothing shows in my JFrame. Would be nice if someone could help a beginner out...
Here's my code (I know it's ugly but this is just a "code sketch"):
package bucketlistpackage;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GameFrame extends JFrame {
public GameFrame(String title) {
super(title); //sets title of frame
startFrame(); //sets details of main frame
final Container logincont = getContentPane(); //creates content pane
JFrame loginframe = new JFrame();
usernameField(loginframe);
loginButton(loginframe);
logincont.add(loginframe);
}
private void usernameField(JFrame loginframe) {
JTextField usernameF = new JTextField("Username", 1);
usernameF.setBounds(50, 50, 50, 20);
loginframe.add(usernameF);
usernameF.setVisible(true);
}
private void startFrame() {
this.setSize(1000, 1000);
this.setVisible(true);
}
private void loginButton(Container cont) {
JButton loginB = new loginButton();
loginB.setSize(300, 150);
loginB.setText("Login");
cont.add(loginB);
}
}
The problem lies on how you are adding component to one another in your case.
You are adding a JFrame to a Container, when in all case it should be the other way around.
The other problem is that you are not using Layouts to manage the components positions on the JFrame.
Another problem as well is that you are not refreshing the windows after adding all the stuff on it.
A bit of a resume on how Java works with native UIs:
Java creates a new thread for the UI. So if you open the debugger you will see AWT threads as well as the main threads and others. This means that you have to manage this in a correct way, because after the application starts SWING and the functions you determine for reactions will lay the ground on how it will behave. Your main thread will die, but the visual threads will keep active.
If you are just starting to program I would encourage you to practice a bit more native java language before moving to SWING or AWT. This libraries can be really painful and tricky to use.
The other thing is SWING library follows a hierarchy for the components:
JFrame > JPanels > Components
In your code you have already worked with all of them but in a disorganized way. JFrame is the main application window, where the graphics will be displayed (can also be a Canvas or whatever class you want to use for that matter). JPanels are organizers, you can use different layouts to organize whatever is inside it. And finally the Components are well... everything! A component can be a JTextField, but it can also be a JPanel, or JButton.
The idea with SWING is to create multiple Panels and organize the end components inside them, using the help of the different layouts to see whats the best approach to make them attractive in many different window sizes.
Finally, if you are using Eclipse, there is a plugin called WindowBuilder which might help you. I don't recommend you using it if you are very new to Java since it will make you depend a lot on it instead of learning how to actually code with SWING.
Hope this helps!!!
Btw, to fix the code above I would do something like this:
public GameFrame(String title) {
super(title); //sets title of frame
startFrame(); //sets details of main frame
final Container logincont = getContentPane(); //creates content pane
logincont.setLayout(new BorderLayout());
usernameField(logincont, BorderLayout.NORTH);
loginButton(logincont, BorderLayout.CENTER);
this.revalidate();
this.repaint();
}
private void usernameField(Container loginframe, String direction) {
JTextField usernameF = new JTextField("Username");
// usernameF.setBounds(50, 50, 50, 20);
loginframe.add(usernameF, direction);
usernameF.setVisible(true);
}
private void startFrame() {
this.setSize(1000, 1000);
this.setVisible(true);
}
private void loginButton(Container cont, String direction) {
JButton loginB = new JButton();
loginB.setSize(300, 150);
loginB.setText("Login");
cont.add(loginB, direction);
}

Code Executing in different orders, Jframe, Button and TextArea

Basically i have some code to make an interface that allows me to submit a request and it pulls the necessary information from a txt File. For some reason wheni execute my StartUp for the code, sometimes the button isnt there, one text box dominates the screen, all the textboxes overlap... Its weird.
Anyway heres the GUI Code
public class Menu {
SubmitCode submit = new SubmitCode();
public static JFrame frame;
public static JTextField field;
public static Button btn;
public static TextArea txtComm;
public static TextArea txtSites;
public static TextArea txtProg;
public static Dimension dim = new Dimension(40, 10);
public Menu() {
frame = new JFrame();
frame.setTitle("Welcome :)");
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
}
public static void open() {
Menu.main(null); // Opens up the main method of the class
}
public static void main(String args[]) {
field = new JTextField();
btn = new Button();
txtComm = new TextArea();
txtSites = new TextArea();
txtProg = new TextArea();
field.setText("What do you want to do?");
field.setSize(390, 20);
field.setLocation(0, 125);
btn.setVisible(true);
btn.setLabel("Click to Submit");
btn.setSize(90, 20);
btn.setLocation(400, 125);
txtComm.setVisible(true);
txtComm.setText("Commands: ");
txtComm.setSize(150, 100);
txtComm.setLocation(10, 10);
txtComm.setEditable(false);
frame.add(txtComm);
txtSites.setVisible(true);
txtSites.setText("Sites: ");
txtSites.setSize(150, 100);
txtSites.setLocation(170, 10);
txtSites.setEditable(false);
frame.add(txtSites);
txtProg.setVisible(true);
txtProg.setText("Programmes: ");
txtProg.setSize(150, 100);
txtProg.setLocation(330, 10);
txtProg.setEditable(false);
frame.add(txtProg);
frame.setSize(500, 175);
frame.add(field, BorderLayout.SOUTH);
frame.add(btn);
btn.addActionListener( new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.out.println("Do Something Clicked");
SubmitCode.main(null);
}
});
}
}
Suggestions:
Don't use static methods/fields, except when a specific need arises or for the main method. You do not have the need here.
Instead use valid classes, classes with constructors, instance (non-static) fields and instance methods.
Don't needlessly mix AWT and Swing components but instead use just Swing components. So JTextArea, not TextArea, JButton, not Button, etc....
For instance, your Menu constructor is wasted code that is never called due to your misuse and over-use of statics.
Don't set sizes, use null layouts and absolute positioning such as with setBounds.
Instead read up on and use the layout managers.
Don't pepper your code with useless bits such as most of your calls to setVisible(true).
Call setVisible(true) on the top level window, here your JFrame, after adding all components.
Do read the relevant tutorials as this is all very well explained there. Google Java Swing Tutorials and check the very first hit.
This bit scares me: SubmitCode.main(null); and suggests that you're trying to call the static main method of another class from within a GUI. You should avoid doing this, and instead have your SubmitCode class use good OOP techniques including non-static methods and fields, constructors, etc...

Java, swing opening new JFrame from another class

I have this piece of code:
public class GUI extends JFrame {
private PlaneUI planeui;
public GUI(PlaneUI planeui) {
this.planeui = planeui;
}
//We have put the code that creates the GUI inside a method
public GUI() {
start();
planeui.display();
} ...
This is just a test and I need the method "planeui.display" to work when the program starts, together with the method "start();" which already works.
public final class PlaneUI extends JFrame {
public void display() {
//Creates a new JPanel object
JPanel panelStart = new JPanel();
getContentPane().add(panelStart);
//Changing the default layout from Flowlayout to absolute
panelStart.setLayout(null);
setTitle("Reservationer"); //Sets the window title
setSize(236, 256); //Sets the default size of the window
setLocationRelativeTo(null); //Start location of the window (centered)
setDefaultCloseOperation(EXIT_ON_CLOSE); //Exits the window
}
}
I have imported the needed libraries and I feel like the problem lies in an object that isn't created correctly since I get a nullpointerexception. I tried running this planeUI class in the main method and it worked correctly. I just can't get it to work this way..
In function PlaneUI.display() add one last line setVisible(true) because your adding everything but not displaying anything
you have to add this into your display() method:
setVisible(true);
Otherwise, all you are doing is setting all the aspects of the JFrame and adding the JPanel to it. You have to make it visible afterwards.

Desktop application - how do I dynamically create and destroy forms

I'm creating a small crypto app for the desktop using java.
I'm using JFrames (import javax.swing.JFrame) with Oracle
JDeveloper 11g under Linux.
I want to have a "welcome" form/frame where users can choose
their encryption method, and then on choosing the method,
I want to dynamically create the appropriate form for the
chosen encryption method and also destroy/free/dispose() of
the welcome form. When the user has finished their encrypting,
they should close the frame/form (either by clicking on the
x at the top right - or using the Exit button or by any
method) and the welcome frame should be dynamically recreated
and appear.
I've tried various things - btnEncode_actionPerformed(ActionEvent e)
then this.dispose() - and I've fiddled with this_windowClosed(WindowEvent e)
and dispose(), but nothing seems to work.
Even a workaround using setVisibl(true/false) would be acceptable at
this stage - this has been wrecking my head all day. It's very
easy to do in Delphi!
TIA and rgs,
Paul...
something like this usually does the trick: (Note I haven't tested this)
public class WelcomeMsg extends JFrame
.
.
.
public void btnContinue_actionPerformed(ActionEvent e)
{
this.dispose();
SwingUtilities.invokeLater(new Runnable(){ new JFrameAppropriateWindow(args) });
}
where btnContinue is the Continue button on your welcome form and JFrameAppropriateWindow is the next frame you would like to show depending on the user's choice. Args are any arguments you need to pass.
When you are ready, you can simply dispose the current frame and relaunch an instance of WelcomeMsg
I put together this simple example for creating and displaying a panel depending on a user choice.
public class Window extends JFrame {
public Window() {
this.setLayout(new BorderLayout());
JComboBox encryptionCombobox = new JComboBox();
encryptionCombobox.addItem("foo");
encryptionCombobox.addItem("bar");
//...
encryptionCombobox.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// find choices and the correct panel
JPanel formPanel = new JPanel();
formPanel.setOpaque(true);
formPanel.setBackground(Color.RED);
//...
Window.this.add(formPanel, BorderLayout.CENTER);
Window.this.validate();
Window.this.repaint();
}
});
add(encryptionCombobox, BorderLayout.NORTH);
}
public static void main(String[] args) {
new Window().setVisible(true);
}
}
When I come to think about it, you should probably use a CardLayout instead, which allows you to switch between different panels (cards).

Categories

Resources