Java Class Diagram - java

I'm learning to design a class diagram for java and this is my first attempt. Could you please tell me if it's okay.
Here's the source code
public class DiceRoll1 extends JFrame implements ActionListener {
private JTextField txtNotation;
private JButton btRoll, btShuffle;
private List<Integer> dealtCard;
private History history;
public DiceRoll1() {
initComponents();
dealtCard = new ArrayList<>();
history = new History();
}
public void initComponents() {
//designing the userform
setSize(400, 500);
setLayout(new FlowLayout());
setTitle("Dice Roll");
txtNotation = new JTextField("2d6");
btRoll = new JButton("Roll");
btShuffle = new JButton("Shuffle");
txtNotation.setColumns(20);
getContentPane().add(txtNotation);
getContentPane().add(btRoll);
getContentPane().add(btShuffle);
btRoll.addActionListener(this);
btShuffle.addActionListener(this);
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
new DiceRoll().setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
JButton source = (JButton) e.getSource();
if (source.equals(btRoll)) {
} else if (source.equals(btShuffle)) {
}
}
public void displayOutput(String message) {
System.out.println(message);
}
}
Here's the diagram that i have drawn using Visio professional:

I think that your diagram isn't too bad but I noticed some things.
the names of your attributes in the code and the diagram are not consistent
You don't need to add Java built-in classes except you extend or implement them or you're told to do so because they unnecessarily inflate your diagram
You should draw an inheritance connection between JFrame and your class
You should draw a realization connection between ActionListeners and your class
Connection types of an UML-Class-Diagram

Related

Rewriting the code so that its readability is improved without changing its behaviour

public class A2 {
public class B implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Fing");
}
}
public class C implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Fang");
}
}
public class D implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Foom");
}
}
public A2(){
JButton a = new JButton("Fing");
JButton b = new JButton("Fang");
JButton c = new JButton("Foom");
a.addActionListener(new B());
b.addActionListener(new C());
c.addActionListener(new D());
}
public static void main(String[] args) {
A2 a2 = new A2();
}
The problem I encountered is quite simple, but complex. I want it to shorten the code without retouching its functionality. For example, the code is showing to many actionlisteners and actionperformed, and I was trying to make it one class pulling out System.out.println(); and putting in String value on it. However, the coding does not work in this simple ways. Please help me out to curtail this code as simple and increase the readability. Thanks.
It's impossible to know what things you could do, I'm personally a fan of self documenting code, so sometimes, you need to be careful when trying to optimise solutions.
My first thought might be to start with the Action's API, which allows you to design a self contained unit of work
public class CommonAction extends AbstractAction {
public CommonAction(String name) {
putValue(NAME, name);
putValue(SHORT_DESCRIPTION, "This is a tool tip for " + name);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(getValue(NAME));
}
}
You could extend it further to provide more customisation if you needed, overriding the actionPerformed method, but, that's up to you.
Then you just need to apply to your buttons...
public class A2 {
public A2() {
JButton a = new JButton(new CommonAction("Fing"));
JButton b = new JButton(new CommonAction("Fang"));
JButton c = new JButton(new CommonAction("Foom"));
}
}
Or your menu's or your key bindings, Action is a rather flexible API supported by a number of other components
You can define single class MyActionListener which implements ActionListener as shown below:
public class MyActionListener implements ActionListener {
private String input;
public MyActionListener(String input) {
this.input = input;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(input);
}
}
public A2(){
String[] inputs = {"Fing","Fang","Foom"};//Array of JButton inputs
for(int i=0;i<inputs.length;i++) {
JButton jButton = new JButton(inputs[i]);//create JButton instance
jButton.addActionListener(new MyActionListener(inputs[i]));
}
}

Java Observer/Observable update

I've tried to apply the Observable/Observer pattern but there is something wrong with my code when I try to change a the textfield of a JTextPane.
I've got 3 classes, Play, Controller and SecondWindow here are a sample of their code.
public class Play() {
Controller c = new Controller();
SecondWindow sw = new SecondWindow();
c.addObserver(sw)
c.setText("blabla");
}
My class Controller:
public class Controller extends Observable(){
private String text ="";
private static Controller getInstance() {
if (instance == null) {
instance = new Controller();
}
return instance;
}
public void setText(String s) {
text = s;
setChanged();
notifyObservers();
}
}
and SecondWindow:
public class SecondWindow extends JFrame implements Observer{
private JPanel contentPane;
private Controller c;
private JTextPane txt = new JTextPane();
public SecondWindow () {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
SecondWindow frame = new SecondWindow();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public SecondWindow() {
initComponents();
createEvents();
c = Controller.getInstance();
}
public void initComponents() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(1000, 0, 300,500);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
txt.setBounds(0, 0, 280, 460);
txt.enable(false);
contentPane.add(txt);
}
public void update(Observable arg0 , Object arg1){
// Things to change here
}
I can't manage to put the variable c in the textField (like a txt.setText(c.getText) instruction). I'm sure that it reads the method update, but I don't know how to make sure it works.
Hint: Per the Observerable API the notifyObservers method has an overload that accepts any object as a parameter:
public void notifyObservers(Object arg)
This can even be a String. And as per the Observer API, this object is then passed into the update method in the observer, and you can use it there.
void update(Observable o,
Object arg)
arg - an argument passed to the notifyObservers method.
Separate side issue here:
contentPane.setLayout(null);
For most Swing aficionados, seeing this is like hearing nails on a chalkboard -- it's painful. While null layouts and setBounds() might seem to Swing newbies like the easiest and best way to create complex GUI's, the more Swing GUI'S you create the more serious difficulties you will run into when using them. They won't resize your components when the GUI resizes, they are a royal witch to enhance or maintain, they fail completely when placed in scrollpanes, they look gawd-awful when viewed on all platforms or screen resolutions that are different from the original one. Instead you will want to study and learn the layout managers and then nest JPanels, each using its own layout manager to create pleasing and complex GUI's that look good on all OS's.
Side issue number two: your code is not Swing thread safe, since the Swing GUI could very well be notified by the observable off of the Swing event dispatch thread or EDT. While it is not likely to cause frequent or serious problems with this simple program, in general it would be better to use a SwingPropertyChangeSupport and PropertyChangeListeners rather than Observer / Observable if you can.
Next Side Issue
This:
public class Controller extends Observable(){
isn't compilable / kosher Java. Same for the duplicate parameter-less constructors for the SecondWindow class. Yes, we know what you're trying to do, but it's hard enough trying to understand someone else's code, you really don't want to make it harder by posting kind-of sort-of uncompilable code, trust me.
For example, something simple could be implemented in Swing using PropertyChangeListeners, like so:
import java.util.concurrent.TimeUnit;
public class Play2 {
public static void main(String[] args) {
Model2 model2 = new Model2();
View2 view2 = new View2();
new Controller2(model2, view2);
view2.show();
for (int i = 0; i < 10; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// one of the few times it's OK to ignore an exception
}
String text = String.format("Counter Value: %d", i);
model2.setText(text);
}
}
}
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
public class Model2 {
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
public static final String TEXT = "text"; // name of our "bound" property
private String text = "";
public String getText() {
return text;
}
public void setText(String text) {
String oldValue = this.text;
String newValue = text;
this.text = text;
pcSupport.firePropertyChange(TEXT, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
public void removePropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(name, listener);
}
}
import javax.swing.*;
public class View2 {
private JPanel mainPanel = new JPanel();
private JTextField textField = new JTextField(10);
public View2() {
textField.setFocusable(false);
mainPanel.add(new JLabel("Text:"));
mainPanel.add(textField);
}
public JPanel getMainPanel() {
return mainPanel;
}
public void setText(String text) {
textField.setText(text);
}
public void show() {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("View");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(getMainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class Controller2 {
private Model2 model2;
private View2 view2;
public Controller2(Model2 model2, View2 view2) {
this.model2 = model2;
this.view2 = view2;
model2.addPropertyChangeListener(Model2.TEXT, new ModelListener());
}
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
view2.setText((String) pcEvt.getNewValue());
}
}
}

How to repaint JPanel from outside its parent JFrame?

I can add/remove elements to/from a panel and repaint it when the method used to fill the panel is called by one of its parent JFrame events, but I can not repaint it by events from other classes even if their sources have been added to it, or that is how I understand the problem for now.
I want to understand what is going on here, Thank you.
Main Class
public class Principal extends JFrame implements ActionListener{
private static Principal instPrincipal = null;
private SubClass subClassInst =new SubClass();
public JPanel panelPrincipal;
public static Principal getInstance() {
if (instPrincipal != null)
return instPrincipal ;
else {
instPrincipal = new Principal ();
return instPrincipal ;
}
}
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
try {
if(source == btnSub)
{
subClassInst.fillPanelPrincipal();
}
}
catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
Sub Classes Example
public class SubClass implements ActionListener {
private JPanel tempPanel;
private JButton btnSave;
private Principal instPrincipal;
public void fillPanelPrincipal() {
instPrincipal = Principal.getInstance();
instPrincipal.panelPrincipal.removeAll();
//Start adding elements..
tempPanel = new JPanel();
instPrincipal.panelPrincipal.add(tempPanel);
btnSave = new JButton("Save");
btnSave.addActionListener(this);
tempPanel.add(btnSave);
//End.
instPrincipal.panelPrincipal.repaint();
}
public void actionPerformed(ActionEvent event) {
instPrincipal = Principal.getInstance();
Object source = event.getSource();
if (source == btnSave) {
// modify local data, Database .. ; //work but need to be repainted on panelPrincipal
instPrincipal.panelPrincipal.repaint();//does not work
}
}
}
Update
To clarify the problem more, I have one single JPanel on a JFrame and there are different classes to fill it for multiple functionalities, I call their methods using JMenuItems on the main frame, these Classes implement ActionListener, passing the panel didn't work, and also the method I am trying here.
I thought about changing the design to use CardLayout, but it was very difficult.
You are calling Principal as a static reference, so how is it supposed to know what frame to repaint? You should pass the instance of the JFrame through the constructor of the subclass. Like so:
private SubClass subClassInst = new SubClass(this);
And create the constructor like this
private JFrame parent;
public SubClass(JFrame parent) { this.parent = parent; }
You can then use it like so
this.parent.repaint();

How to make interaction between Swing components, which are in different classes?

I have a complicated GUI with lot of components (JButtons, JLabels, JComboBoxes, JSpinners, etc). That's why I have to split it on several classes (add components to JPanels, this JPanels add to bigger JPanels, this JPanels add to JTabbedPane, and JTabbedPane add to JFrame).
Depend on user choises and filling in data some components enabled or disabled or get some value and set not editable (in a word - interact). It's easy to done and worked properly, if components (which are interact) are in the same class, but if only it are in different classes - any results... AAA!!!
I made simple example to explane what I need. There are four classes. First one create JFrame and add JTabbedPane:
public class MainFrame extends JFrame {
MainFrame() {
super("MainFrame");
go();
}
public void go() {
Tabs tabs = new Tabs();
getContentPane().add(tabs);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(500, 300);
setVisible(true);
}
public static void main(String[] args) {
MainFrame frame = new MainFrame();
}
}
The second class create JTabbedPane and add two JPanels as tabs. Second tab.setEnabledAt(1, false):
public class Tabs extends JTabbedPane {
public Tabs() {
go();
}
public void go() {
TabData data = new TabData();
add(" Data ", data);
TabCalculation calculation = new TabCalculation();
add("Calculation", calculation);
setEnabledAt(1, false);
}
}
The third class create JPanel with JComboBox:
public class TabData extends JPanel {
public TabData() {
go();
}
JComboBox someData;
public void go() {
String type[] = { " ", "Type 1", "Type 2", "Type 3" };
someData = new JComboBox(type);
add(someData);
someData.addActionListener(new DataListener());
}
public class DataListener implements ActionListener {
public void actionPerformed(ActionEvent ev) {
if (someData.getSelectedIndex() > 0) {
Tabs tabs = new Tabs();
tabs.setEnabledAt(1, true);
}
}
}
}
... and fourth class create some JPanel. Second tab with this JPanel disabled. When user set some value in JComboBox (selectedIndex>0) - tab have to enabled. But Tabs tabs = new Tabs(); tabs.setEnabledAt(1, true); didn't help...
How can I do that? PLEASE HELP!!! I can't sleep... I can't work... I always thinking about it and try to find out a solution...
When user set some value in JComboBox (selectedIndex>0) - tab have to
enabled.
If you need to have all of these classes split, then I would suggest you make this change in your 3rd class:
public class TabData extends JPanel {
JComboBox someData;
...
// Get rid of DataListener class and add this public method instead:
public void addActionListenerToComboBox(ActionListener listener) {
someData.addActionListener(listener);
}
}
And make this change in your 2nd class:
public class Tabs extends JTabbedPane {
public Tabs() {
go();
}
public void go() {
TabData data = new TabData();
data.addActionListenerToComboBox(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JComboBox comboBox = (JComboBox)e.getSource();
boolean enableSecondTab = comboBox.getSelectedIndex() > -1;
setEnabledAt(1, enableSecondTab);
}
});
add(" Data ", data);
TabCalculation calculation = new TabCalculation();
add("Calculation", calculation);
setEnabledAt(1, false);
}
}
Take a look to EventObject.getSource() javadoc for more details.

Leap Motion problems with Swing?

I'm starting to toy a little with the Leap Motion Controller and made a small GUI in Swing. That means it's just a Frame with a Label on it which should show a text of what the Leap Motion sees. Unfortunately my programm simply breaks down after two seconds. I have no Exceptions or something like that. Here's my code:
public class GUI extends JFrame{
private static final long serialVersionUID = 6411499808530678723L;
public JLabel label;
public GUI(){
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(300, 200);
this.label = new JLabel("Waiting for Gestures");
this.add(label);
setVisible(true);
}
public class LeapListener extends Listener{
JLabel label;
LeapListener(JLabel label){
this.label = label;
}
#Override
public void onInit(Controller controller){
}
#Override
public void onExit(Controller controller){
}
#Override
public void onConnect(Controller controller){
System.out.println("bin da");
controller.enableGesture(Gesture.Type.TYPE_CIRCLE);
controller.enableGesture(Gesture.Type.TYPE_KEY_TAP);
controller.enableGesture(Gesture.Type.TYPE_SCREEN_TAP);
controller.enableGesture(Gesture.Type.TYPE_SWIPE);
}
#Override
public void onDisconnect(Controller controller){
}
#Override
public void onFrame(Controller controller){
Frame frame = controller.frame();
GestureList glist = frame.gestures();
for (int i = 0; i < glist.count(); i++){
Gesture g = glist.get(i);
switch (g.type()){
case TYPE_CIRCLE:
CircleGesture circle = new CircleGesture(g);
this.label.setText("Mach mal nen Kreis!");
case TYPE_KEY_TAP:
KeyTapGesture key = new KeyTapGesture(g);
this.label.setText("Schreiben?");
case TYPE_SCREEN_TAP:
ScreenTapGesture screen = new ScreenTapGesture(g);
this.label.setText("Klicken?");
case TYPE_SWIPE:
SwipeGesture swipe = new SwipeGesture(g);
this.label.setText("Da wurde gewischt!");
default:
System.out.println("nothing!");
break;
}
}
}
}
public static void main(String[] args) {
GUI gui = new GUI();
LeapListener listener;
listener = gui.new LeapListener(gui.label);
Controller controller = new Controller();
controller.addListener(listener);
}
}
I have no idea what I've done wrong. The Windows-Error-Message says that the Java Platform SE binary is down (javaw.exe). Errormodule: Leap.dll
Is it a mistake that I've made or is my whole setup f#*ked up?
Ok, I found a solution by myself but unfortunately I can't explain it.
I have to create the Controller Object in the class declaration, not in the main-method. Then I have to add the listener to the controller in the constructor of my GUI, like that:
public class GUI extends JFrame{
private static final long serialVersionUID = 6411499808530678723L;
public JLabel label;
public Controller c = new Controller();
public LeapListener listener;
public GUI(){
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setSize(300, 200);
this.label = new JLabel("Waiting for Gestures");
this.add(label);
listener = new LeapListener(this.label);
c.addListener(listener);
setVisible(true);
}
...
}
So, I'm happy that I got it to work but maybe somebody is interested in the problem and may find a reason for the error I've had.

Categories