I am looking to use the Factory Method Pattern in order to make the development of my Swing UI quicker and more manageable.
In general, its an MDI application using JInternalFrames. I have a lot of settings, types as I call them, in the system (Eg. userTypes, accountTypes, etc.) I have a fixed UI which I've decided to use. Thing is, there are over 50 of these types in the system, so the factory method pattern seems to be the most manageable solution. Below are two screenshots of a working app.
I was looking at [this example][3] but since I wont be able to estimate the number of tabs I would require to store all info in a record, I would need to be able to add multiple tabs and controls (labels, textboxes, tables, comboboxes, etc.) within these tabs.
Based on the example, is it possible to create a JTabbedPane in the abstract class and modify and add to it in the subclasses? I tried the following and am a bit lost:
public AbstractTypeInternalFrame(String title) {
setBounds(100, 100, 808, 589);
JToolBar toolBar = new JToolBar();
getContentPane().add(toolBar, BorderLayout.NORTH);
JButton btnAdd = new JButton("Add");
toolBar.add(btnAdd);
JButton btnSave = new JButton("Save");
btnSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
toolBar.add(btnSave);
JButton btnDelete = new JButton("Delete");
toolBar.add(btnDelete);
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
toolBar.add(btnCancel);
JTabbedPane recordTabs = new JTabbedPane(makeRecordTabPane());
getContentPane().add(recordTabs, BorderLayout.NORTH);
JSeparator recordSearchSeparator = new JSeparator();
getContentPane().add(recordSearchSeparator, BorderLayout.NORTH);
}
protected abstract int makeRecordTabPane();
with the method makeRecordTabPane() require to return an int.
As you can see, I'm a little lost and just need some direction as to how to proceed with such a pattern. If any has any advice or even examples/links, it would be much appreciated.
I realize my question is vague, so if any clarification is required on my side, please feel free to ask.
Best regards.
Here is the question in more detail.
So, I am looking to build a simple JInternalFrame for CRUD operations on records on the system. Records such as users, usertypes, accounts, accountypes, etc. There are more than 50 of these types in the system, so I figure using the factory method pattern would make all these JInternalFrames more manageable.
Here is an example of a user record:
Link1
Link2
The top half constitutes of the details of a record, which are split into tabs depending on the contents of the record. Some records may have just one tab, while other larger ones will have multiple. Therefore, the contents of the JTabbedPane should be instantiated at the subclass level and per this example.
The bottom part is where we would search for records of that type. Say for example, in the links posted, the User Manager JInternalFrame is opened. We then would search for users according to username and/or userID. Results are displayed in the table below and on double-clicking a search result, the record is displayed above in the JTabbedPane.
Add, Save, Delete and Cancel buttons are then used to perform CRUD operations on whatever is entered into the record.
From this, we can say that the aspects of the design than need to be instantiated by subclasses are:
1) Size of the JInternaFrame
2) All contents of the JTabbedPane: no of tabes, tables, labels, textboxes, etc.
3) The number of columns in the search result JTable: which we can change by instantiating the JTable Header.
As a start, I was trying to just create an Abstract class with a JTabbedPane, and add components to the JTabbedPane to see how I could go about it. This is the code I posted earlier. This file was generated using WindowBuilder, which I later then modified:
package zm.co.freight.fpsManagementGUI.view;
import java.awt.EventQueue;
public abstract class AbstractTypeInternalFrame extends JInternalFrame {
/**
* Launch the application.
*/
// public static void main(String[] args) {
// EventQueue.invokeLater(new Runnable() {
// public void run() {
// try {
// AbstractTypeInternalFrame frame = new AbstractTypeInternalFrame();
// frame.setVisible(true);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// });
// }
/**
* Create the frame.
*/
public AbstractTypeInternalFrame(String title) {
setBounds(100, 100, 808, 589);
JToolBar toolBar = new JToolBar();
getContentPane().add(toolBar, BorderLayout.NORTH);
JButton btnAdd = new JButton("Add");
toolBar.add(btnAdd);
JButton btnSave = new JButton("Save");
btnSave.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
toolBar.add(btnSave);
JButton btnDelete = new JButton("Delete");
toolBar.add(btnDelete);
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
}
});
toolBar.add(btnCancel);
JTabbedPane recordTabs = new JTabbedPane(makeRecordTabPane());
getContentPane().add(recordTabs, BorderLayout.NORTH);
JSeparator recordSearchSeparator = new JSeparator();
getContentPane().add(recordSearchSeparator, BorderLayout.NORTH);
}
protected abstract int makeRecordTabPane();
}
The question is, am I on the right track? How should I approach it using the factory method pattern as I don't seem to grasp it very well. I've seen simpler examples, with shapes and drawings, but am a bit lost with Swing interfaces. Is there a good example you could direct me to or a simple example just to point me in the right direction ... thats all I was asking for. Sorry if it was vague ...
Related
Which way of implementing an ActionListener is more correct?
Is there any major performance differences?
Implementing an ActionListener to the class:
public class MainFrame implements ActionListener {
JButton exampleButton1 = new JButton();
JButton exampleButton2 = new JButton();
JButton exampleButton3 = new JButton();
public MainFrame(){
exampleButton1.addActionListener(this);
exampleButton2.addActionListener(this);
exampleButton3.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if(src.equals(exampleButton1)){
//Do something
}else if(src.equals(exampleButton2)){
//Do something
}else if(src.equals(exampleButton3)){
//Do something
}
}
}
Versus adding ActionListeners to each JButton:
public class MainFrame {
JButton exampleButton1 = new JButton();
JButton exampleButton2 = new JButton();
JButton exampleButton3 = new JButton();
public MainFrame(){
exampleButton1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Do something
}
});
exampleButton2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Do something
}
});
exampleButton3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//Do something
}
});
}
}
Or perhaps even using Lambdas..?
I would prefer to use an individual Action as the listener for the button. An Action is a slightly more advanced listener that can be used anywhere an ActionListener can be used.
It provides additional functionality such as:
The same Action can be used by multiple components, such as a JButton, JMenuItem
You can disable the Action, which will disable all components that use the Action
It allows to assign mnemonics and accelerators to your components
See the Swing tutorial on How to Use Actions for more information and examples on this concept.
As you can spot, for single ActionListener-approach there are three more branches for each single if test, which button was pressed. There was nothing done yet, so no real action, just testing which button was pressed.
Now, if you want to achieve high quality work there are metrics like branch coverage. Firstly, If you go for the single ActionListener-approach each of your if is creating two branches. So you have to come up with 6 tests to just test if the base idea of your ActionListener is working correctly, so to find out which button was pressed and the correct if part was used. This is some overhead effort.
Secondly, there is the Single Responsibility Paradigm (SRP). It states that each class should be responsibly for one task only. Now, there are three things this single ActionListener is handling.
Thirdly, the reusage of the single ActionListener is very limited and highly depending on the buttons.
Fourthly, I also call this kind of single ActionListener-approach Manual written Object Orientation, because this would be an approach if there was no object orientation and you have to switch or if/else for calling different methods, like exampleButton1Pressed(), exampleButton2Pressed() etc. But, this can be achieved by three dedicated ActionListeners.
So go for dedicated ActionListeners.
public class Login extends JFrame{
JFrame frame; //frame
JTextField field; //to get username
JPasswordField p; //password field
JLabel l; //used for printing on frame
JButton b;
Login() {
frame = new JFrame("Login");
frame.setSize(350,200);
frame.setLocationRelativeTo(null);
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
l = new JLabel("Enter Username");
l.setLocation(10,10);
l.setSize(l.getPreferredSize());
frame.add(l);
field = new JTextField();
field.setColumns(15);
field.setSize(field.getPreferredSize());
field.setLocation(120,10);
frame.add(field);
l = new JLabel("Enter Password");
l.setLocation(10,40);
l.setSize(l.getPreferredSize());
frame.add(l);
p = new JPasswordField();
p.setColumns(15);
p.setSize(p.getPreferredSize());
p.setLocation(120,40);
frame.add(p);
b = new JButton("OK");
b.setSize(b.getPreferredSize());
b.setLocation(120, 80);
frame.add(b);
frame.setVisible(true);
}
private class b implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String str;
str = field.getText();
if(str.equals("")) {
JOptionPane.showMessageDialog(null,"Please enter username");
field.requestFocusInWindow();
} else {
}
}
}
public static void main (String[] args) {
new Login();
}
}
the button won't functioning when I'm hit it
the button won't functioning when I'm hit it
You need to add the ActionListener to the button:
b = new JButton("OK");
b.addActionListener( new b() );
Make your class names more descriptive. "b" is not descriptive. Also, class names should start with an upper case character.
Don't use null layouts and setBounds(...). Swing was designed to be used with Layout Managers. Keep a link to the tutorial handy for Swing basics.
Take a look at How to Write an Action Listeners and How to Use Buttons, Check Boxes, and Radio Buttons.
Basically, you never register the ActionListener with your JButton
b.addActionListener(new b());
You code would be easier to read if you used meaningful variable names and followed the establishing coding conventions of the language. Have a look at Code Conventions for the Java TM Programming Language, for more details, it will make it easier for people to read your code and for you to read others
You may also want to have a read of You might want to have a read of Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?, but since you're discarded the layout manager, the use of setPreferredSize is completely pointless.
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
alright.,ive already tried every trick off my sleeves..but couldnt figure out how to update the comboBox w/glazedList..if the input is coming from other class..ive tried passing the value to the methods,declaring it first to a string..and such..but none has work..tho it does work if the new item will just gonna come from same class..via click of a button..
so far ive got this code..
values = GlazedLists.eventListOf(auto);//auto is an array..
AutoCompleteSupport.install(comboSearch,values);//comboSearch is the comboBox
//"x" is the value coming from another class.
public void updateCombo(String x){
List<String> item = new ArrayList<>();
item.add(x)
value.addAll(item);
}
i hope this codes are enough to interpret what im trying to ask..
It's not possible to see how you've created your combobox and your eventlist. Therefore I'll just create a simple example application from scratch that shows you the essentials.
Just in case you're not familiar the general concepts the main take home points are:
Try and avoid using standard Java collections (eg ArrayList, Vector) and use the EventList class as soon as possible. All the goodness that comes with sorting/filtering/auto-complete relies on the EventList foundation so set one up asap and then simply manipulate (add/remove/etc) and then the GlazedLists plumbing will take care of the rest.
Once you've got your collection of objects in an EventList and you want to leverage a swing component then look in the ca.odell.glazedlists.swing module which contains everything you need. In this instance you can use an EventListComboBoxModel - pass in your eventlist, and then set your JComboBox model to use the newly created EventListComboBoxModel and from that point GlazedLists will take care of ensuring your list data structure and combobox stay in sync.
So in my example I create an empty combobox and an button. Clicking the button will add an item per click into the combobox. The magic is simply the creation of the EventList and the use of EventListComboBoxModel to link the list to the combobox.
Please note that the code below was only tested against GlazedLists 1.8. But I'm pretty sure it'll work fine with 1.9 or 1.7 too.
public class UpdateComboBox {
private JFrame mainFrame;
private JComboBox cboItems;
private EventList<String> itemsList = new BasicEventList<String>();
public UpdateComboBox() {
createGUI();
}
private void createGUI() {
mainFrame = new JFrame("GlazedLists Update Combobox Example");
mainFrame.setSize(600, 400);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton addButton = new JButton("Add Item");
addButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
itemsList.add("Item " + (itemsList.size()+1));
}
});
// Use a GlazedLists EventComboBoxModel to connect the JComboBox with an EventList.
EventComboBoxModel<String> model = new EventComboBoxModel<String>(itemsList);
cboItems = new JComboBox(model);
JPanel panel = new JPanel(new BorderLayout());
panel.add(cboItems, BorderLayout.NORTH);
panel.add(addButton, BorderLayout.SOUTH);
mainFrame.getContentPane().add(panel);
mainFrame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new UpdateComboBox();
}
});
}
}
I have a decorated JFrame. I need to make close button and minimize button. What should I do?
Here is my code snippet:
public Startup()
{
setTitle("STARTUP");
setSize(800,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setUndecorated(true);
setLocationRelativeTo(null);
setVisible(true);
}
Your approach is very unique and will look quite good. There are many ways to solve your problem. Now, as per your request, you want a CLOSE and a MINIMIZE button. Let us make the following Actions.
private final Action exitAction = new AbstractAction("Exit")
{
#Override
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
};
private final Action minimizeAction = new AbstractAction("Minimize")
{
#Override
public void actionPerformed(ActionEvent e)
{
setState(JFrame.ICONIFIED);
}
};
Now, let us apply the above actions to JButtons:
JButton closeButton = new JButton(exitAction);
JButton miniButton = new JButton(minimizeAction);
There you have it. Now, all you need to do is add your buttons to your JFrame.
Note For Eclipse Users
this code will come in your minimize button when You click On minimize button in Eclipse.
YourFrameName is the Frame name you had set or it is set by default, use that frame name here:
YourFrameName.setState(YourFrameName.ICONIFIED);
I am working on a LAB for one of my classes and am in need of some assistance.
I am building an Apartment Complex GUI which will have a menu system and individual functions between many different classes. The complex with consist of Tenants, Employees and a Bank.
I currently have the whole project working based out of the console but now I am assigned to convert it to a GUI interface.
This is the code in my main function for GUI:
ApartmentComplex mavPlace = new ApartmentComplex(); //creates a new apartment complex object
mavPlace.aptBank.setBalance(ANNUAL_BUDGET); //sets the apartment bank budget
readFile(mavPlace);
mavPlace.goThroughAndAssignValues(mavPlace);
JFrame frame = new JFrame("My First GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
JButton button = new JButton("Press");
frame.getContentPane().add(button); // Adds Button to content pane of frame
frame.setVisible(true);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
mavPlace.lease(mavPlace);
}
});
With the action listener, when the button is pressed it should call a lease function in another class of mine. From there I want it do go back to console output.
The error netbeans is giving me is: local variable mavPlace is accessed from within inner class; needs to be declared final
.... now I went an made the decleration final just to see what happened and it worked, but i couldnt edit my complex details so that was not possible.
What can i do?
Thank You!
Make your class implement the ActionListener interface and use this to add an action listener ie
button.addActionListener(this);
http://docs.oracle.com/javase/tutorial/uiswing/events/actionlistener.html
If you use Anonymous Class, you should set the parameter used in the class as final type in current block or as a member private variable.
class MyGUI
{
ApartmentComplex mavPlace;
public MyGUI()
{
JFrame frame = new JFrame("My First GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300,300);
JButton button = new JButton("Press");
frame.getContentPane().add(button); // Adds Button to content pane of frame
frame.setVisible(true);
mavPlace = new ApartmentComplex(); //creates a new apartment complex object
mavPlace.aptBank.setBalance(ANNUAL_BUDGET); //sets the apartment bank budget
readFile(mavPlace);
mavPlace.goThroughAndAssignValues(mavPlace);
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
//Execute when button is pressed
mavPlace.lease(mavPlace);
}
});
}
}
I think you should reconsider your structure of your program.
If you told us the complete purpose, you would get better answer.