WindowBuilder for Swing made member data and it seemed unnecessary - java

WindowBuilder for Swing creates checkboxes as local variables and textboxes as member data. This inconsistency bothered me. Since it all gets linked up into the toplevel JFrame anyway, these widgets are sure to live as long as the JFrame has references down to them so there doesn't seem to be a need for the textboxes to be member data. It seems to me that the textboxes should be locals just like the checkboxes. Locals are better encapsulation. The local references can die at the end of the GUI object (a class that extends JFrame) constructor generated by WindowBuilder and the JFrame will still have references to all the widgets.
Making them local and putting "final" in front of these widget declarations so that they can be used inside the event handler's anonymous inner classes was what it took to make them work. I also had to rearrange the order a bit since the order of instantiation of textboxes doesn't matter if they are all declared as members. Order does matter for locals so I had to move the uses of the "new" operator (instantiation) "up" a bit towards the top of the local scope. They just had to be north of the event handlers that use them.
So far I've found no bugs as a consequence so I am asking why WindowBuilder did not do it this way to begin with. I am new to Swing and WindowBuilder so there is a high probability that there are excellent reasons for WindowBuilder to not do this even though it seems to be the right approach for my case.
The following is the WindowBuilder output after some trivial naming modifications but before the modifications described above. This is the output as it is with 2 textboxes, 2 checkboxes, 2 buttons in the north and 1 label in the center. This is being pasted here in case somebody can see something here that may explain the choice behind WindowBuilder's use of member data.
public class TestWB extends JFrame
{
private static final long serialVersionUID = 1L;
private JPanel contentPane;
private JTextField textBox1;
private JTextField textBox2;
public TestWB() // the constructor
{
... // see the constructor below
}
}
The constructor for the above class:
public TestWB()
{
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 646, 451);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JPanel northPanel = new JPanel();
contentPane.add(northPanel, BorderLayout.NORTH);
JButton button1 = new JButton("button1");
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
northPanel.add(button1);
JButton button2 = new JButton("button2");
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
northPanel.add(button2);
final JCheckBox checkBox1 = new JCheckBox("cb1");
checkBox1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
CbProcessor cbp = new CbProcessor();
cbp.dealWithCb(checkBox1.isSelected(), textBox1);
}
});
northPanel.add(checkBox1);
final JCheckBox checkBox2 = new JCheckBox("cb2");
checkBox2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
CbProcessor cbp = new CbProcessor();
cbp.dealWithCb(checkBox2.isSelected(), textBox2);
}
});
northPanel.add(checkBox2);
textBox1 = new JTextField();
textBox1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
textBox1.setText("tb1");
northPanel.add(textBox1);
textBox1.setColumns(5);
textBox2 = new JTextField();
textBox2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
textBox2.setText("tb2");
northPanel.add(textBox2);
textBox2.setColumns(5);
JPanel centerPanel = new JPanel();
contentPane.add(centerPanel, BorderLayout.CENTER);
JLabel label1 = new JLabel("label1");
centerPanel.add(label1);
}

This is a case where reading the WindowBuilder docs would have easily answered your question(s). WindowBuilder will generate code any way that you like. Widgets can all be local variables, all be fields, or any combination in between. You can control the scope of different widgets individually or on a type-by-type basis (by setting defaults). In fact, WindowBuilder has an incredibly rich set of code generation preferences and can replicate just about any code generation style you could desire. It will also happily reverse engineer just about any code you throw at it, so you can make just about any changes you want to the generated code (by hand or via the tool) and it will remain perfectly happy.

I don't know something about WindowBuilder, but I do know something about SWT and SimpleDesktopAplication FrameWorks but
1) both are based on AWT(part from SWT) and Swing
2) both are overrode standard AWT & Swing's methods
3) in some cases is too hard to returns back to standard AWT & Swing's methods from Framework's methods
I'd suggest to learn basic Swing at begining,

Related

Style errors with swing: method creates an object but does not assign variable or field

"This method creates an object but does not assign this object to any variable or field. This implies that the class operates through side effects in the constructor, which is a bad pattern to use, as it adds unnecessary coupling. Consider pulling the side effect out of the constructor, into a separate method, or into the calling method."
This short test program runs as I expected, but I don't know how to address this checkstyle error. Most of the examples of using javax.swing seem to have this structure.
There is also a error causes by EXIT_ON_CLOSE, but without it the process lingers after I close the window and must be force quit.
public class GUI implements ActionListener {
private int clicks = 0;
private JLabel label = new JLabel("Clicks= " + clicks);
private JFrame frame = new JFrame();
public GUI() {
// make a Jbutton named button
JButton button = new JButton("Click Me");
button.addActionListener(this);
// arrange the button and label
JPanel panel = new JPanel();
panel.add(button);
panel.add(label);
// put the panel in a frame
frame.add(panel, BorderLayout.CENTER);
// EXIT_ON_CLOSE has a style error too.
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setTitle("Graphical User Interface");
frame.pack();
frame.setVisible(true);
}
// update label and number of clicks when button is clicked
public void actionPerformed(ActionEvent e) {
clicks++;
label.setText("Clicks= " + clicks);
}
// This is the code that InteliJ says has bad form.
public static void main(String[] args) {
new GUI();
} }
One bad pattern here is that you are not creating your GUI on Event Dispatch Thread. Not sure if this is related to your problem.. but you should always use EDT to create the GUI in Swing.
EDIT: take a look here. In the main method you just have "new GUI()" without a reference variable. Writing your app like this example you are not going to use the constructor to create all :)

GUI won't open when button pressed (Java)

I am trying to open a GUI from my main GUI by pressing a button. When the button is pressed, this is executed:
WorkloadFactor wf = new WorkloadFactor();
wf.setVisible(true);
This doesn't open the WorkloadFactor GUI. I am confused by this because I have other GUIs that open this way without issue.
WorkloadFactor class works fine when I run it by itself but won't open when it is called by my main GUI. Below is my class without imports and stuff:
public class WorkloadFactor extends JPanel {
public WorkloadFactor() {
setLayout(new BorderLayout());
JTabbedPane tabbedPane = new JTabbedPane();
String[] tabnames = { "Zero", "One", "Two", "Three", "Four" };
for (int i = 0; i < tabnames.length; i++) {
tabbedPane.addTab(tabnames[i], createPane(tabnames[i]));
}
tabbedPane.setSelectedIndex(0);
JButton submit = new JButton("Submit All");
submit.setForeground(Color.RED);
add(tabbedPane, BorderLayout.CENTER);
add(submit, BorderLayout.SOUTH);
}
public JPanel createPane(final String t) {
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
//setContentPane(contentPane); I think this might be it?
contentPane.setLayout(null);
setBounds(100, 100, 531, 347);
//***** all the components I am including then add them like so
//******contentPane.add(checkbox1);
//****** contentpane.add(label1);
return contentPane;
}
public static void main(String[] args) {
JFrame frame = new JFrame("Set Workload Factor Information");
frame.getContentPane().add(new WorkloadFactor());
frame.setBounds(100, 100, 531, 347);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
}
I have tried arranging things in so many ways, putting everything in the constructor and other changes but can't seem to find a reason why instantiating this WorkloadFactor class elsewhere and setting it visible won't work.
Does it have something to do with setContentPane(contentPane) vs contentPane.add(xxxx) and returning it?
Thank you for reading!
WorkloadFactor wf = new WorkloadFactor();
wf.setVisible(true);
To be blunt, this won't display anything. Please understand that WorkloadFactor extends JPanel and like all non-top level components must be placed into a container that is ultimately held by a top-level window in order to be displayed. Look at how you display it in your main method -- you first put it into a JFrame, and then display that JFrame. You must do the same thing if you want to display it on button press -- you need to put it into a JPanel or other container that is held by a JFrame or JDialog, or JOptionPane.
Make sure that you have properly registered the button on your main GUI which opens WorkLoadFactor GUI to an action listener.
Since you have not included code from your main GUI I can't confirm this is the issue. However it is a commonly overlooked issue.
Heres some suggestions from the Java documentation tutorials:
"Problem: I'm trying to handle certain events from a component, but the component isn't generating the events it should.
First, make sure you registered the right kind of listener to detect the events. See whether another kind of listener might detect the kind of events you need.
Make sure you registered the listener on the right object.
Did you implement the event handler correctly? For example, if you extended an adapter class, then make sure you used the right method signature. Make sure each event-handling method is public void, that the name spelled right and that the argument is of the right type."
source: Solving Common Event-Handling Problems
Make a JFrame and add a JButton in it than add action listener in button and add this code in it like this:
This code makes a frame with a button and when button is pressed new window is opened.
public class Example extends JFrame {
public Example() {
super("Title");
setLayout(new FlowLayout());
JButton b = new JButton("Open new Frame");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
newWindow nw = new newWindow();
}
});
add(b);
}
}
newWindow Code:
public class newWindow extends JFrame {
newWindow() {
super("title");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
setVisible(true);
}
}

How can a component on a panel alert other components outside the panel when a value changes?

I am writing a Swing program in which all panels are declared as separate classes and a JFrame that holds the panels. The input panel has a subpanel that has a number of buttons on it. When when one of those buttons is clicked and a value is calculated, I would like to pass that value back to the JFrame holding the input panel, so that the value can be used in a number of other calculations.
I know that I can just use the JFrame ActionListener to be directly responsible for the buttons on the sub panel, but that seems to violate either portability, encapsulation, or both. I want the sub panel to be able to work on its own and let the JFrame using it be aware when a certain value changes.
I would prefer to keep the value as a primitive, but if only an object works, I can go with that.
The program has already been written as one class and it worked fine, but a beast to edit. When I was done, I realized that it was a mistake not to break it down into six panels each as their own class. A lesson for future projects. So, I am rewriting it and running into the problem that the JFrame is dependent on knowing when one of its panels (actually a panel on that panel) recalculates a value. The value calculation isn't a problem, but the JFrame needs to know when it changes.
I hope that is clear. It seemed pretty clear to me! :-)
The following code is a simplification of what I'm trying to do.
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
public class ChangeState extends JFrame {
// This is to receive the value when changed in ButtonPanel
private JTextField answer = new JTextField(5);
private InputPanel inputPanel = new InputPanel();
public ChangeState() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
add(inputPanel, BorderLayout.CENTER);
add(answer, BorderLayout.SOUTH);
pack();
setVisible(true);
}
public static void main(String[] args) {
ChangeState mf = new ChangeState();
}
}
class InputPanel extends JPanel {
private ButtonPanel buttonPanel = new ButtonPanel();
InputPanel() {
add(buttonPanel);
}
}
class ButtonPanel extends JPanel implements ActionListener {
private int value;
JButton b1 = new JButton("Value *2");
JButton b2 = new JButton("Value *3");
public ButtonPanel() {
value = 1;
b1.addActionListener(this);
add(b1);
b2.addActionListener(this);
add(b2);
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == b1) {
value *= 2;
}
if (e.getSource() == b2) {
value *= 3;
}
System.out.println("Value: " + value);
/*
* How do I let ChangeState.answer know VALUE has changed and needs
* to be updated?
*/
}
}
You can make ChangeState an observer of your ButtonPanel, by being an ActionListener listening to the ButtonPanel, or by being some other custom observer that's more abstract which you can create.
I'd recommend a more abstract custom observer when the class observing is not another GUI class with only one event, but in this case since it is perhaps you can just use an ActionListener (on the other hand, ChangeState is not much of a GUI class, you could have made it be composed of a JFrame).
If you have more than one event that could be passed through that ActionListener, you will probably then need to make ChangeState implement a more abstract observer implementation so you can better distinguish between events. Otherwise you'll need to have ChangeState know the name of some of the different GUI components that created the event's, or have a reference to them which would not be that great design wise.

Using actionListener with Button

I am programming a menu to be used with a formerly all text based game. I am trying to use addActionListener to print a line of text when a button is clicked, so I can figure out how to implement my main code in the future. The issue I am having is with the addActionListener method on my JButton. I am performing all of this with a JFrame. From what others say, I have used this as the argument but am getting a "non-static variable this cannot be referenced from a static context" error. Here is my code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Menu
{
public static void Menu()
{
JButton button = new JButton("Click to enter");
button.setBounds(125, 140, 150, 20);
JFrame frame = new JFrame("Casino");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(button);
button.addActionListener(this);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(400, 300));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
#Override
String s = "Welcome!";
System.out.println(s);
}
}
Currently your program is nothing more than a single static method with everything trying to be shoehorned into this method. This would be fine if you were creating the most basic console program, such as one that asks the user for 2 numbers, then adds the numbers and returns the answer, but you are no longer trying to do this. Instead you're trying to create a Swing GUI program, one whose state you wish to change if the user interacts with it in an event-driven way, in other words you want it to change state if the user presses a button or selects a menu item.
Your problem is that you're trying to mesh this simple static world with the "instance" world, but in static land, there is no this.
Since your needs and requirements are becoming more complex, your program structure will need to change to reflect this. Is this an absolute requirement that you do this? No -- something called Turing Equivalence tells that it is possible to write most complex program imaginable inside of a single static main method, but due to the increased complexity, the program would become very difficult to understand and almost impossible to debug.
What I recommend specifically is that you create one or more well behaved object-orient classes, classes with non-static variables and non-static methods, and use these to build your GUI and its model (the non-GUI nucleus that GUI programs should have). Again the main method should be short, very short, and should only involve itself in creating the above classes, and setting the GUI visible, and that's about it.
What you want to do is to study the basic concepts of Java, and in particular that on how to create Java classes. The Java tutorials can help you with this.
There are a number of issues with this class.
It does not implement ActionListener so it can't be used as parameter to JButton
The static modifier on the Menu method means you can even use this anyway
public static void Main is not a constructor, so beware
#Override should appear before the method declaration, not in it.
Something like...
public class Menu implements ActionListener
{
public Menu()
{
JButton button = new JButton("Click to enter");
button.setBounds(125, 140, 150, 20);
JFrame frame = new JFrame("Casino");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(button);
button.addActionListener(this);
JLabel emptyLabel = new JLabel("");
emptyLabel.setPreferredSize(new Dimension(400, 300));
frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e)
{
String s = "Welcome!";
System.out.println(s);
}
}
Might be a better approach, but I'd be worried about creating a JFrame within the class, but that's just me...

I have a JLabel that doesn't want to update

I've looked at other JLabel threads and though similar, a few just don't seem to apply to what I'm experiencing. First, I want to say I am a novice when it comes to Java. Next, I am trying to follow tutorials and demos at the docs.oracle.com site. Now, I can update the label when I type something into a JTextField and there is an ActionListener on that...
But I also have a Menu, and when I select a Menu Item, that Action does not want to update the label.
Questions -
How do I have action listeners on both JTextFields and JMenuItems? Are there two ActionEvent methods or do I use one method and somehow identify each type of action?
If I use the same basic code in the JTextField ActionEvent and JMenuItem ActionEvent, the JLabel updates correctly with the JTextField event but not JMenuItem event. They both use the messageField.setText property. Could the JMenuItem action be doing something to block the setText?
I can easily copy code in here, but it's pretty spaghetti-like at the moment, so if you want to see anything, let me know specifically and I'll post it.
I would appreciate any assistance that anyone would be able to provide.
---edit---
Wow!! Thanks for all of the comments and suggestions.
1 - I know it has to be my code. As I mentioned, I am really just cobbling stuff together from demos and tutorials, and trying to learn Java along the way. I've just never gotten the hang of object oriented....
2 - I do know the individual Listeners are working. I'm using System.out.println to validate, as well as inspecting those labels in debug mode to see they have indeed changed.
3 - I will look at the various links and code posted here and see if I can figure out what's wrong with my code.
Really, thanks again!
---edit---
Here is what I originally had in my createAndShowGUI method....
private static void createAndShowGUI()
{
JFrame frame = new JFrame("Create XML for Photo Gallery");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CreateGalleryXML window = new CreateGalleryXML();
frame.setJMenuBar(window.createMenuBar());
frame.add(new CreateGalleryXML());
frame.pack();
frame.setVisible(true);
}
Seems like you yourself are doing something wrong, in your code. Without a proper SSCCE it's hard to say what thing you doing wrong, since it works perfectly, using same ActionListener for both JMenuItem and JTextField.
Here is a sample program to match with yours :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class UpdateLabel
{
private JLabel label;
private String labelText;
private ActionListener action = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
setLabelText((String) ae.getActionCommand());
label.setText(getLabelText());
}
};
private void setLabelText(String text)
{
labelText = text;
}
private String getLabelText()
{
return labelText;
}
private void createAndDisplayGUI()
{
final JFrame frame = new JFrame("Update Label");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setLocationByPlatform(true);
JMenuBar menuBar = new JMenuBar();
JMenu programMenu = new JMenu("Program");
JMenuItem exitMenuItem = new JMenuItem("Exit");
exitMenuItem.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
frame.dispose();
}
});
JMenu labelMenu = new JMenu("Label");
JMenuItem updateMenuItem = new JMenuItem("Update Label");
updateMenuItem.setActionCommand("Updated by JMenuItem");
updateMenuItem.addActionListener(action);
programMenu.add(exitMenuItem);
labelMenu.add(updateMenuItem);
menuBar.add(programMenu);
menuBar.add(labelMenu);
frame.setJMenuBar(menuBar);
JPanel contentPane = new JPanel();
label = new JLabel("I am the LABEL which will be updated!!");
contentPane.add(label);
JTextField tfield = new JTextField(10);
tfield.setActionCommand("Updated by JTextField");
tfield.addActionListener(action);
frame.add(contentPane, BorderLayout.CENTER);
frame.add(tfield, BorderLayout.PAGE_END);
frame.pack();
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new UpdateLabel().createAndDisplayGUI();
}
});
}
}
And here is the output in both the cases :
and
Do check out the main method, might be you had failed to put your code inside EDT - Event Dispatcher Thread, that can lead to such issues too. All updates on the Swing GUI, must be done on the Event Dispatcher Thread.
LATEST EDIT
It seems to me that CreateGalleryXML extends JPanel by the look of it. See at Line 3 of this below code taken from your update, here you are initializing a new Object of CreateGalleryXML inside, when you already had one Object window created at Line 1:
CreateGalleryXML window = new CreateGalleryXML();
frame.setJMenuBar(window.createMenuBar());
frame.add(new CreateGalleryXML());
So try to change the above thingy to this
CreateGalleryXML window = new CreateGalleryXML();
frame.setJMenuBar(window.createMenuBar());
frame.add(window);
and see what happens and Please do revert back again :-)
Use Action to encapsulate common functionality that must be shared by menus and related components. See this example that extends AbstractAction.
Pretty much everything you could need to know is in the Java tutorials. Down the bottom they have demo's on how to do both menu's and text fields. They include source code to look at as well.
There's not much more I can say that they don't say better, but in answer to your questions:
Both, you can have separate listener's on each component, or one that figures out what component is responsible for causing the action event. I would suggest you use separate ones for each thing.
Can't really say with out seeing the code, are you sure that the action on the JMenu is even firing? Does it print something to the console etc if you use System.out.println somewhere?

Categories