sábado, 27 de septiembre de 2014

Java 8 and the Two Worlds for Desktop-Based Applications: JavaFX - Swing

On last days I was trying and playing seriously with JavaFX 2 (also called only Java FX) because I'm really interested in how to get the maximum advantages for new apps on this platform.

While I was trying JavaFX, I found three main interesting areas:
  1. Application design approaches: The three main approaches to develop Java-FX based applications.
  2. Datasets display: The new approach to display data into tables or trees, because this is achieved in a very different way from Swing.
  3. Multithreading/Hard-tasks-processing: The basics to impement large/hard tasks that must be "observed" from the graphical user interface (using the JavaFX controls).
On next posts I will explain in detail all the above points.

Today, a considerable information amount about the new JavaFX exists on the web, including the official tutorials and documents from Oracle.

There is not doubts about JavaFX is the best adoption choice for new desktop-based developments under the Java Platform. From my point of view, Java FX is amazing and today it is the oficially recommended  platform by Oracle for new desktop-based applications. But... wait... this is not time to forget or isolate it from his ancestor: Swing.

Although JavaFX offers a better user experience that Swing does, it has a lack of custom controls that are necessary in many applications. At this moment, I could identify a couple of them: docking frameworks and rich text editors. This is normal in all new platforms. More custom and advanced components will be released over the time. But, what can you do if you need that components for your today projects? Well... the answer is very simple and you have to choose one of two ways:
  1. Develop your custom JavaFX components.
  2. Integrate certain-well-tested Swing components.
Both approaches have advantages and disadvantages. For example, taking the first way means that you don't "get out" of the JavaFX world. However, the required effort and time to achieve the goal could be expensive. On the other way, if the desired component exists (this is highly probably) in Swing, you can consider to use it into your JavaFX application. But, you must be careful and take into account that you are mixing two different worlds: The Swing World and the JavaFX World. This is not imposible and with appropiate design approaches you can achieve the goal with success.

Choosing one approach is a trade-off between time-effort-skills-platform constraints. But, in many cases, you could take the second way under this conditions:
  1. The required custom component does not exists on the oficial JavaFX bundles.
  2. The required custom component does not exists as a JavaFX-third part library or the source code to create it is not available.
  3. You do not have enough knowledgment or development skills about the JavaFX platform.
  4. The required custom component exists on Swing and it is well probed that it's performance is correct.
  5. You have moderated knowledgment and skills on Java Swing.
In order to ilustrate this approach I will use an application that I developed first on Swing and recently in JavaFX: JGreep / JGreepFX.

JGreep is an old program that I developed on top of the Swing framework some years ago. It's a very simple word-finder that acts over plain text documents. In order to use it, you start specifying a directory. Then, all files contained into the directory and subdirectories are listed into a table (a JTable component). Next, you type a word and the application starts to search the word occurrence inside of the listed text type files.

Next table shows you the JGreep/JgreepFX application, one using Swing and the other using JavaFX:

JGreep JGreepFX
Main Application Window:
Listing files process:


Search process:


Search results:



As you can see in the above pictures, the same application was builded on top of Swing and on top of JavaFX. The look and feel used in Swing is the PGS Look And Feel from Pagosoft.

At this point, you can appreciate some interesting appearance features on both applications. Now, lets to see another feature of the original JGreep: Open and display plain text files with a list of line numbers where the word occurences were found. The next picture shows a screenshot of a plain text file loaded with JGreep:


The JGreep's text viewer displays the file's contents in rich text. This is achieved using the amazing RSyntaxtTextArea Swing component from fifesoft (http://fifesoft.com/rsyntaxtextarea/). But... for JavaFX, today is not a complete rich text editor. Searching in google I found only an early development intended to develop this component: http://github.com/TomasMikula/RichTextFX. However, at this moment, only is available the basic framework to support regexp and you must do by hand the rest of the work.

Then, my approach to have a rich text editor in JGreepFX was using the Swing-based RSyntaxtTextArea. The result is:


The obtained result was very good and the appearance between the two frameworks looks similar. I used an additional trick: The document viewer in JGreepFX uses the Weblaf Look and Feel.This look and feel is very close (but not equals) in appearance to the standard Modena theme in JavaFX.

The most important when you are mixing JavaFX and Swing is: "Never perform tasks of each other out of their own thread". Remember: Tasks related with Swing controls are performed under the Swing's Event Dispatch Thread or EDT, while tasks related with JavaFX controls are performed under the JavaFX's Platform Application Thread.

If you want learn more about Swing's EDT I reommend this links:
  1. http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html (English)
  2. http://chuwiki.chuidiang.org/index.php?title=El_EDT_(Event_Dispatch_Thread)_de_Java (Spanish)
If you want learn more about the JavaFX PAT I recommend you to start with the Oracle's docs: http://docs.oracle.com/javafx/2/api/javafx/application/Platform.html.

And, this document about integrating JavaFX and Swing is a "must-read" to successfull achieve the goal: http://docs.oracle.com/javafx/2/swing/swing-fx-interoperability.htm.

To see this concepts in action, you can download the JGreep and JGreepFX, including their source codes from this locations:

http://sourceforge.net/projects/jgreep/

http://sourceforge.net/projects/jgreepfx/

Download the codes and start playing with it. I recommend you to use a Java versión 1.8.20+ because earlier version has a lack of bugs and the JavaFX applications throws a lot of exceptions, specially when you use the TableView control.

Para leer una versión en español de este post, ve a este enlace.

+ Miguel Angel

Java 8: El nuevo y el viejo mundo en el desarrollo de aplicaciones de escritorio.

Durante estos días pasados he estado aprendiendo y practicando con la plataforma JavaFX 2 (conocida solo como JavaFX). Realmente estoy interesado en aprender los conceptos claves de la plataforma para poder explotar al máximo las prestaciones que ofrece.

Durante mis días de práctica encontré tres áreas prácticas de interés:
  1. Enfoques para el diseño de aplicaciones: En este punto, encontré que existen tres modelos o formas básicas para desarrollar aplicaciones en JavaFX.
  2. Despliegue de datos dentro de la aplicación: JavaFX introduce un cambio extremadamente radical, en comparación de su antecesor Swing, en la forma en que se construyen las tablas y se les asignan los datos que deberán ser visualizados.
  3. Procesamiento de tareas con múltiples hilos: JavaFX tiene sus propias clases que permiten a una aplicación ejecutar tareas pesadas a la vez que puede "observar" su progreso y reflejarlo en los controles de la intefaz de usuario (basada en JavaFX).
En posts posteriores iré explicando a detalle cada uno de los puntos anteriores.

Actualmente, en internet existe una cantidad de información considerable sobre JavaFX. Basta con realizar una búsqueda en google o ver la documentación oficial de Oracle.

Tampoco hay duda de que JavaFX es la plataforma recomendada para el desarrollo de nuevas aplicaciones de escritorio. Desde mi punto de vista, las aplicaciones hechas con JavaFX, en comparación con Swing, ofrecen una mejor experiencia de usuario, además de un modelo de desarrollo simplificado y elegante para el manejo de eventos en los controles por parte de los desarrolladores. Sin embargo, considero que aun no es tiempo de aislarla ni de olvidar a Swing.

La plataforma JavaFX, al día de hoy, tiene carencia de muchos componentes personalizados que sí están disponibles en Swing. Por ejemplo, un framework propio de JavaFX para componentes "acomodables" ó "dockings". Otro ejemplo es la existencia de un control JavaFX puro que permita el despliegue de texto enriquecido. Esto es normal y totalmente entendible cuando una plataforma nueva se pone a disposición de los usuarios y desarrolladores. Con el paso del tiempo, estarán disponibles más componentes personalizados y avanzados. Sin embargo, ¿que podemos hacer si necesitamos esos componentes en nuestros proyectos actuales bajo JavaFX? Bueno, la respuesta parece ser bastante simple y solo disponemos de dos opciones:

  1. Desarrollar tu propio componente utilizando JavaFX.
  2. Integrar componentes Swing existentes que ya están bien definidos y probados.
Ambas opciones tienen sus ventajas y desventajas. Por ejemplo, decantarse por la primera opción tiene la ventaja de que siempre permaneceremos dentro del entorno de JavaFX. Sin embargo, el esfuerzo y tiempo requeridos para desarrollarlo puede ser considerable. 

Por otra parte, si el componente personalizado que se requiere existe en Swing (lo cual es altamente probable), entonces se podría considerar seriamente su utilización dentro de la aplicación JavaFX. Adicionalmente, se debe tener especial cuidado al mezclar ambos ambientes para lograr tener un buen resultado.

La elección de un enfoque u otro dependerá de los factores de tiempo, esfuerzo, habilidades técnicas y, sus propias restricciones. Sin embargo, en muchos de los casos yo recomendaría elegir la segunda opción, bajo las siguientes condiciones:

  1. El componente personalizado que se requiere no existe como parte oficial de la Plataforma JavaFX.
  2. El componente personalizado que se requiere no existe dentro de una librería JavaFX de terceros ni tampoco existe algún código fuente que pueda crearlo.
  3. No se tiene mucho conocimiento sobre JavaFX.
  4. El componente personalizado requerido existe en Swing y está bien probado que su funcionamiento y desempeño son correctos.
  5. Tienes un conocimiento básico o intermedio acerca de Swing.
Para explicar un poco más sobre este enfoque, utilizaré de ejemplo una aplicación que desarrollé hace algunos años, incialmente en Swing y en estos días la reprogramé sobre JavaFX.

El nombre de la aplicación es JGreep  (JGreepFX en JavaFX) y no es más que una aplicación simple que busca palabras dentro de archivos de texto plano. Basta con definir un directorio para que la aplicación liste (dentro de un JTable) todos los archivos que encuentra tanto en el mismo directorio como en sus subdirectorios. Posteriormente, el usuario escribe una palabra y el programa busca sus ocurrencias dentro del contenido de cada archivo.

La siguiente tabla muestra la apariencia de la aplicación tanto en Java Swing como en JavaFX.

JGreepJGreepFX
Ventana principal de la aplicación:
Proceso de búsqueda y listado de archivos:


Proceso de búsqueda de palabras:


Resultados de búsqueda:


Como se puede observar en las imágenes anteriores, existen tanto diferencias como similitudes significativas entre ambas. El Look And Feel utilizado en la aplicación Swing es  PGS Look And Feel, de Pagosoft. Ahora, veamos una característica interesante del JGreep original: Abrir y desplegar el contenido de los archivos de texto plano, conteniendo una lista de los números de renglón donde aparece la palabra buscada. La siguiente imagen muestra la apariencia de esta interfaz:


La interfaz anterior muestra el contenido del archivo en formato de texto enriquecido, ya que resalta las palabras reservadas dependiendo del tipo de archivos, por ejemplo, .java, .sql, .xml, .html, entre otros. Para lograr el aspecto elaborado del visor de contenido de los archivos, utilicé un componente llamado RSyntaxTextArea de la empresa fifesoft: http://fifesoft.com/rsyntaxtextarea/. Sin embargo, en JavaFX no existe un componente similar al día de hoy, que permita mostrar textos enriquecidos de forma fácil, ya que con el componente RSyntaxTextArea solo basta definir los tokens o palabras reservadas y su color. Buscando en google, encontré solo una entrada acerca de un componente para tal efecto. Por ahora, el proyecto se encuentra en una etapa temprana y el desarrollador debe definir los tokens y los rangos de texto a los que se les aplicará el estilo. Esto, como se puede suponer, esto representa un esfuerzo considerable si se toma en cuenta que se tienen que definir todas las palabras que pudieran ser reservadas en los distintos tipos de archivos, como es el caso de JGreep.

Por tal motivo, decidí utilizar el editor de texto rico Swing, RSyntaxTextArea dentro de la aplicación JGreepFX, basada por supuesto, en JavaFX. Y esto fue lo que obtuve:



Como se puede observar, el resultado fue muy bueno y la apariencia de los dos frameworks (Swing-JavaFX) fue muy parecida. Para esto, utilicé un truco adicional: apliqué el Look and Feel WebLaF. Este look and feel es muy parecido, más no igual, al estilo por defecto que tienen las aplicaciones JavaFX, denominado Modena.

Para terminar este post, debo mencionar una restricción muy importante al mezclar los entornosSwing y JavaFX: Nunca realizar tareas de un entorno dentro del hilo de eventos del otro. Recuerda: Las tareas relacionadas con la interacción de controles Swing deben realizarse dentro de su propio Event Dispatch Thread también denominado EDT o simplemente Hilo Swing. De igual forma, las tareas relacionadas con la interacción de controles JavaFX deben realizarse dentro del JavaFX Platform Application Thread o Hilo de la Plataforma de la Aplicación.

Si quieres aprender más sobre el EDT de Swing puedes ir a estos enlaces:

  1. http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html (Inglés)
  2. http://chuwiki.chuidiang.org/index.php?title=El_EDT_(Event_Dispatch_Thread)_de_Java (Español)
Si deseas aprender más sobre el JavaFX Platform Application Thread, te recomiendo comenzar con la documentación oficial de Oracle: http://docs.oracle.com/javafx/2/api/javafx/application/Platform.html.

Y, para integrar Swing y JavaFX con éxito, la lectura de este documento es obligada: http://docs.oracle.com/javafx/2/swing/swing-fx-interoperability.htm.

Si quieres ver estos conceptos "en acción", puedes descargar las aplicaciones JGreep y JGreepFX, incluyendo sus códigos fuente, en estos enlaces:

http://sourceforge.net/projects/jgreep/

http://sourceforge.net/projects/jgreepfx/

Recuerda descargar también los códigos fuente y practicar con ellos. De preferencia utiliza una versión de Java Mayor o igual a la 1.8.20, ya que en versiones anteriores, existen muchos bugs que causan innumerables excepciones en las aplicaciones javaFX, especialmente al utilizar el TableView.

+ Miguel Angel


jueves, 18 de septiembre de 2014

SQL Data Workshop v.0.8.6.r1 released!

A few hours ago, the new version 0.8.6.r1 of SQL Data Workshop was available on the sourceforge site.

 The "r1" in this version means "revision 1" because some important bugs were corrected in this version.


 Major changes include:

  • SQL Server Visual Editor issue was corrected.
  • Quick search over query results was implemented.
  • Now is posible load and save connection settings files in your storage drives and devices.
  • Connection dialog now displays a connection hint for each DBMS.
  • Aditional JDBC Drivers were added. Now is posible connect to CSV Files and Oracle-Thin-Client
  • Some icons were changed.
  • Minor issues was corrected.
Here some screenshots of this new version:

Improved Connection dialog.

Visual Query Editor minor issues corrected.

Fast-Query Results Search mechanism was implemented.
Also, a first-fast site attempt was designed. You can visit and leave your comments here: http://sqldw.sourceforge.net.

Direct download link is here: http://sourceforge.net/projects/sqldw/.

Greetings!

+ Miguel Angel

jueves, 21 de agosto de 2014

SQL Data Workshop 0.8.7 0.8.6 is now released!

Changes include:
  • Visual Query Builder is now based on SQLeo 2014.07.rc1
  • Visual Queries now are builded by drag and drop table and view objects directly from the databases tree general panel.
  • Improved integration of SQLeo with SQL Data Workshop
  • Query pagination was implemented. This is done using the native dialect for each DBMS
  • Query results table and fields metadata were improved. They uses too a monospaced font in order to provide more clear read.
  • Data Analysis Project module was turned off until more and better features are implemented.
  • Toolbars were rearranged.
  • Aditional Drivers were added.
  • The Driver Specification File was improved by adding native dialect for pagination in each DBMS that supports it.
  • Export query data to text file now allows to the user to specify custom fields delimiters.
  • Application is now based on Java 8 and it is ready to use JavaFX features in next releases.
Next minor versión (0.8.6.1) will include:
  • Repair minor errors on current version
  • Add a fast-search feature that acts over the query results.
  • Implement some charts based on JavaFX
Here are some pictures of this new version

Visual query designer is better integrated:


Query results looks better:

Paginated results using native DBMS/SQL dialect:

You can download it from: http://sourceforge.net/projects/sqldw/

Greetings!


sábado, 5 de julio de 2014

Using webcam in your Java Applications without pain.

When you need to implement webcam access in your Java applications, the first thing to do is perform a google search: http://www.google.com.mx/webhp?q=java%20webcam&gws_rd=ssl#q=java+webcam

With that, a huge amount of results are found by the search engine. However, things can be confusing in the begining because a wide variety of methods to achieve the goal are described.

Luckly, I found a very easy method to achieve the goal in this blog: http://www.sleepingdumpling.com/blog/download/jvideoinput/. The method described by the author was very easy to implement compared with other solutions.

Based in the above description, I was able to wrote a java library in order to get access to webcam in desktop Java apps (swing/JavaFX) avoiding me and others to write a lot of repetitive code simplifying the work. You can download the library from sourceforge.

Swing example usage:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
    import org.grios.swing.jwebcam.JWebCamSimple;

    public class Test extends javax.swing.JFrame
    {
        public Test()
        {
            String[] devices = null;
            initComponents();
            jwcs = new JWebCamSimple();

            try
            {
                devices = JWebCamSimple.getDeviceNames();
                for (String s : devices)
                    jComboBox1.addItem(s);
            } 
            catch (Exception e)
            {
                e.printStackTrace();
                System.exit(0);
            }
        }
        private void initComponents()
        {
            jLabel1 = new javax.swing.JLabel();
            jComboBox1 = new javax.swing.JComboBox();
            jButton1 = new javax.swing.JButton();
            jDesktopPane1 = new javax.swing.JDesktopPane();
            jInternalFrame1 = new javax.swing.JInternalFrame();
            jLabel2 = new javax.swing.JLabel();
            jButton2 = new javax.swing.JButton();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

            jLabel1.setText("Available Devices:");

            jButton1.setText("Start");
            jButton1.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    jButton1ActionPerformed(evt);
                }
            });

            jDesktopPane1.setBackground(new java.awt.Color(255, 255, 255));

            jInternalFrame1.setMaximizable(true);
            jInternalFrame1.setResizable(true);
            jInternalFrame1.setTitle("No Device");
            jInternalFrame1.setVisible(true);

            jLabel2.setBackground(new java.awt.Color(255, 255, 255));
            jLabel2.setOpaque(true);
            jInternalFrame1.getContentPane().add(jLabel2, java.awt.BorderLayout.CENTER);

            jDesktopPane1.add(jInternalFrame1);
            jInternalFrame1.setBounds(10, 11, 160, 162);

            jButton2.setText("Stop");
            jButton2.addActionListener(new java.awt.event.ActionListener()
            {
                public void actionPerformed(java.awt.event.ActionEvent evt)
                {
                    jButton2ActionPerformed(evt);
                }
            });

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addComponent(jLabel1)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, 188, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(jButton1)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(jButton2)
                    .addContainerGap(67, Short.MAX_VALUE))
                .addComponent(jDesktopPane1)
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addContainerGap()
                    .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                        .addComponent(jLabel1)
                        .addComponent(jComboBox1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addComponent(jButton1)
                        .addComponent(jButton2))
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(jDesktopPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE))
            );

            setBounds(0, 0, 496, 339);
        }            

        private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)                                         
        {                                             
            try
            {
                jComboBox1.setEnabled(false);
                jButton1.setEnabled(false);
                jwcs.start(jComboBox1.getSelectedItem().toString(), jLabel2);

            } 
            catch (Exception e)
            {
                e.printStackTrace();
                System.exit(0);
            }
        }                                        

        private void jButton2ActionPerformed(java.awt.event.ActionEvent evt)                                         
        {                                             
            if (jwcs.isRunning())
                jwcs.stop();            

            jButton1.setEnabled(true);
            jComboBox1.setEnabled(true);
        }                                        

        public static void main(String args[])
        {
                    try
                    {
                            javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
                    }
                    catch (Exception ex)
                    {
                    }
            java.awt.EventQueue.invokeLater(new Runnable()
            {
                public void run()
                {
                    new Test().setVisible(true);
                }
            });
        }

        private javax.swing.JButton jButton1;
        private javax.swing.JButton jButton2;
        private javax.swing.JComboBox jComboBox1;
        private javax.swing.JDesktopPane jDesktopPane1;
        private javax.swing.JInternalFrame jInternalFrame1;
        private javax.swing.JLabel jLabel1;
        private javax.swing.JLabel jLabel2;    
        JWebCamSimple jwcs;
    }

On the above code, in line 151 we are declaring  a JWebCamSimple object named jwcs. With JWebCamSimple we will able to play our web cam after of create an instance of it (line 9).
Finally, you can start the webcam calling to start() (line 107) method by passing two arguments:
  • The Device Name, specified as a String value.
  • The Swing component (JComponent) where the webcam video will be displayed. The most easy solution is passing a JLabel object.
For the device name, you sould let the user to select the video device. In above example, this is done firstly on lines 13-15, where the program ask for the video devices available (line 13) and after, a JComboBox object is filled with each found device's name (lines 14 and 15).

And a JavaFX example:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
        import javafx.application.Application;
        import javafx.collections.FXCollections;
        import javafx.geometry.Insets;
        import javafx.scene.Scene;
        import javafx.scene.control.Button;
        import javafx.scene.control.ComboBox;
        import javafx.scene.control.Label;
        import javafx.scene.image.ImageView;
        import javafx.scene.layout.BorderPane;
        import javafx.scene.layout.ColumnConstraints;
        import javafx.scene.layout.GridPane;
        import javafx.scene.layout.Priority;
        import javafx.scene.layout.RowConstraints;
        import javafx.stage.Stage;
        import org.grios.jwebcam.fx.FXWebCamSimple;

        public class Test extends Application
        {   
            Scene scene;
            BorderPane mainPane;
            GridPane topPane;
            ComboBox<String> cmbVideoDevices;
            Label lblVideoDevices;
            ImageView imgvDisplay;
            Button btnStartDevice;
            Button btnStopDevice;

            FXWebCamSimple fxWebCam;   

           Override
            public void start(Stage primaryStage) throws Exception
            {
                initComponents();

                scene = new Scene(mainPane);
                primaryStage.setWidth(480);
                primaryStage.setHeight(240);
                primaryStage.setTitle("JWebCamFX Demo");
                primaryStage.setScene(scene);
                primaryStage.setOnCloseRequest((evt) -&gt;
                {
                    System.exit(0);
                });
                primaryStage.show();

                fxWebCam = new FXWebCamSimple();

            }

            private void initComponents()
            {
                lblVideoDevices = new Label("Available Video Devices:");
                cmbVideoDevices = new ComboBox<String>(FXCollections.observableArrayList());
                btnStartDevice = new Button("Start");
                btnStopDevice = new Button("Stop");
                imgvDisplay = new ImageView();        

                lblVideoDevices.setPrefSize(135, 21);
                cmbVideoDevices.setPrefSize(140, 21);
                btnStartDevice.setPrefSize(50, 21);
                btnStopDevice.setPrefSize(50, 21);

                btnStartDevice.setOnAction((evt) -&gt; 
                {

                    try
                    {
                        btnStartDevice.setDisable(true);
                        lblVideoDevices.setDisable(true);
                        cmbVideoDevices.setDisable(true);

                        fxWebCam.start(cmbVideoDevices.getSelectionModel().getSelectedItem(), imgvDisplay);
                    } 
                    catch (Exception e)
                    {
                        e.printStackTrace();
                        System.exit(0);
                    }
                });

                btnStopDevice.setOnAction((evt) -&gt;
                {
                    try
                    {
                        fxWebCam.stop();                
                        btnStartDevice.setDisable(false);
                        lblVideoDevices.setDisable(false);
                        cmbVideoDevices.setDisable(false);
                    } 
                    catch (Exception e)
                    {
                        e.printStackTrace();
                        System.exit(0);
                    }
                });


                fillComboBox();

                topPane = new GridPane();
                topPane.setPadding(new Insets(5));
                topPane.setHgap(10);
                topPane.setVgap(10);
                topPane.add(lblVideoDevices, 0, 0);
                topPane.add(cmbVideoDevices, 1, 0);
                topPane.add(btnStartDevice, 2, 0);
                topPane.add(btnStopDevice, 3, 0);

                mainPane = new BorderPane();
                imgvDisplay.fitWidthProperty().bind(mainPane.widthProperty());
                imgvDisplay.fitHeightProperty().bind(mainPane.heightProperty());
                imgvDisplay.setSmooth(true);
                imgvDisplay.setCache(true);
                mainPane.setCenter(imgvDisplay);
                mainPane.setTop(topPane);
            }

            private void fillComboBox()
            {
                try
                {
                    cmbVideoDevices.getItems().clear();
                    for (String str : FXWebCamSimple.getDeviceNames())
                        cmbVideoDevices.getItems().add(str);
                    if (cmbVideoDevices.getItems().size() &gt; 0)
                        cmbVideoDevices.getSelectionModel().selectFirst();
                } 
                catch (Exception e)
                {
                    e.printStackTrace();
                    System.exit(0);
                }
            }

            public static void main(String[] args)
            {
                launch(args);
            }
        }

Good luck!

+ Grios

domingo, 1 de diciembre de 2013

SQL Data Workshop - First version (0.8.5) released

Approximately, eighteen months ago, I began to work with SQL queries that returned large data amounts. The database server was SQL Server 2005 and I used the SQL Server Management Studio 2005 and 2008 with no successful results.

Then, in my free times I developed a small application using java and swing in order to execute those queries. This time, I have success. This is a screenshot of the very earlier versions with it’s initial name “Bringer Query Executor”:





Over time, I was adding more features. At the beginning of this year, I realized that I could share this application with more people if I made some adjusts and improvements to the GUI (graphical user interface) and correct some errors and bugs.

For the GUI, I began using the flamingo ribbon bar but, I felt the application's performance very poor. Interacting with controls and it's response was not good. Additionally, I do not found some way to remove the ribbon’s upper toolbar when using other look and feel that substance.

This is a screenshot of the application using the native look and feel under Windows 7 Operating System:



The same application with substance look and feel:



But, using the substance look and feel, sometimes the application freezes unexpectedly or throws a Java Heap Memory Exception.

Then, I decided to leave the GUI ribbon-based approach and tried the jidesoft framework (http://www.jidesoft.com). This time, the application has a very good performance.
The latest feature that I added it was a visual query engine. I implemented this engine based on the SQL Leonardo application (https://sourceforge.net/projects/sqleo/).

Finally, I host it in sourceforge: http://sourceforge.net/projects/sqldw/.

Here are some screenshots.

This is the main application window running on Windows 7:

 The Visual Query Builder running on Ubuntu Linux:

 The results populated by the query:

A correlation matrix calculated using values retrieved by a query:

A grouped histogram chart using the integrated charting feature:

A scatter chart using a short dataset:

A scientific scatter chart using a large dataset:


And finaly, a spider-web chart:


There are some of the program's features. But, there are more to explore. 

At this moment, last released version is 0.8.5.2. 

Changes in 0.8.5.2 compared with 0.8.5.1, are related only with certain parts of code in order to provide back compatibility with jre 1.6.x. This changes were made because many users ask me for compatibility at least with jdk 1.6.x.

I'm planning improvements and major changes for the next version. For example, I'm thinking seriously to write some parts using java fx, including css stylying in order to integrate uniformly the jide native swing look and feel with the new javafx controls. Another change includes too quit the current statistical core and replace it by the apache commons math library since it is more robust and efficient for nearly all tasks. But, until all this changes are commited, I hope that you enjoy work with this current version (0.8.5.x).

Thanks to +Dolores Juárez by support with the project documentation. Now, she is in charge for the user experience improvements.

Greetings!

+ M. Angel

domingo, 5 de febrero de 2012

Primera versión de JGreep

A través de esta entrada quiero compartir con la comunidad una pequeña herramienta que desarrollé hace tiempo para buscar palabras dentro de archivos de texto. No tengo la menor duda de que actualmente puedo encontrar casi infinitas opciones "googleando". Sin embargo, cuando tuve la necesidad de esas herramientas, curiosamente no encontré una que me agradara. Lo que más extrañaba en ese momento era el comando "greep" de linux ya que soy usuario de windows principalmente. Así que comencé a desarrollar una herramienta para lo que necesitaba. Con el tiempo, añadí un par de funcionalidades, corregí algunos errores de programación, le dí una "pintada" más "mona"  a la interfaz y la publiqué en la red con todo y código fuente por si a alguien más pudiera serle útil. He aquí un pantallazo de la interfaz de la herramienta:



Una vez explicado el génesis de este proyecto, os comento de la utilidad. Esta herramienta está diseñada para buscar palabras dentro de archivos de texto plano. Esta construida completamente en Java. Para utilizarla simplemente hay que seleccionar un directorio y la aplicación carga todos los archivos encontrados en ese directorio con la opción de cargar archivos en directorios anidados:

Una vez que la carga de archivos termina, se escribe el término o palabra que se desea buscar y la herramienta comienza a realizar una búsqueda de esa palabra dentro de los archivos previamente cargados:

Adicionalmente, la aplicación permite ordenar los datos por cualquier campo así como también el uso de filtros para mostrar solo aquellos archivos que coinciden con un criterio de búsqueda:

Y como no podía faltar, permite visualizar el contenido de los archivos junto con las ocurrencias de la palabra buscada:

Finalmente, comentar que tiene soporte para el idioma español, inglés y alemán así como también agradecer a la gente de desarrollo de las librerías que utilicé en la herramienta:

Infonode Docking Windows

RSyntaxTextArea

A continuación os comparto la página del proyecto en sourceforge:

Quedo a la espera de vuestros comentarios y sugerencias.

Saludos y hasta pronto en la siguiente entrega, que espero no tarde tanto.