【问题标题】:keyPressed Listener produces strange behaviourkeyPressed Listener 产生奇怪的行为
【发布时间】:2011-03-02 10:02:08
【问题描述】:

我在 jTable 上有一系列文本框和组合框。我使用框中的输入来过滤 JPQL 查询的结果,这些结果显示在 jTable 上。现在,这个想法是自动化这个过程,这样每次用户在框中键入一个字符时,应用程序都会自动发送查询并使用过滤结果更新 jTable。我试过这样做:

public class MyKeyListener extends KeyAdapter{
   public void keyPressed(KeyEvent evt){
      setFilters();
      displayResults(); }}

setFilters()和displayResults()分别是设置参数和查询并获取ResultList和更新jTable的方法。然后我将 keyPressed 添加到所有相关的文本框,以及一些 System.out.println 行以进行调试。发生的事情如下:当我输入第一个字符时,什么也没有发生。如果我输入第二个字符,KeyListener 会起作用并发送查询,但仅使用第二个字符进行过滤,则忽略第一个字符。这是我的第一个怪事。第二个是,看着我的控制台,我意识到每个成功的 Key Listened 都会发送 6 次查询。帮助将不胜感激。再三考虑,我还插入了我的 setFilters() 和 displayResults()。

  private void setFilters() {

    //Auslesen der gesetzten Filter
    String name=jName.getText()+"%";
    String vorname= jVorname.getText()+"%";
    String vvname= jVName.getText()+"%";
    String vvorname=jVVorname.getText()+"%";
    String mname=jMName.getText()+"%";
    String strasse=jAdresse.getText()+"%";
    String plz=jPlz.getText()+"%";
    String ort=jOrt.getText()+"%";
    String gruppe=jGruppe.getText()+"%";
    String geschlecht=(String) jGeschlecht.getSelectedItem()+"%";
    String mvorname=jMVorname.getText()+"%";
    String firma=jFirma.getText()+"%";



    //Die Query
    kinderQuery = java.beans.Beans.isDesignTime() ? null : rcwPUEntityManager.createQuery("SELECT k FROM Kinder k "
            + "INNER JOIN k.vaeter vat "
            + "INNER JOIN k.muetter mut "
            + "INNER JOIN k.gruppen gru "
            + "INNER JOIN k.firmen fir "
            + "WHERE k.kindName LIKE :name "
            + "AND k.kindVorname LIKE :vorname "
            + "AND vat.vaterName LIKE :vname "
            + "AND vat.vaterVorname LIKE :vvorname "
            + "AND mut.mutterName LIKE :mname "
            + "AND mut.mutterVorname LIKE :mvorname "
            + "AND k.kindStrasse LIKE :strasse "
            + "AND k.kindPLZ LIKE :plz "
            + "AND k.kindOrt LIKE :ort "
            + "AND gru.gruppeName LIKE :gruppe "
            + "AND k.kindGeschlecht LIKE :geschlecht "
            + "AND fir.firmaName LIKE :firma ");


           //Einsetzen der ausgelesenen Strings in die JPQL-Query Parameter
    kinderQuery.setParameter("name", name);
    kinderQuery.setParameter("vorname", vorname);
    kinderQuery.setParameter("vname", vvname);
    kinderQuery.setParameter("vvorname", vvorname);
    kinderQuery.setParameter("mname", mname);
    kinderQuery.setParameter("mvorname", mvorname);
    kinderQuery.setParameter("strasse", strasse);
    kinderQuery.setParameter("plz", plz);
    kinderQuery.setParameter("ort", ort);
    kinderQuery.setParameter("gruppe", gruppe);
    kinderQuery.setParameter("geschlecht", geschlecht);
    kinderQuery.setParameter("firma", firma);

}

 private void displayResults(){
    java.util.Collection data = kinderQuery.getResultList();
    System.out.println(data);
    kinderList.clear();
    kinderList.addAll(data);
    jTable1.repaint();
}

提前致谢!

【问题讨论】:

    标签: java swing keylistener


    【解决方案1】:

    问题是生成keyPressed事件时,文本字段使用的Document还没有更新。你可以监听 keyTyped 事件,但我不推荐这样做,因为它不是最好的解决方案,而且 Swing 提供了更好的 API 来使用。

    更好的方法是使用专门为此目的设计的 DocumentListener。请阅读 How to Write a Document Listener 上的 Swing 教程中的部分以获取示例和说明。

    【讨论】:

    • 感谢两位的回答。我承认从未使用过 DocumentListener,我会通读一遍。
    【解决方案2】:

    这几乎是如何做到的。使用这种方法而不是 keyPressed 对您来说有几个好处是,当您将一些文本粘贴到字段中时它也可以工作,并且很容易避免对删除等进行所有过滤。

    // in your frame or panel
    Document doc = new PlainDocument();
    doc.addDocumentListener(new MyDocumentListener());
    
    JTextField textField = new JTextField(15);
    textField.setDocument(doc);
    
    add(textField);
    
    private class MyDocumentListener implements DocumentListener
    {
        public void insertUpdate(DocumentEvent documentEvent)
        {
            // Do your stuff here
            System.out.println("insert detected!");
        }
    
        public void removeUpdate(DocumentEvent documentEvent)
        {
            // ignore this
        }
    
        public void changedUpdate(DocumentEvent documentEvent)
        {
            // ignore this
        }
    }
    

    为了避免对用户可能在文本字段中输入的每件奇怪的事情进行搜索和过滤往返,您应该考虑自己实现仅接受某些字符的 PlainDocument。

    private class MyDocument extends PlainDocument
    {
        @Override
        public void insertString(int offs, String str, AttributeSet a) throws BadLocationException
        {
            StringBuilder builder = new StringBuilder(getText(0, getLength()));
            builder.insert(offs, str);
    
            if (builder.toString().matches("[A-Za-z]*"))
            {
                super.insertString(offs, str, a);
            }
        }
    }
    

    【讨论】:

    • Swing 教程提供和解释以及一个工作示例。为什么你认为发布一些不做任何事情的代码片段比教程更好?此外,从 Swing 教程中有关“文本组件功能”的部分中,您将找到有关使用文档过滤器的部分,这是在键入文本时过滤/编辑文本的首选方法。或者你甚至可以使用 JFormattedTextField。
    • 我并没有宣称它更好,阅读教程仍然是一个好主意,我也是提高你答案的人。然而,通常你不需要完整的教程来解决一个特定的问题,这是很多噪音。获得针对手头问题量身定制的具体示例并为指出的这个特定案例获得一些好处也非常方便。你不能同意吗?
    • 我从不建议你阅读整个教程,只建议你阅读如何编写 DocumentListener 的部分。您没有发布具体示例,因为您的代码只是一些不可编译的随机行。您的代码不是针对问题量身定制的。一般来说,当教程有一个通用的解决方案时,没有必要用勺子喂答案。这样,它会迫使发布者理解示例,而不仅仅是复制代码而不理解它。 “授人以鱼,终生食。授人以渔,终生食”。
    • 天啊.. 听你自己。我不会在标记词级别反驳,所以这是我最后的话:不是每个人都喜欢“教程链接”类型的答案,对于新手来说,他们有“通用解决方案”而不是一个特定的。本教程不会说“如果有人像您一样,触发对文档的每次更改的搜索,您应该考虑过滤用户输入以避免进行不必要的搜索,这是一种方法!”。我不希望 SO 成为教程注册表。
    • 实际上,我两者都做了。我使用了代码并阅读了教程。并不是说我是外交类型,但我真的很感激这两种帮助。我喜欢快速而肮脏的代码 sn-p 我可以立即粘贴到我的代码中,但我也是最终会阅读 F***ing 手册的类型:)....我已经这样做了,在这个案子。谢谢大家。
    猜你喜欢
    • 2016-10-18
    • 1970-01-01
    • 2012-08-17
    • 1970-01-01
    • 2021-09-20
    • 2018-12-27
    • 1970-01-01
    • 2020-10-15
    • 2015-06-28
    相关资源
    最近更新 更多