0

Disclaimers:

Special KDB knowledge is unneccessary for this.
I realise there are some similar questions but none of the solutions have worked for me. I'm in a situation slightly unique to the similar questions you might find on here.
I apologize if I've missed any information here you would need. Ask and I'll give you as much info as you need.

I have a Java application with 3 classes, but only 2 are relevant because 3rd is an API created by kx called 'Fusion'.

Basically, the application queries a KDB database which returns the last row of a trade table every second. This table is constantly added modified by a feed. I have it return the last row, where I have it to print to the console. But I need it to be printed in a JavaFX textField or textArea instead. I'm not that great at creating Java GUIs as my job doesn't usually require me to make them. I feel like this is a bit harder than it sounds.

My ConnectionToKDB class is responsible for printing to the console but I need to send what it is printing to the GUI in the main class JavaFXToKDB. I've been thinking that there must be a way to redirect the console output to the GUI component textfield in JavaFXToKDB.java.

Another idea is to maybe store the outputs from the flip code to a string array list and make it somehow accessible to the textfield. I could really use some advice on this. Also the console printing occurs in the code block where you see me accessing the flip function and accessing rows and columns. You can find the class for the Fusion API here if you wish to look at the flip function.

JavaFxToKDB.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import java.lang.*;
import javafx.geometry.Insets;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;


public class JavaFxToKdb extends Application {

    @Override
    public void start(Stage primaryStage) {

        TextField textfield = new TextField();
        Button btn = new Button();
        btn.setText("Show me the last Trade Record");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });

        VBox vbox = new VBox();
        vbox.getChildren().addAll(textfield,btn);
        vbox.setSpacing(10);
        vbox.setPadding(new Insets(40,40,40,40));
        Scene scene = new Scene(vbox, 600, 500);

        primaryStage.setTitle("KDB Connector");
        primaryStage.setScene(scene);
        primaryStage.show();
    }


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


/*
Instance of the class containing the method which connects to the KDB Process and queries the process table
        */
        ConnectionToKDB varConnect = new ConnectionToKDB();
        //varConnect.ConnectToKDB();
    }



}

ConnectionToKDB.java

import java.io.IOException;
import java.util.Calendar;


public class ConnectionToKDB {

    public ConnectionToKDB(){}

   public void ConnectToKDB(){
    //c connection = null;
        // 1) create a java calendar instance
        Calendar calendar = Calendar.getInstance();
        // 2) get a java.util.Date from the calendar instance.
        //    this date will represent the current instant, or "now".
        java.util.Date now = calendar.getTime();
        // 3) a java current time (now) instance
        java.sql.Timestamp currentTimestamp = new java.sql.Timestamp(now.getTime());
        try{
        c connection=new c("localhost",6002,"admin:admin");

        boolean run = true; //While true the application will continue to query the kdb process (RDB or TP depending on port)
        while(run){


        //System.out.println("Received "+ Arrays.deepToString(objectFeedArray));
        //System.out.println("Recieved" + connection.k("-1#trade"));

/*
Prints the returned table row with column names and row data
*/
        c.Flip flip = (c.Flip)connection.k("-1#trade");
        for(int col=0;col<flip.x.length;col++)
          System.out.print((col>0?",":"")+flip.x[col]);
        System.out.println();
        for(int row=0;row<c.n(flip.y[0]);row++){
          for(int col=0;col<flip.x.length;col++)
            System.out.print((col>0?",":"")+c.at(flip.y[col],row));
            System.out.println();
        }
        //run = false;
        Thread.sleep(1000); // Prevents duplicate rows produced due to querying the rdb multiple times before a new 'last row' was generated
        //System.out.println(connection.k("2+4")); //Test connection to kdb process
        }
        //connection.close();

        }
        catch(c.KException ke){
            System.out.println("Oops"); 
        }
        catch(IOException io){
            System.out.println("Oops2");
        }
        catch(InterruptedException ie){
            System.out.println("Oops3");
        }
        System.exit(0);
   }
}
fin444
  • 725
  • 2
  • 14
  • 27
  • So, what's wrong with doing something like [this](https://stackoverflow.com/questions/12945537/how-to-set-output-stream-to-textarea/12945678#12945678)? The solution is decoupled enough that you should be able take the core concept of `StreamCapturer` and it's companion `Consumer` and apply it to your problem – MadProgrammer Jan 23 '18 at 22:31
  • An over all better solution would be to have `ConnectionToKDB` generate a notification/event when ever it gets new content, then allow observers to react to those events in what ever prescribed manner they want to – MadProgrammer Jan 23 '18 at 22:32
  • I would also consider using `java.util.Timer` to schedule regular updates, but that's just me – MadProgrammer Jan 23 '18 at 22:34
  • @MadProgrammer wow i couldnt find that post before, i was probably trying to search too specific. Let me try this and get back to you – CodeSword345 Jan 23 '18 at 22:40
  • @MadProgrammer the timer would be a cool touch, its just the database updates multiple times a second and i query it faster than it updates so i was getting duplicate rows, so i figure sleeping a second inbetween record prints is ok for now. ill change down the line at some point. I plan to have a button which when pressed will show the latest record recieved from the KDB process – CodeSword345 Jan 23 '18 at 22:45
  • 1
    @cknoxk9 Just beware, you can't update the UI from outside JavaFX's "main" thread, so you'll need to synchronise the updates from your update thread with it – MadProgrammer Jan 23 '18 at 22:48
  • 1
    To get around the threading issues, you could use something like: [Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks](https://stackoverflow.com/questions/24116858/most-efficient-way-to-log-messages-to-javafx-textarea-via-threads-with-simple-cu). If it's just about redirecting output and not worrying about threading, also see related: [Redirecting System.out to a TextArea in JavaFX](https://stackoverflow.com/questions/13841884/redirecting-system-out-to-a-textarea-in-javafx). – jewelsea Jan 24 '18 at 00:40
  • You might want to take a look at [ScheduledService](https://docs.oracle.com/javase/9/docs/api/javafx/concurrent/ScheduledService.html) as well. – Jai Jan 24 '18 at 02:02
  • @MadProgrammer thanks this worked for me! thanks everyone for the helpful comments – CodeSword345 Jan 25 '18 at 22:19

0 Answers0