【问题标题】:How to validate and modify a String before pasting it into a JSpinner?如何在将字符串粘贴到 JSpinner 之前验证和修改字符串?
【发布时间】:2015-12-08 08:36:48
【问题描述】:

我有一个带有“HH:mm”格式的 SpinnerDateModel 的 JSpinner。我希望用户(例如)能够从表(或任何其他来源)复制“yyyy-MM-dd HH:mm:ss.SSS”中的日期并将其粘贴到 JSpinner - HH:mm仅部分。这样的完整日期字符串通常对组件无效,但我仍然想尝试粘贴的字符串并从中获取所需的信息(如果它在那里)...... 我认为我的验证方法应该如下所示,但我不知道如何更改 paste() 行为,以便我可以添加粘贴文本的验证和更改...

        private String validateAndReturnCorrected(String pastedText) {

            DateFormat hoursMinutesFormat = new SimpleDateFormat("HH:mm");
            try {
                // trying to paste a full date string?
                DateFormat fullDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                Date date = fullDateFormat.parse(pastedText);
                return hoursMinutesFormat.format(date);
            } catch (ParseException ex) {
            }
            // trying to paste hour and minutes?
            try {
                Date date = hoursMinutesFormat.parse(pastedText);
                return hoursMinutesFormat.format(date);
            } catch (ParseException ex1) {
            }
            // trying to paste date in HH:mm:ss format?
            try {
                DateFormat hoursMinutesSecondsFormat = new SimpleDateFormat("HH:mm:ss");
                Date date = hoursMinutesSecondsFormat.parse(pastedText);
                return hoursMinutesSecondsFormat.format(date);
            } catch (ParseException ex2) {
            }
            // trying to paste date in HH:mm:ss.SSS format?
            try {
                DateFormat hoursMinutesSecondsMilisecondsFormat = new SimpleDateFormat("HH:mm:ss.SSS");
                Date date = hoursMinutesSecondsMilisecondsFormat.parse(pastedText);
                return hoursMinutesFormat.format(date);
            } catch (ParseException ex3) {
            }

            // unable to correct the string...
            return "";

        }

更新

更改谷歌搜索的问题,我发现以下两个网站让我解决了问题:

所以解决方案看起来像这样:

class ProxyAction extends TextAction implements ClipboardOwner {

    private TextAction action;

    public ProxyAction(TextAction action) {
        super(action.toString());
        this.action = action;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        String cbc=getClipboardContents();
        setClipboardContents(validateAndReturnCorrected(cbc));
        action.actionPerformed(e);
        setClipboardContents(cbc);
        System.out.println("Paste Occured...............................................................");
    }

// here goes the validateAndReturnCorrected method

    public String getClipboardContents() {
        String result = "";
        try {
            result = (String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
        } catch (UnsupportedFlavorException | IOException ex) {
            ex.printStackTrace();
        }
        return result;
    }

    public void setClipboardContents(String aString) {
        StringSelection stringSelection = new StringSelection(aString);
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents(stringSelection, this);
    }

    @Override
    public void lostOwnership(Clipboard clipboard, Transferable contents) {
    }
}

【问题讨论】:

  • 这个问题可能对您有所帮助:stackoverflow.com/questions/3707485/… 是否可以让用户在文本字段中粘贴日期并让用户在需要时修改输入?
  • 不,它应该尝试自动更正粘贴的字符串...我想我需要一种方法来覆盖我的 jSpinner 编辑器的 paste() 方法或类似的方法...您链接的问题涉及从字符串获取日期的问题,但我认为我在发布的验证方法中做得很好。

标签: java swing date jspinner


【解决方案1】:

我希望用户(例如)能够在“yyyy-MM-dd”中复制日期 HH:mm:ss.SSS" 来自表格(或任何其他来源)并将其粘贴到 JSpinner - 仅 HH:mm 部分。

  • 这个简单的事情是在JSpinners Xxx(Spinner)Model 中实现的,并且取决于 - 是否将 SimpleDateFormat 添加到 JSpinner 中

  • 输入验证 (SpinnerEditor),默认情况下只是 JFormattedTextField(更多信息可阅读 JFormattedTextFields 配置和 InputVerifier)

  • 例如(基础和标准,无需覆盖或设置特殊内容), 日期从 12 月 8 日更改为 12 月 10 日,小时从上午 10 点更改为上午 7 点

.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GraphicsEnvironment;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import javax.swing.AbstractSpinnerModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerListModel;
import javax.swing.SpinnerNumberModel;

public class JSpinnerTest {

    public static final int DEFAULT_WIDTH = 400;
    public static final int DEFAULT_HEIGHT = 250;
    private JFrame frame = new JFrame();
    private JPanel mainPanel = new JPanel(new GridLayout(0, 3, 10, 10));
    private JButton okButton = new JButton("Ok");
    private JPanel buttonPanel = new JPanel();

    public JSpinnerTest() {
        buttonPanel.add(okButton);
        mainPanel = new JPanel();
        mainPanel.setLayout(new GridLayout(0, 3, 10, 10));

        JSpinner defaultSpinner = new JSpinner();
        addRow("Default", defaultSpinner);
        JSpinner boundedSpinner = new JSpinner(new SpinnerNumberModel(5, 0, 10, 0.5));
        addRow("Bounded", boundedSpinner);
        String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment()
                .getAvailableFontFamilyNames();
        JSpinner listSpinner = new JSpinner(new SpinnerListModel(fonts));
        addRow("List", listSpinner);
        JSpinner reverseListSpinner = new JSpinner(new SpinnerListModel(fonts) {
            private static final long serialVersionUID = 1L;

            @Override
            public Object getNextValue() {
                return super.getPreviousValue();
            }

            @Override
            public Object getPreviousValue() {
                return super.getNextValue();
            }
        });
        addRow("Reverse List", reverseListSpinner);
        JSpinner dateSpinner = new JSpinner(new SpinnerDateModel());
        addRow("Date", dateSpinner);
        JSpinner betterDateSpinner = new JSpinner(new SpinnerDateModel());
        String pattern = ((SimpleDateFormat) DateFormat.getDateInstance()).toPattern();
        betterDateSpinner.setEditor(new JSpinner.DateEditor(betterDateSpinner, pattern));
        addRow("Better Date", betterDateSpinner);
        JSpinner timeSpinner = new JSpinner(new SpinnerDateModel());
        pattern = ((SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.SHORT)).toPattern();
        timeSpinner.setEditor(new JSpinner.DateEditor(timeSpinner, pattern));
        addRow("Time", timeSpinner);
        JSpinner permSpinner = new JSpinner(new PermutationSpinnerModel("meat"));
        addRow("Word permutations", permSpinner);
        frame.setTitle("SpinnerTest");
        frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
        frame.add(buttonPanel, BorderLayout.SOUTH);
        frame.add(mainPanel, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private void addRow(String labelText, final JSpinner spinner) {
        mainPanel.add(new JLabel(labelText));
        mainPanel.add(spinner);
        final JLabel valueLabel = new JLabel();
        mainPanel.add(valueLabel);
        okButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                Object value = spinner.getValue();
                valueLabel.setText(value.toString());
            }
        });
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JSpinnerTest frame = new JSpinnerTest();

            }
        });
    }
}

class PermutationSpinnerModel extends AbstractSpinnerModel {

    private static final long serialVersionUID = 1L;

    /**
     * Constructs the model.
     *
     * @param w the word to permute
     */
    public PermutationSpinnerModel(String w) {
        word = w;
    }

    @Override
    public Object getValue() {
        return word;
    }

    @Override
    public void setValue(Object value) {
        if (!(value instanceof String)) {
            throw new IllegalArgumentException();
        }
        word = (String) value;
        fireStateChanged();
    }

    @Override
    public Object getNextValue() {
        int[] codePoints = toCodePointArray(word);
        for (int i = codePoints.length - 1; i > 0; i--) {
            if (codePoints[i - 1] < codePoints[i]) {
                int j = codePoints.length - 1;
                while (codePoints[i - 1] > codePoints[j]) {
                    j--;
                }
                swap(codePoints, i - 1, j);
                reverse(codePoints, i, codePoints.length - 1);
                return new String(codePoints, 0, codePoints.length);
            }
        }
        reverse(codePoints, 0, codePoints.length - 1);
        return new String(codePoints, 0, codePoints.length);
    }

    @Override
    public Object getPreviousValue() {
        int[] codePoints = toCodePointArray(word);
        for (int i = codePoints.length - 1; i > 0; i--) {
            if (codePoints[i - 1] > codePoints[i]) {
                int j = codePoints.length - 1;
                while (codePoints[i - 1] < codePoints[j]) {
                    j--;
                }
                swap(codePoints, i - 1, j);
                reverse(codePoints, i, codePoints.length - 1);
                return new String(codePoints, 0, codePoints.length);
            }
        }
        reverse(codePoints, 0, codePoints.length - 1);
        return new String(codePoints, 0, codePoints.length);
    }

    private static int[] toCodePointArray(String str) {
        int[] codePoints = new int[str.codePointCount(0, str.length())];
        for (int i = 0, j = 0; i < str.length(); i++, j++) {
            int cp = str.codePointAt(i);
            if (Character.isSupplementaryCodePoint(cp)) {
                i++;
            }
            codePoints[j] = cp;
        }
        return codePoints;
    }

    private static void swap(int[] a, int i, int j) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

    private static void reverse(int[] a, int i, int j) {
        while (i < j) {
            swap(a, i, j);
            i++;
            j--;
        }
    }
    private String word;
}

【讨论】:

  • 我似乎无法从“日期”微调器中复制字符串并将其粘贴到“更好的日期”或“时间”中,以便他们从“获取”他们需要的部分剪贴板值...还是我做错了什么?有没有办法改变粘贴的内容?
  • 我刚刚意识到您误解了我:我希望能够复制整个日期并粘贴整个日期,但是粘贴的字符串将在粘贴时被修改为仅包含有效数据(在我的情况下,它应该将粘贴的完整日期剥离为仅小时和分钟部分 - 我不希望用户必须手动进行;日期的“智能”粘贴)。
  • @ssr 1. 为了获得更好的帮助,请尽快发布 SSCCE / MCVE 简短、可运行、可编译,2. 描述了基本解决方法(错误和收缩值)(日期从 12 月 8 日更改为 10 日。 12 月和上午 10 点到上午 7 点的小时)在我的回答中,有几种方法,但是(不想猜测您是否缺少小时、分钟或小时和分钟以及模型中的实际值和格式化输出屏幕)
  • at 1. 我目前可以发布的唯一 SSCCE 是带有微调器的面板,没有真正的附加功能,这就是我刚刚发布验证方法的原因。我需要的是一种在要粘贴的文本上调用我的验证方法的方法(作为对 ctrl+v 的反应或从菜单中选择“粘贴”),以便将更正后的字符串粘贴到微调器中,而不是存储的原始剪贴板值(剪贴板不应更改)。我唯一的想法是覆盖微调器编辑器的 paste() 方法,但我能做到吗?不幸的是我不明白你的第二点......
  • 例如:我将完整日期 2015-12-10 14:12:30.125 复制到剪贴板中,然后尝试将其粘贴到“HH:mm”格式的微调器中。微调器中的值应变为 14:12,剪贴板的内容不变。 “剥离”是在验证方法中进行的,但我不知道如何将其与粘贴操作挂钩。
【解决方案2】:

我认为您应该能够分两步完成此操作。

  1. 首先您需要在 JSpinner 上附加一个 ChangeListener。
  2. 然后在 stateChanged 方法中进行验证并将更改应用到值。

【讨论】:

  • 我已经尝试过了,但我无法让听众将粘贴与通过键入进行的正常编辑区分开来。
  • 再试一次看看到底是什么问题,并且 stateChanged 方法只有在编辑成功提交后才会触发。我可以为格式化程序执行 setCommitsOnValidEdit(true) ,但这也不会让它按我想要的方式工作 - 它只会让它在输入的每个字符等处触发......我想要的是修改当时粘贴的字符串将其粘贴到文本字段中。例如,我的剪贴板有一个完整格式的日期,但我的代码会即时将字符串更改为“HH:mm”格式并将其粘贴到字段或类似字段中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多