简体   繁体   English

在Java中切换只读

[英]Toggle read-only in Java

Is there a way to toggle a read-only mode so when you click any object in your window it simply returns what you clicked, ignoring the object's usual event handling? 有没有办法切换只读模式,所以当您单击窗口中的任何对象时,它只返回您单击的内容,忽略对象的常规事件处理? IE, while in this "read-only" mode, if you click on a Button, it simply returns the button, not actually pressing the button. IE,在这种“只读”模式下,如果你点击一个按钮,它只是返回按钮,而不是实际按下按钮。 Then I could do something like: 然后我可以这样做:

if ("thing pressed" == button) "do this";
else if ("thing pressed" == panel) "do that";
else "do nothing";

Here's my code, its a frame with 3 colored boxes. 这是我的代码,它是一个带有3个彩色框的框架。 Clicking the 2nd box, the 3rd box, or the background will display a message. 单击第二个框,第三个框或背景将显示一条消息。 Clicking box 1 does nothing. 单击框1不执行任何操作。 I like using new mouse adapters so I want to do it this way. 我喜欢使用新的鼠标适配器,所以我想这样做。

Now what I want is when you click box 1, box 1 is treated as selected (if that helps you get the picture). 现在我想要的是当您单击框1时,框1被视为已选中(如果这有助于您获得图片)。 Then if you click anywhere, including box 1 again, box 1 is deselected and nothing else (meaning that box 2, box 3. or the background's message will display). 然后,如果你点击任何地方,包括方框1,则取消选择方框1而不显示其他内容(意味着将显示方框2,方框3或背景信息)。 At that time, only if box 2 or 3 were clicked, they will still not display their normal message but a different message would be displayed. 那时,只有在单击框2或3时,它们仍然不会显示正常消息,但会显示不同的消息。

I'm very sorry if I come off a little short. 如果我有点短暂,我很抱歉。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Labels {
    public static void main(String[] args) {
        new Labels();
    }

    Square l1, l2, l3;
    public Labels() {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        l1 = new Square();
        l2 = new Square();
        l3 = new Square();

        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(120, 150);
        frame.setResizable(false);

        panel.setVisible(true);
        panel.setLayout(null);
        l1.setLocation(5, 5);
        l2.setLocation(5, 60);
        l3.setLocation(60, 5);

        l2.setColor("yellow");
        l3.setColor("black");

        l1.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                //do nothing
            }
        });

        l2.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Pushed label 2");
            }
        });
        l3.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("Pushed label 3");
            }
        });
        panel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("pushed background");
            }
        });

        frame.add(panel);
        panel.add(l1);
        panel.add(l2);
        panel.add(l3);
    }

    class Square extends JLabel{
        Color color = Color.blue;

        public Square() {
            // TODO Auto-generated constructor stub\
            setVisible(true);
            setSize(50,50);
        }

        public void paint(Graphics g) {
            super.paint(g);
            g.setColor(color);
            g.fillRect(0, 0, 50, 50);
        }
        public void setColor(String color){
            if (color == "white") this.color = Color.white;
            else if (color == "black") this.color = Color.black;
            else if (color == "yellow") this.color = Color.yellow;
            else {
                System.out.println("Invalid color");
                return;
            }
            repaint();
        }
    }
}

Don't disable anything. 不要禁用任何东西。 Simply change the state of your class, perhaps by using a few boolean flag variables/fields and change these flags depending on what is pressed. 只需更改类的状态,可能使用一些布尔标志变量/字段,并根据按下的内容更改这些标志。

So have boolean fields called label1PressedLast , label2PressedLast , and label3PressedLast or something similar, and when a label is pressed, check the states of all other flags and have your program's behavior change depending on the state of these flags and the label that was just pressed. 所以有名为label1PressedLastlabel2PressedLastlabel3PressedLast类似的布尔字段,当按下标签时,检查所有其他标志的状态,并根据这些标志的状态和刚刚按下的标签改变程序的行为。 Then set all flags to false except for the one corresponding to the label that was just pressed. 然后将所有标志设置为false,除了与刚刚按下的标签对应的标志。

For example, this little program reacts only if the first and then the third JLabel have been pressed: 例如,只有在第一个和第三个JLabel被按下时,这个小程序才会做出反应:

import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.*;

public class FlagEg extends JPanel {
   private static final int LABEL_COUNT = 3;
   private JLabel[] labels = new JLabel[LABEL_COUNT];
   private boolean[] flags = new boolean[LABEL_COUNT];

   public FlagEg() {
      setLayout(new GridLayout(1, 0, 20, 0));
      setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

      // panel mouse listener
      addMouseListener(new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent arg0) {
            inactivateAll();
         }
      });

      MouseListener labelsMouseListener = new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent mouseEvt) {
            myMousePressed(mouseEvt);
         }
      };

      // create JLabels and add MouseListener
      for (int i = 0; i < labels.length; i++) {
         labels[i] = new JLabel("Label " + (i + 1));
         labels[i].addMouseListener(labelsMouseListener);
         labels[i].setOpaque(true);
         labels[i].setBorder(BorderFactory.createLineBorder(Color.black));
         add(labels[i]);
      }
   }

   private void inactivateAll() {
      for (int i = 0; i < labels.length; i++) {
         labels[i].setBackground(null);
         flags[i] = false;
      }
   }

   private void myMousePressed(MouseEvent mouseEvt) {
      JLabel label = (JLabel) mouseEvt.getSource();

      // which label was pressed?
      int index = -1;
      for (int i = 0; i < labels.length; i++) {
         if (label == labels[i]) {
            index = i;
         }
      }

      // check if first label and then third pressed:
      if (flags[0] && index == 2) {
         System.out.println("first and then third label pressed!");
      }

      // reset all labels and flags to initial state
      inactivateAll();

      // set pressed label background color and set flag of label just pressed
      labels[index].setBackground(Color.pink);
      flags[index] = true;

   }

   private static void createAndShowGui() {
      FlagEg mainPanel = new FlagEg();

      JFrame frame = new JFrame("Flag Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

Logic iteration two: only label 1 is the "primer" JLabel. 逻辑迭代二:只有标签1是“引物”JLabel。 This is actually easier to implement, because now you only need one boolean flag, that representing label 1 being pressed: 这实际上更容易实现,因为现在您只需要一个布尔标志,表示按下标签1:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

@SuppressWarnings("serial")
public class FlagEg2 extends JPanel {
   private static final int LABEL_COUNT = 3;
   private JLabel[] labels = new JLabel[LABEL_COUNT];

   private boolean label1Flag = false;

   public FlagEg2() {
      setLayout(new GridLayout(1, 0, 20, 0));
      setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

      // panel mouse listener
      addMouseListener(new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent arg0) {
            inactivateAll();
         }
      });

      MouseListener labelsMouseListener = new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent mouseEvt) {
            myMousePressed(mouseEvt);
         }
      };

      // create JLabels and add MouseListener
      for (int i = 0; i < labels.length; i++) {
         labels[i] = new JLabel("Label " + (i + 1));
         labels[i].addMouseListener(labelsMouseListener);
         labels[i].setOpaque(true);
         labels[i].setBorder(BorderFactory.createLineBorder(Color.black));
         add(labels[i]);
      }
   }

   private void inactivateAll() {
      for (int i = 0; i < labels.length; i++) {
         labels[i].setBackground(null);
         label1Flag = false;
      }
   }

   private void myMousePressed(MouseEvent mouseEvt) {
      JLabel label = (JLabel) mouseEvt.getSource();

      // which label was pressed?
      int index = -1;
      for (int i = 0; i < labels.length; i++) {
         if (label == labels[i]) {
            index = i;
         }
      }

      if (label1Flag) {
         if (index == 1) {
            System.out.println("Label 1 and label 2 pressed");
         } else if (index == 2) {
            System.out.println("Label 1 and label 3 pressed");
         }

      }

      // reset all labels and flags to initial state
      inactivateAll();

      // if label1, then activate it
      if (index == 0) {
         labels[0].setBackground(Color.pink);
         label1Flag = true;
      }

   }

   private static void createAndShowGui() {
      FlagEg2 mainPanel = new FlagEg2();

      JFrame frame = new JFrame("Flag Example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}
package javaapplication6;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 *
 * @author Jan Vorcak <vorcak@mail.muni.cz>
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

        MouseListener listener = new MouseAdapter() {

            private int count = 0;

            @Override
            public void mouseClicked(MouseEvent e) {
                if(e.getComponent() instanceof JLabel) {
                    count++;
                    if (count >= 2) {
                        System.out.println("clicked 2 times on labels");
                        count = 0;
                    }
                } else {
                    count = 0;
                }
            }

        };

        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        JLabel l1 = new JLabel("Label 1");
        JLabel l2 = new JLabel("Label 2");
        JLabel l3 = new JLabel("Label 3");
        l1.addMouseListener(listener);
        l2.addMouseListener(listener);
        l3.addMouseListener(listener);
        frame.addMouseListener(listener); // or panel.addMouseListener(listener);
        panel.add(l1);
        panel.add(l2);
        panel.add(l3);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
    }

}

You could want to create a listener that do the job for using the putClientProperty method of JComponent . 您可能希望创建一个侦听器来执行使用JComponentputClientProperty方法的工作。

   public class JComponentClickCountListener extends MouseAdapter {

        private final Integer ONE = 1;

        @Override
        public void mouseClicked(MouseEvent e) {
            if (e.getComponent() instanceof JComponent) {

                JComponent jComponent = (JComponent) e.getComponent();

                Object property = jComponent.getClientProperty(JComponentClickCountListener.class);

                if (property instanceof Number) {
                    property = ONE + ((Number) property).intValue();
                }
                else {
                    property = ONE;
                }

                jComponent.putClientProperty(JComponentClickCountListener.class, property);
            }

        }

    }

Then in your code you can decide to have a single instace of that class for all of your components or create a new one each time. 然后在您的代码中,您可以决定为所有组件创建该类的单个实例,或者每次创建一个新实例。

This could give you the advantage of using the propertyChangeListener for future actions. 这可以为您提供使用propertyChangeListener进行将来操作的优势。

PS. PS。

The code example do not represent all logic for OP question but i could by used as solid base. 代码示例并不代表OP问题的所有逻辑,但我可以用作实体基础。 Later on i will try to update it. 稍后我将尝试更新它。 To cover that. 为了掩盖这一点。

EDIT2: EDIT2:

I think that you should separate the logic, of selection and action over selected items. 我认为你应该将所选项目的逻辑,选择和行动分开。 Then the task is divided into two tasks. 然后任务分为两个任务。 First is the possibility to store the information about it state, clicked active, clicked again inactive. 首先是存储有关状态的信息,点击活动,再次点击不活动的可能性。 The second tasks it to operate on that status when a jComponent status was changed. 第二个任务是在更改jComponent状态时对该状态进行操作。

This is an simple example that i wrote, the functionality is to highlight the background of labels when the are selected and remove it when it was clicked again or the panel was clicked remove all selections. 这是我写的一个简单示例,其功能是在选中时突出显示标签的背景,并在再次单击时单击面板或单击面板删除所有选择。

This example is divided to three elements Enum, Iterface and class that manage the logic of selection 此示例分为三个元素Enum,Iterface和类,用于管理选择逻辑

Enum - we store the possible statuses and a property key. 枚举 - 我们存储可能的状态和属性键。

public enum JComponentActivationStatus {
    NONE,
    ACTIVE,
    INACTIVE;

    public static final String PROPERTY_KEY = JComponentActivationStatus.class.getCanonicalName();
}

Interface - provide a delegate for action to be taken when jcomponenet status change. 接口 - 提供jcomponenet状态更改时要采取的操作的委托。

public abstract interface JComponenetActivationStatusChangeAction<T extends JComponent> {

    public abstract void onActivation(T object);

    public abstract void onDeactivation(T object);

}

Class - This class mange the status logic of jcomponents. Class - 此类管理jcomponents的状态逻辑。

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JComponent;



public class JComponenetActivationManager {



    public static <T extends JComponent> T addMouseStatusControl(T jComponent) {

        jComponent.addMouseListener(new JComponentMouseStatusModyfier());

        return jComponent;
    }

    public static <T extends JComponent> T addActivationStatusChangeAction(T jComponenet, JComponenetActivationStatusChangeAction<T> statusChangeAction) {

        jComponenet.addPropertyChangeListener(craeteJCompositeActivationStatusChangeListener(statusChangeAction));

        return jComponenet;

    }

    public static  <T extends JComponent> PropertyChangeListener craeteJCompositeActivationStatusChangeListener(JComponenetActivationStatusChangeAction<T> action) {

        return new JComponentStatusPropertyChangeListener<T>(action);

    }


    /**
     * Class that set the status for the JComponet after doubClicl
     */
    private final static class JComponentMouseStatusModyfier extends MouseAdapter {

        @Override
        public void mouseClicked(MouseEvent e) {

            if(e.getComponent() instanceof JComponent) {

                JComponent jComponent = (JComponent) e.getComponent();

                Object propertyValue = jComponent.getClientProperty(JComponentActivationStatus.PROPERTY_KEY);

                if(JComponentActivationStatus.ACTIVE.equals(propertyValue)) { //We check that the ACTIVE status is already selected, if so we inactive. 
                    propertyValue = JComponentActivationStatus.INACTIVE; //If so we inactive it. 
                } else {
                    propertyValue = JComponentActivationStatus.ACTIVE; // Otherwise we set it as active
                }

                jComponent.putClientProperty(JComponentActivationStatus.PROPERTY_KEY, propertyValue); // We use the property key form status

            }
        }
    }

    /**
     * Help class that fire the actions after status is changed 
     */
    private static final class JComponentStatusPropertyChangeListener<T extends JComponent> implements PropertyChangeListener {

        private final JComponenetActivationStatusChangeAction<T> statusChangeAction;

        /**
         * 
         */
        public JComponentStatusPropertyChangeListener(JComponenetActivationStatusChangeAction<T> statusChangeAction) {

            if(statusChangeAction == null) {
                throw new IllegalArgumentException("action can not be null at this point");
            }

            this.statusChangeAction = statusChangeAction;
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {

            if(JComponentActivationStatus.PROPERTY_KEY.equals(evt.getPropertyName())) {

                if(JComponentActivationStatus.ACTIVE.equals(evt.getNewValue())) {
                    statusChangeAction.onActivation((T) evt.getSource());
                }

                if(JComponentActivationStatus.INACTIVE.equals(evt.getNewValue())){
                    statusChangeAction.onDeactivation((T) evt.getSource());
                }
            }
        }

    }
}

That class contain two public static method, that allow the developer to add the functionality to mange status to any jComponent object, add subscribe the action handler if any change occur. 该类包含两个公共静态方法,允许开发人员将mange状态的功能添加到任何jComponent对象,如果发生任何更改,则添加订阅操作处理程序。

At the end we have the main method that test our solution 最后,我们有测试我们的解决方案的主要方法

public static void main(String[] args) {

        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
            JLabel l1 = new JLabel("Label 1");
            JLabel l2 = new JLabel("Label 2");
            JLabel l3 = new JLabel("Label 3");

        panel.setBackground(Color.CYAN);

        addMouseStatusControl(panel);
        addMouseStatusControl(l1);
        addMouseStatusControl(l2);
        addMouseStatusControl(l3);

        JComponenetActivationStatusChangeAction<JLabel> activeBackground = new JComponenetActivationStatusChangeAction<JLabel>() {
            @Override
            public void onActivation(JLabel object) {
                object.setOpaque(true);
                object.setBackground(Color.YELLOW);
            }


            @Override
            public void onDeactivation(JLabel object) {
                object.setOpaque(false);
                object.setBackground(object.getParent().getBackground());
            }

        };


        JComponenetActivationStatusChangeAction<JPanel> deactivateChildrens = new JComponenetActivationStatusChangeAction<JPanel>() {

            @Override
            public void onDeactivation(JPanel object) {
            }

            @Override
            public void onActivation(JPanel object) {

                for(Component component : object.getComponents()) {
                    if(component instanceof JComponent) {
                        ((JComponent) component).putClientProperty(JComponentActivationStatus.PROPERTY_KEY,JComponentActivationStatus.INACTIVE); 
                    }
                }
            }
        };

        addActivationStatusChangeAction(l1, activeBackground);
        addActivationStatusChangeAction(l2, activeBackground);
        addActivationStatusChangeAction(l3, activeBackground);
        addActivationStatusChangeAction(panel, deactivateChildrens);


        panel.add(l1);
        panel.add(l2);
        panel.add(l3);
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);

}

The solution is very flexible and extendable in case you will need to add more labels. 该解决方案非常灵活且可扩展,以防您需要添加更多标签。

The example is for those that want to learn. 这个例子适合那些想要学习的人。 Any comment would be appreciate. 任何评论都会很感激。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM