lundi 28 décembre 2015

Which pattern would you suggest for handling those events?

I'm trying to improve my code, and i think i found something that I could manage better, but Even after watching lots video about patterns design i still have doubt on how to modify my source code.

In my software i have a certain JPanel which contains some JComponents. These JComponents have a MouseAdapter that fires events on mouseClick and MouseHover (both entered and exited). The thing is: when a mouseClick is fired the related JComponent enters in the "Edit status", and when one JComponent is in this status, the others do not have to fire their events.

to achieve this kind of behave, i added a boolean to the JComponents container, which is modified by those events, and each events check its status before doing anything. It works as expected, but i m sure there is something more clever to implement this kind of behaviour.

Here is a sample code, and 2 images of the tool:

img 1

img 2

Main Class:

public class Main {
    public static void main(String[] args)  {   
        SwingUtilities.invokeLater(new Runnable(){
            @Override
            public void run(){           
                JFrame myFrame= new MyFrame();
                myFrame.setVisible(true);
            }
        });     
    }
}

Code JFrame:

public class MyFrame extends JFrame{

    private  boolean onEdit;
    private MyComponent myComp1;
    private MyComponent myComp2;
    private MyComponent myComp3;
    private MyComponent myComp4;

    public MyFrame(){
        super.setTitle("MyFrame");
        super.setPreferredSize(new Dimension(400,400));
        super.setLocationRelativeTo(null);
        super.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        super.setLayout(new GridBagLayout());
        onEdit = false;
        initComponents();
        addComponents();
        super.pack();
    }

    private void initComponents() {
        myComp1 = new MyComponent(this);
        myComp2 = new MyComponent(this);
        myComp3 = new MyComponent(this);
        myComp4 = new MyComponent(this);
    }

    private void addComponents() {
        Container myContainer = getContentPane();
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridx = 0;
        gbc.gridy = 0;
        myContainer.add(myComp1,gbc);

        gbc.gridx = 0;
        gbc.gridy = 1;
        myContainer.add(myComp2,gbc);

        gbc.gridx = 1;
        gbc.gridy = 0;
        myContainer.add(myComp3,gbc);

        gbc.gridx = 1;
        gbc.gridy = 1;
        myContainer.add(myComp4,gbc);
    }

    public void setOnEdit(boolean toggle){
        onEdit = toggle;
    }

    public boolean isOnEdit(){
        return onEdit;
    }

}

Code JComponents:

public class MyComponent extends JComponent{

    private MyFrame mainFrame;

    public  MyComponent(MyFrame myFrame){
        mainFrame = myFrame;
        this.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
        this.setLayout(new FlowLayout(FlowLayout.LEFT));
        this.setPreferredSize(new Dimension(100,50));
        this.add(initTextField());
        this.add(initCheckBox());
        this.addMouseListener(new MyComponentMouseListener(this));
        this.addKeyListener(new MyComponentKeyListener(this));
    }

    private JFormattedTextField initTextField() {
        NumberFormat myFormat = NumberFormat.getInstance();
        JFormattedTextField text = new JFormattedTextField(myFormat);
        text.setDisabledTextColor(Color.BLACK);
        text.setColumns(5);
        text.addMouseListener(new MouseEventDispatcher());
        text.addKeyListener(new KeyEventDispatcher());
        text.setEnabled(false);
        return text;
    }

    private JCheckBox initCheckBox() {
        JCheckBox check = new JCheckBox();
        check.addMouseListener(new MouseEventDispatcher());
        check.addKeyListener(new KeyEventDispatcher());
        check.setEnabled(false);
        return check;
    }

    public MyFrame getMainFrame() {
        return mainFrame;
    }

    public void saveEdit() {
        /**not relevant for the example*/
    }

    public void resetEdit() {
        /**not relevant for the example*/
    }

}

class MouseEventDispatcher extends MouseAdapter{
    @Override 
    public void mouseEntered(MouseEvent e) {
        dispatchMouseEvent(e);
    }

    @Override 
    public void mouseExited(MouseEvent e) {
        dispatchMouseEvent(e);
    }

    @Override
    public void mouseClicked(MouseEvent e){
        dispatchMouseEvent(e);
    }

    private void dispatchMouseEvent(MouseEvent event) {
        Component source = event.getComponent();
        Component destination = SwingUtilities.getUnwrappedParent(source);
        MouseEvent mouseEvent = SwingUtilities.convertMouseEvent(source, event, destination);
        destination.dispatchEvent(mouseEvent);
    }
}

class KeyEventDispatcher extends KeyAdapter{
    public void keyPressed(KeyEvent e) {
        if(EnterPressed(e) || EscPressed(e)){
            dispatchKeyEvent(e);
        }
    }

    private boolean EnterPressed(KeyEvent e) {
        return e.getKeyChar() == KeyEvent.VK_ENTER;
    }

    private boolean EscPressed(KeyEvent e) {
        return e.getKeyChar() == KeyEvent.VK_ESCAPE;
    }

    private void dispatchKeyEvent(KeyEvent event) {
        Component source = event.getComponent();
        Component destination = SwingUtilities.getUnwrappedParent(source);
        destination.dispatchEvent(event);
    }
}

Code MouseAdapter :

public class MyComponentMouseListener extends MouseAdapter {

private MyComponent myComponent;

    public MyComponentMouseListener(MyComponent comp){
        myComponent = comp;
    }

    @Override
    public void mouseEntered(MouseEvent e) {
        if(!myComponent.getMainFrame().isOnEdit()){
            myComponent.setBorder(BorderFactory.createLineBorder(Color.GREEN));
        }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if(!myComponent.getMainFrame().isOnEdit()){
            myComponent.getMainFrame().setOnEdit(true);
            myComponent.setBorder(BorderFactory.createLineBorder(Color.RED));
            myComponent.getComponent(0).setEnabled(true);
            myComponent.getComponent(1).setEnabled(true);
            myComponent.getComponent(0).requestFocus();
        }
    }

    @Override
    public void mouseExited(MouseEvent e) {
        if(!myComponent.getMainFrame().isOnEdit()){
            Rectangle componentArea = e.getComponent().getBounds();
            Point cursorPosition = e.getPoint();
            if(cursorIsOut(cursorPosition,componentArea)){
                myComponent.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
            }
        }
    }

    private boolean cursorIsOut(Point p, Rectangle r) {
        return p.x < 0 || p.y < 0 || p.x >= r.width || p.y >= r.height;
    }

}

Code KeyAdapter:

public class MyComponentKeyListener extends KeyAdapter {

    private MyComponent myComponent;

    public MyComponentKeyListener(MyComponent comp){
        myComponent = comp;
    }

    @Override
    public void keyPressed(KeyEvent e) {
        if(EnterPressed(e)){
            saveChanges(e);
        }
        if(EscPressed(e)){
            cancelChanges(e);
        }
    }

    private boolean EnterPressed(KeyEvent e) {
        return e.getKeyChar() == KeyEvent.VK_ENTER;
    }

    private boolean EscPressed(KeyEvent e) {
        return e.getKeyChar() == KeyEvent.VK_ESCAPE;
    }

    private void cancelChanges(KeyEvent e) {
        myComponent.resetEdit();
        exitEdit();
    }

    private void saveChanges(KeyEvent e) {
        myComponent.saveEdit();
        exitEdit();
    }

    private void exitEdit() {
        myComponent.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
        myComponent.getComponent(0).setEnabled(false);
        myComponent.getComponent(1).setEnabled(false);
        myComponent.requestFocus();
        myComponent.getMainFrame().setOnEdit(false);
    }

}

Thanks for any suggestion!

Aucun commentaire:

Enregistrer un commentaire