قائمة انتظار JMS لتحديث JTable [الآن يتم الحصول على الاستثناء بعد التغييرات]

StackOverflow https://stackoverflow.com/questions/1624679

  •  06-07-2019
  •  | 
  •  

سؤال

أنا أكتب متصفح JMS الخاص بي وأذهلتني تحديث JTable للرسائل من خوادم JMS. لقد حاولت AbstractTableModel TableModelListener لإجراء تحديث Jtable عند إضافة البيانات إلى LinkedList. يعمل هذا السجل أدناه، ولكنه لا يتم تحديثه في الوقت الفعلي، مما يعني أنني أرغب في عرض كل صف تمت إضافته إلى Jtable على الفور عند إضافته من QueueBrowser إلى LinkedList.

لقد قمت بتحديث الكود وفقًا للاقتراحات أدناه.

أفعل شيئا خاطئا؟هل يستطيع أي أحد مساعدتي ؟

QueueBrowser qb = session.createBrowser(q);
MsgTable mt = (MsgTable) queueTable.getModel();
mt.load(qb.getEnumeration(),mt);
qb.close();




 class MsgTable extends AbstractTableModel implements TableModelListener{


      final String[] columnNames = { "#", "Timestamp", "Type", "Mode",
        "Priority" };

      public void setRowSize(){

      }
      LinkedList queueList = new LinkedList();

      public int getRowCount() { if (queueList == null) { return 0; } else { return queueList.size();}}
      public int getColumnCount() { return columnNames.length;}
      public String getColumnName(int column) {return columnNames[column];}

      public Object getValueAt(int row, int column) {
       if(queueList == null){
        return null;
       }
                        Message m = (Message) queueList.get(row);
                        ...  
      }

      void load(Enumeration e,MsgTable mt) {
                         mt.addTableModelListener(this);
        while(e.hasMoreElements()){
         queueList.add(e.nextElement());

        }
                      fireTableDataChanged();   
      }

      Message getMessageAtRow(int row) {
       if (queueList == null)
        return null;
       return ((Message) queueList.get(row));
      }

                @Override
  public void tableChanged(TableModelEvent arg0) {
   // TODO Auto-generated method stub
   fireTableDataChanged();
  }

}

والحصول على هذا الاستثناء.

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError  at javax.swing.table.AbstractTableModel.fireTableRowsInserted(Unknown Source)

هل هذا خطأ؟

هل كانت مفيدة؟

المحلول

على حد علمي، الخاص بك JTable يجب أن يتم التحديث تلقائيًا عند التغيير إلى TableModel يحدث.تحقق من البرنامج التعليمي الشمس على العمل مع الجداول وخاصة القسم على الاستماع لتغييرات البيانات, ، قد يساعد هذا.ومع ذلك، لدي ملاحظتان:

  • أنا لا أفهم حقا getValueAt(int row, int col) طريقة.ألا يجب أن تحصل على رسالة الصف والسمة العمودية للرسالة؟

  • أود أن أضيف أ addRow(...) و addRows(...) ل MsgTable تنفيذ TableModel لتحديث النموذج الداخلي وإطلاق الحدث المناسب.

  • لا تحتاج إلى التنفيذ TableModelListener (لا أستطيع رؤية أي اتصال بـ addTableModelListener(...) على أي حال)

(يحرر:قام OP بتحديث سؤاله برمز جديد لذا أقوم بتحديث إجابتي وفقًا لذلك أدناه.)

لقد قمت بتعديل load(...) التوقيع والنص لإضافة مكالمة إلى addTableModelListener(...) وأعتقد أن كلا التعديلين غير صحيحين.

حول ال addTableModelListener(...), ، تقول الوثائق:

إضافة مستمع إلى القائمة التي يتم إعلامها في كل مرة يحدث فيها تغيير في نموذج البيانات.

وعن مختلف fireFooXxx(...) طُرق:

يخطر جميع المستمعين أنه [حدث تغيير]

لذلك مع التنفيذ التالي لـ a TableModelListener:

@Override
public void tableChanged(TableModelEvent arg0) {
    // TODO Auto-generated method stub
    fireTableDataChanged();
} 

سينتهي بك الأمر بإجراء مكالمات متكررة لا نهائية (يتم إخطار المستمع بتغيير وإطلاق حدث سيخطره مرة أخرى وما إلى ذلك)، ومن هنا java.lang.StackOverflowError.

في الواقع، ما زلت أعتقد أنك لا تحتاج إلى TableModelListener (والطريقة التي تسجل بها ليست صحيحة في IMO، راجع الاستماع لتغييرات البيانات في دروس الشمس).وبالتالي سأقوم بإزالة implements TableModelListener وبدلا من تنفيذ load(...) طريقة مثل هذا:

void load(Enumeration e) {
    while(e.hasMoreElements()) {
        queueList.add(e.nextElement());
    }
    fireTableDataChanged();   
}

نصائح أخرى

هناك نقطتان يجب إضافتهما للنظر فيهما:

  • لك load(Enumeration e) لا تحتاج الطريقة إلى رمي JMSException, ، لأنك تقوم فقط بالتكرار عبر ملف Enumeration.
  • يجب عليك التأكد من أن إطلاق الأحداث يتم داخل EDT.قد يكون هذا بسيطًا مثل إنهاء مكالمتك إلى load في runnable وإسقاطه في SwingUtilities.invokeLater() :

    MsgTable mt = (MsgTable) queueTable.getModel();
    final Enumeration e = qb.getEnumeration();
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            mt.load(e);
        }
    });
    

وطريقة واحدة لغاية الأداء سيكون فقط لاستدعاء fireTableDataChanged () في نهاية الأسلوب تحميل ()، في مقابل بعد تحميل كل سطر.

ومن شأنها أن تساعد.

وأي:

void load(Enumeration e) throws JMSException {
                 while(e.hasMoreElements()){
                         queueList.add(e.nextElement());
                         fireTableDataChanged();
                 }                      
        }

إلى

void load(Enumeration e) throws JMSException {
                 boolean dataAdded = false;
                 while(e.hasMoreElements()){
                         queueList.add(e.nextElement());
                         dataAdded = true;
                     }
                 fireTableDataChanged();

        }

حسنا، وتصميم السليم هو خلق وسيلة addRow (...) الذي يتلقى صف من البيانات وتحديث التخزين الداخلي TableModel الخاص بك. يجب أن هذا الأسلوب ثم استدعاء الأسلوب fileTableRowsInserted (). من طريقة getValueAt () أيضا لا معنى له. وفقا لنموذج الخاص لديك 5 أعمدة البيانات، ولكن لا يمكن ان تحقق المتغير عمود للعودة الكائن العمود المناسب.

ونلقي نظرة على شفرة المصدر من DefaultTableModel أن نرى كيف يمكن لinsertRow () وgetValueAt () قد تكون مشفرة الأسلوب.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top