【问题标题】:need to update variables, main thread or different thread?需要更新变量,主线程还是不同的线程?
【发布时间】:2014-06-05 22:27:42
【问题描述】:

对不起,如果这个问题听起来很愚蠢,我没有编程太久,所以我有这样的新手问题......

我有一个带有一些变量(arrayList、int...)的 JFrame(来自 netBeans 的 JFrame 形式)。经过一个过程,这个变量会发生变化。该过程是通过JCDB驱动程序进行mySQL查询,一些arrayList更新数据,我用它来填充Jtable......等等......

起初(可怜的我)我做了一个 SwingWorker。通过 SwingWorker 构造函数,我传递了这些变量(或多或少大约 6 个变量),并使用它们进行处理和填充表格。

我认为我可以在覆盖的 Done() 方法中更新这些变量的值(我又可怜了),而不仅仅是 GUI 组件。

我从这次失败中学到了很多东西: 1)即使我通过构造函数传递了变量,但这并不意味着它们会在它们来自的地方得到更新。 2) SwingWorker 只能返回 1 个变量,并且可以修改 GUI 组件。

所以,这是我的主要观点,我该如何做我想做的事?我了解到它不能用 SwingWorker 类完成,但是,它怎么能完成呢?

我不想像这样将代码放在鼠标单击事件中,因为它会阻止我的 EDT,而不会通知用户正在发生的事情。

我打算做这样的事情:将代码放在鼠标单击事件中,并显示一个对话框,以便用户知道此时正在发生一个过程。

private void jButton_calcular_rutaMousePressed(java.awt.event.MouseEvent evt) {                                                   
        // BOTON CALCULAR RUTA

        int index = jL_empGeo.getSelectedIndex();

        JOptionPane optionPane = new JOptionPane("Descargando ruta, espere por favor.", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[]{}, null);
        JDialog dialog = new JDialog();
        dialog.setTitle("Descarga");
        dialog.setModalityType(Dialog.DEFAULT_MODALITY_TYPE);

        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);

        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        dialog.setLocation(dim.width / 2 - dialog.getSize().width / 2, dim.height / 2 - dialog.getSize().height / 2);
        dialog.setContentPane(optionPane);

        dialog.pack();

        dialog.setLocationRelativeTo(this);

        dialog.setVisible(true);

        //
        // THE PROCESSING TAKES PLACE HERE
        //
        //
        // mySQL query
        //
        // update arrayLists and variables
        //
        // update GUI components
        //
        //

        dialog.setVisible(false);
    }

这有意义吗?有什么办法可以在不同的线程中进行处理,然后将数组列表和变量返回到主线程中?

提前感谢您的帮助。

编辑

SwingWorker 类

package descargas;

import clases.Empleados;
import clases.InfoPuntoRuta;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;
import java.awt.Dimension;
import java.awt.Image;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
import javax.swing.table.DefaultTableModel;
import maps.java.Geocoding;
import maps.java.Route;
import maps.java.StaticMaps;

public class ActualizarRuta2 extends SwingWorker<Void, Void> {

    int index;
    ArrayList<Empleados> arrayEmpleados;
    ArrayList<InfoPuntoRuta> listaPuntosRuta;
    DefaultTableModel modeloTablaRutas;
    JDialog dialog;
    ArrayList<String> listaIntermedios;
    JLabel jLab_RutaMAP;
    ImageIcon icono;
    int origenInt;
    int destinoInt;
    int destinoMax;

    public ActualizarRuta2(int index, int origenInt, int destinoInt, int destinoMax, ArrayList<Empleados> arrayEmpleados, ArrayList<InfoPuntoRuta> listaPuntosRuta, DefaultTableModel modeloTablaRutas, JDialog dialog, JLabel jLab_RutaMAP) {
        this.index = index;
        this.arrayEmpleados = arrayEmpleados;
        this.listaPuntosRuta = listaPuntosRuta;
        this.modeloTablaRutas = modeloTablaRutas;
        this.dialog = dialog;
        this.jLab_RutaMAP = jLab_RutaMAP;
        this.origenInt = origenInt;
        this.destinoInt = destinoInt;
        this.destinoMax = destinoMax;
    }

    @Override
    protected Void doInBackground() throws Exception {

        listaIntermedios = new ArrayList<String>();

        // recogemos la fecha actual
        DateFormat formatoFecha = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        String dateMIN = formatoFecha.format(cal.getTime()) + " 00:00:01";
        String dateMAX = formatoFecha.format(cal.getTime()) + " 23:59:59";

        // GENERAR MAPA DE LA RUTA DEL DIA
        Connection conexion;
        conexion = conexiondb.ConexionDB.getConnection();
        if (conexion != null) {
            try {
                Statement st;
                ResultSet rs;

                st = (Statement) conexion.createStatement();
                rs = st.executeQuery("SELECT * \n"
                        + "FROM position\n"
                        + "WHERE nombre =  '" + arrayEmpleados.get(index) + "'\n"
                        + "AND position_date BETWEEN '" + dateMIN + "' AND '" + dateMAX + "'\n"
                        + "ORDER BY position_date;");

                // vaciamos la lista
                //listaPuntosRuta.clear();
                //System.out.println(rs.);
                // rellenamos la lista
                rs.beforeFirst();

                while (rs.next()) {
                    InfoPuntoRuta punto = new InfoPuntoRuta(rs.getString("nombre"),
                            rs.getString("position_date"), rs.getDouble("latitud"),
                            rs.getDouble("longitud"));

                    Geocoding ObjGeocod = new Geocoding();
                    ArrayList<String> resultadoCI = ObjGeocod.getAddress(punto.getLatitud(), punto.getLongitud());
                    String direccion = resultadoCI.get(0);

                    punto.setDireccion(direccion);

                    listaIntermedios.add(direccion);
                    listaPuntosRuta.add(punto);
                }

                //
                // DESCARGAR MAPA RUTA
                //
                int posicionUltimo = (listaIntermedios.size()) - 1;
                String origen, destino;

                ArrayList<String> waypoints = new ArrayList<String>();
                if (listaIntermedios.size() < 10) {
                    origen = listaIntermedios.get(0);
                    destino = listaIntermedios.get(posicionUltimo);
                    for (int i = 1; i < posicionUltimo; i++) {
                        waypoints.add(listaIntermedios.get(i));
                    }
                } else {
                    origen = listaIntermedios.get(0);
                    destino = listaIntermedios.get(9);
                    for (int i = 1; i < 9; i++) {
                        waypoints.add(listaIntermedios.get(i));
                    }
                }

//                ArrayList<String> prueba = new ArrayList<String>();
//                prueba.add("coruña avenida finisterre 65");
//                prueba.add("coruña ronda de outeiro 125");
//                prueba.add("coruña avenida del ejercito 20");
                Route ObjRout = new Route();

                String[][] resultadoRuta = ObjRout.getRoute(origen, destino, waypoints, Boolean.TRUE, Route.mode.driving, Route.avoids.nothing);
                //String[][] resultadoRuta = ObjRout.getRoute("Madrid", "Barcelona", prueba, Boolean.TRUE, Route.mode.driving, Route.avoids.nothing);
//                String[][] resultadoRuta = ObjRout.getRoute("coruña virrey ossorio 25", "pla y cancela, 16, 15005 la coruña, españa", prueba, Boolean.TRUE, Route.mode.driving, Route.avoids.nothing);
                String polylinea = ObjRout.getGeneralPolyline();
                StaticMaps ObjStatMap = new StaticMaps();
                Image resultadoMapa = ObjStatMap.getStaticMapRoute(new Dimension(585, 405), 1, StaticMaps.Format.png, StaticMaps.Maptype.hybrid, polylinea);
                icono = new ImageIcon(resultadoMapa);

                // RELLENAR TABLA DETALLES DE LA RUTA
                modeloTablaRutas.setRowCount(0);

            } catch (SQLException | UnsupportedEncodingException | MalformedURLException ex) {
                Logger.getLogger(ActualizarRuta2.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    conexion.close();
                } catch (SQLException ex) {
                    Logger.getLogger(ActualizarRuta2.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return null;
    }

    @Override
    protected void done() {

        dialog.dispose();

        // RELLENAR TABLA DETALLES DE LA RUTA
        for (InfoPuntoRuta p : listaPuntosRuta) {
            modeloTablaRutas.addRow(new Object[]{
                p.getNombre(), p.getFecha(), p.getDireccion()});
        }

        // ponemos la imagen de la ruta
        jLab_RutaMAP.setIcon(icono);

        //
        listaIntermedios.clear();

//        listaPuntosRuta.clear();
        origenInt = 0;
        destinoMax = listaPuntosRuta.size() - 1;
        if (destinoMax < 9) {
            destinoInt = destinoMax;
        } else {
            destinoInt = 9;
        }

    }

}

我调用 SwingWorker 的鼠标事件

private void jButton_calcular_rutaMousePressed(java.awt.event.MouseEvent evt) {                                                   
        // BOTON CALCULAR RUTA

        int index = jL_empGeo.getSelectedIndex();

        JOptionPane optionPane = new JOptionPane("Descargando ruta, espere por favor.", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[]{}, null);
        JDialog dialog = new JDialog();
        dialog.setTitle("Descarga");
        dialog.setModalityType(Dialog.DEFAULT_MODALITY_TYPE);

        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);

        Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
        dialog.setLocation(dim.width / 2 - dialog.getSize().width / 2, dim.height / 2 - dialog.getSize().height / 2);
        dialog.setContentPane(optionPane);

        dialog.pack();

        dialog.setLocationRelativeTo(this);

        listaPuntosRuta.clear();
        modeloTablaRutas.setRowCount(0);
        ActualizarRuta2 task = new ActualizarRuta2(index, origenInt, destinoInt, destinoMax, arrayEmpleados, listaPuntosRuta, modeloTablaRutas, dialog, jLab_RutaMAP);
        task.execute();

        dialog.setVisible(true);

    }     

【问题讨论】:

  • 您是否介意也包括您的(失败的)SwingWorker 示例
  • 是的,它现在包括在内 :)
  • 我认为您过于关注属性,而没有足够关注您在 OO 环境中运行的事实。也就是说,您应该能够向SwingWorker 提供足够的信息来完成它的工作,并且一旦完成,它应该能够提供您需要更新自己的信息。目前,工作人员正在尝试执行查询和更新 UI,它具有交叉用途。 @ThomasW 提出了您需要开始的基本想法。

标签: java multithreading swing swingworker


【解决方案1】:

您需要从“SwingWorker”返回到 GUI。 Java 参数是按值传递——因此,您需要某种形式的值持有者

从 Observable 创建一个“数据 bean”可能是最简单的方法。

public class QueryResults extends Observable {
    protected List<SomeItem> itemList;
    // getters and setters.
}

从您的 SwingWorker 中,您需要存储结果并通知观察者。通知必须在事件调度线程上完成,并且 javax.swing.SwingWorker 提供了在 EDT 上调用 SwingWorker.done() 的内置功能。

我使用“Void”类型作为“结果”,因为数据持有者已经存在并且我们只是将数据加载到其中。 UI 应该已经绑定(并观察)它。像这样的:

public class QueryWorker<Void,Void> extends SwingWorker {
    protected QueryResults holder;
    public QueryWorker (QueryResults holder) {
        this.holder = holder;  // keep the holder & put data into it.
    }

    @Override
    protected Void doInBackground() {
        // run the query..
    }
    @Override
    protected void done() {
        holder.notifyObservers();
    }
}

这是一个简化的示例。例如,它忽略了 UI 想要在加载过程中读取 result-hodler(用于显示刷新)的可能性。您的替代方法是将 data bean 与 bean 的 observable 引用 分开。

【讨论】:

    【解决方案2】:

    有没有办法在不同的线程中进行处理,然后将数组列表和变量返回主线程?

    是的,有。您可以(并且可能应该)在 dialog.setVisible(true) 之后使用

    启动一个新线程
    new Thread() {
        @Override
        public void run() {
            getNewValues();
        }
    }.start();
    

    这项工作完成后,您可以从您的“工作者”线程调用

    EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            //overwrite existing variables, update GUI elements, trigger repaints, etc.
            dialog.setVisible(false);
        }
    };
    

    但是,您应该始终尝试将数据与视图分开。这意味着:您可能不应该从您的工作线程调用这些操作,而是实现observer pattern 以通知您的 GUI 数据已更改并自行刷新。

    【讨论】:

    • 非常感谢您的快速回答。我明天会试试,因为在我的国家已经很晚了。
    • 好答案,快速检查文档确认 javax.swing.SwingWorker 中的 SwingWorker.done() 将自动在 EDT 中运行.. 所以不需要显式的 invokeLater()。不过,最好了解它的工作原理。
    • getNewValues() 方法是什么? swingWorker?
    • 没有。这将是 SwingWorker 的 content 并因此替换它。我倾向于与 SwingWorker 之类的工具保持距离,因为任何称为“Swing”的东西可能永远不会触及我的数据。当谈到视图和数据之间的关注点分离时,我有点偏执;)
    • 如果我在dialog.setVisible(true)之后启动线程,则线程永远不会执行
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多