I am executing some commands on linux using JSCH and taking output of that command and printing same on the activity log in my JAVAFX application.
Here is a problem: the activity log area is getting stuck after printing some line. But, if I switch from the window and back application continues to print lines on log area. I have debugged several times but wasn't able to catch the problem.
Below is the code
channel.connect();
PrintStream commander = new PrintStream(channel.getOutputStream(), true);
commander.println(command_cd);
commander.println(" exit;");
commander.close();
InputStream outputstream_from_the_channel = channel.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(outputstream_from_the_channel));
String jarOutput;
BufferedWriter bw = new BufferedWriter(new FileWriter(resultLogFile.getAbsolutePath(), true));
while ((jarOutput = reader.readLine()) != null) {
this.logger.info("Status Update = " + jarOutput);
System.out.print("Status Update on screen ="+jarOutput + "\n");
bw.write(jarOutput);
bw.newLine();
outputFromUnix.append(jarOutput).append("\n");
// Display in activity log area in realtime.
if (DeploymentTaskController.actLogTArea != null) {
System.out.println("outputFromUnix.toString()---->>>>> " + outputFromUnix.toString());
//actlogArea is TextArea
DeploymentTaskController.actLogTArea.setText(outputFromUnix.toString());
DeploymentTaskController.actLogTArea.end();
}
}
bw.close();
reader.close();
JavaFX has a special thread named "JavaFX Application Thread" to update all UI. This thread shouldn't be used for any non-UI operations, and all UI operations must be run on that thread.
Make sure you run your code in a separate Thread and wrap all UI code into Platform#runLater() to have executed
// Using separate thread to run data loading code
new Thread(new Runnable() {
public void run() {
channel.connect();
// [...] all your channel reading code
// Updating UI from JavaFX Application Thread
if (DeploymentTaskController.actLogTArea != null) {
System.out.println("outputFromUnix.toString()---->>>>> " + outputFromUnix.toString());
final String outputStr = outputFromUnix.toString();
Platform.runLater(new Runnable() {
#Override
public void run() {
DeploymentTaskController.actLogTArea.setText(outputStr);
DeploymentTaskController.actLogTArea.end();
}
});
}
bw.close();
reader.close();
}
}).start();
There is also a special concurrency API in JavaFX for such tasks, see here: http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm
Related
I want to make my QChart dynamically update whenever a point is added to the QLineSeries object attached to it, but it seems that this update only occurs after the while loop I am running has finished. I am using said while loop in interface.cpp that calls a function updatePlot() which adds the data point to the line series, but this only updates the chart after the while loop has completely finished. Pseudo code of what is happening here:
qtwindow.cpp
// Constructor that initializes the series which will be passed into the interface
AlgoWindow::AlgoWindow( ..., TradingInterface* interface, ... ) {
...
QLineSeries* series = new QLineSeries();
QLineSeries* benchmark = new QLineSeries();
QChart* chart = new QChart();
chart->addSeries(series);
chart->addSeries(benchmark);
// Also creates custom axes which are attached to each series
...
}
// Slot connected to a button signal
void AlgoWindow::buttonClicked() {
// Runs the backtest
interface->runbacktest(..., series, benchmark, ...);
}
interface.cpp
void TradingInterface::runbacktest(..., QtCharts::QLineSeries* algoplot, QtCharts::QLineSeries* benchplot) {
// Runs a huge while loop that continuously checks for events
while (continue_backtest) {
if (!eventsqueue.isEmpty()) {
// Handle each event for the bar
} else {
// All events have been handled for the day, so plot
updatePlot(algoplot, benchplot);
}
}
}
void TradingInterface::updatePlot(QtCharts::QLineSeries *algoseries,
QtCharts::QLineSeries *benchseries) {
// Get the date and the information to put in each point
long date = portfolio.bars->latestDates.back();
double equitycurve = portfolio.all_holdings.rbegin().operator*().second["equitycurve"];
double benchcurve = benchmarkportfolio.all_holdings.rbegin().operator*.second["equitycurve"];
// Append the new points to their respective QLineSeries
algoseries->append(date * 1000, equitycurve*100);
benchseries->append(date * 1000, benchcurve*100);
}
This gives me no errors and the while loop completes, but the lines are only plotted after runbacktest() exits. It then plots all the data correctly, but all at once.
What I need to happen is for the QChart to update every time the lines are added, which my guess was to use some form of custom signal-slot listener but I have no clue how to go about that. If the graph will not update until after the function completes, is it even possible within the QChart framework?
Also, I have already tried QChart::update() and QChartView::repaint(). Both produced the same results as without.
EDIT: I tried setting up a new thread that emits a signal back to the main thread whenever the data is completed but it seems to have changed nothing. The QChart still does not update until after all the data has been inputted. I added a couple lines to help debug and it seems like the function which emits the signal runs consistently just fine, but the slot function which receives the signal only runs after the thread has finished. Not only that, but slowing the signals down with a sleep does not make it plot slowly (like I thought), as the QChart still refuses to update until after the final update to addData().
Either remove your while loop and perform the work one step at a time with a timer.
Or run your runbacktest function in another thread and send a signal to update the QChart in the UI's thread when the data is ready.
Either way you need to give control back to the event loop so that the chart can be repainted.
The Qt idiom for running an operation “continuously” is to use a zero-duration “timer”. It’s not a timer really, but Qt calls it one.
You can do the operation in chunks that take approximately a millisecond. For this, invert the control flow. Qt doesn't provide too much syntactic sugar for it, but it's easy to remedy.
Convert this code, which maintains a loop:
for (int i = 0; i < 1000; ++i) {
doSomething(i);
}
into this lambda, which is invoked by the event loop:
m_tasks.addTask([this](i = 0) mutable {
doSomething(i);
++i;
return i < 1000;
});
assuming:
class Controller : public QObject {
Tasks m_tasks;
...
};
where the Tasks class maintains a list of tasks to be executed by the event loop:
class Tasks : public QObject {
Q_OBJECT
QBasicTimer timer;
std::list<std::function<bool()>> tasks;
protected:
void timerEvent(QTimerEvent *ev) override {
if (ev->timerId() != timer.timerId())
return;
for (auto it = tasks.begin(); it != tasks.end(); ) {
bool keep = (*it)();
if (!keep)
it = tasks.erase(it);
else
++it;
}
if (tasks.empty())
timer.stop();
}
public:
using QObject :: QObject;
template <typename F> void addTask(F &&fun) {
tasks.emplace_back(std::forward(fun));
if (!timer.isActive())
timer.start(0, this);
}
};
I have the following code:
tbb::concurrent_bounded_queue<Image> camera_queue_;
camera_queue_.set_capacity(1);
struct Image
{
int hour_;
int minute_;
int second_;
int msec_;
QImage image_;
Image(){hour_ = -1; minute_ = -1; second_ = -1; msec_ = -1; image_ = QImage();}
Image& operator=(Image const& copy)
{
this->hour_ = copy.hour_;
this->minute_ = copy.minute_;
this->second_ = copy.second_;
this->msec_ = copy.msec_;
this->image_ = copy.image_;
return *this;
}
};
In a Qt Thread :
ThreadA:
tbb::concurrent_bounded_queue<Image> image_queue_;
image_queue_.set_capacity(1);
Image cur_image_;
void Worker::process() {
while(1)
{
if(quit_)
break;
{
camera_queue_.pop(cur_image_);
image_queue_.push(cur_image_);
}
emit imageReady();
}
emit finished();
}
Image Worker::getCurrentImage()
{
Image tmp_image;
image_queue_.pop(tmp_image);
return tmp_image;
}
In Another Thread:
ThreadB:
Producer::Producer(){
work_ = new Worker();
work_->moveToThread(workerThread_);
QObject::connect(workerThread_, &QThread::finished, work_, &QObject::deleteLater);
QObject::connect(this, &Producer::operate, work_, &Worker::process);
QObject::connect(work_, &Worker::imageReady, this, &Producer::displayImage);
QObject::connect(this, &Producer::stopDecode, work_, &Worker::stop);
workerThread_->start();
emit operate();
}
void Producer::process() {
while(1)
{
if(quit_)
break;
{
camera_queue_.push(GetImage());
}
}
}
void Producer::displayImage()
{
Image tmp = std::move(work_->getCurrentImage());
widget_->showImage(tmp.image_);
}
However, In main thread, I have a function that enables user to click a button to get current image:
bool Producer::SaveImage()
{
Image img = std::move(work_->getCurrentImage());
std::string fileName = std::to_string(img.hour_) + "-" + std::to_string(img.minute_) + "-" + std::to_string(img.second_) + "-" + std::to_string(img.msec_/1000) + ".jpg";
std::string outFileName = folder + "/" + fileName;
return img.image_.save(QString::fromStdString(outFileName));
}
The problem is:
When user does not click the button to invoke Producer::SaveImage(), the Image Decoding and Showing runs smoothly. But when user invoke Producer::SaveImage(), the whole program will get stuck (Caton phenomenon ?). The GUI response becomes not that smooth. The more user invokes SaveImage, the slower the GUI response becomes.
Can anyone help to explain why ? Is there a way to solve that ?
Why do you want to use concurrent queue? It looks like there is a syncronization mechanism in place and you rely mostly on it instead of using concurrent_queue for synchronisation and communication as it is supposed for.
The issue is that when you set capacity = 1, both operations of concurrent_bounded_queue will block until there is enough space of items in the queue. E.g. if the queue contains an item already, the push operation will block. And since you control your threads with another notification mechanism, you might catch a deadlock.
In particular, try to swap the operations like below:
camera_queue_.pop(cur_image_);
emit imageReady();
image_queue_.push(cur_image_);
This should prepare the thread which receives images (if I understand this correctly) and it will block on its image_queue_.pop() method, then this thread will put new image and unblocks the recipient. There might be other issues similar to this, so, please rethink all of your synchronization.
I have an app with contextual commands. After triggered a contextual command, it will make a HTTP request with a link and post the result on the card, something like, "Completed!". I want this card to be closed by itself after one second so that the user need not to tap to close it. Once the result card is closed, it will go back to contextual command lists with "Ok, glass" at footer and ready for next command.
May i know how to do that?
private class HTTPRequest extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
try {
if (mWhat.equalsIgnoreCase("GET")) {
// get json via YouTube API
URL url = new URL("http://example.com");
mUrlConnection = (HttpURLConnection)
url.openConnection();
InputStream in = new BufferedInputStream(
mUrlConnection.getInputStream());
int ch;
StringBuffer b = new StringBuffer();
while ((ch = in.read()) != -1) {
b.append((char) ch);
}
mResult = new String(b);
}
} catch (Exception e) {}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
mTvInfo.setText(mResult);
}
You can use an Android Dialog for this:
Use CardBuilder to create the "Completed" card using the MENU layout.
Create a new instance of Dialog and set its content view to be the view returned by CardBuilder.getView.
Show the dialog.
Use Handler.postDelayed (or some similar mechanism) to automatically dismiss the dialog after the desired amount of time has passed.
How do I start a fragment in my Android application from a notification in the notification bar?
I've tried to implement this answer of creating my own action and then setting the action to the intent, but I'm unsure how to use it and what is required additionally - like adding something to the Manifest.
I've got a notification class that receives a context, a message and then an action. I then want to filter on that action to determine which fragment to launch, but I don't know how to launch a fragment as opposed to launching an activity.
Here is my Notifications.java class (incomplete):
public class Notifications {
private Context mContext;
public Notifications(Context context) {
this.mContext = context;
}
public static void notify(Context context, String message, String action) {
//Action you invent should include the application package as a prefix — for example: "com.example.project.SHOW_COLOR".
action = "my.package.name.here.frag."+action;
//Construct a user message.
String appName = context.getResources().getString(R.string.app_name);
// Use the Notification manager to send notification
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Create a notification using android stat_notify_chat icon.
Notification notification = new Notification(R.drawable.ic_stat_notification, message, 0);
//Sound, lights, vibration.
//REMEMBER PERMISSIONS.
notification.defaults |= Notification.DEFAULT_SOUND;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.defaults |= Notification.DEFAULT_LIGHTS;
// Create a pending intent to open the application when the notification is clicked.
//Restart the app.
Intent launchIntent = null;
//Get the action and based on what the action is, launch the application displaying the appropriate fragment.
if (action.equalsIgnoreCase("friend")){
//New friend notification
//Launch application displaying the list of friends
}
if (action.equalsIgnoreCase("article")){
//New article has been posted
//Launch application displaying the news feed fragment
}
if (action.equalsIgnoreCase("points")){
//Points scored notification
//Launch application displaying the user's profile
}
if (action.equalsIgnoreCase("redeemable")){
//New redeemable is offered
//Launch application displaying the list of redeemables
}
if (!action.equalsIgnoreCase("friend")
&& !action.equalsIgnoreCase("article")
&& !action.equalsIgnoreCase("points")
&& !action.equalsIgnoreCase("redeemable")){
//Not specific, so launch the application from scratch displaying the activity feed
launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
}
if(action != null && launchIntent != null){
launchIntent.setAction(action);
}
// Set the notification and register the pending intent to it
notification.setLatestEventInfo(context, appName, message, pendingIntent);
// Trigger the notification
notificationManager.notify(0, notification);
}
}
So this was actually pretty easy. Hopefully I can help someone else see this too.
I send an action to this notify function. The I add that action to my intent to launch an activity. In my case I open the launching activity, because all the fragments are loaded from within that activity based on what the user does. So I set the action using setAction and the I use that action in the activity as below.
My Notifications.java class changed to this:
public static void notify(Context context, String message, String action) {
action = action.toUpperCase();
// Create a pending intent to open the the application when the notification is clicked.
//Restart the app.
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
if(action != null && launchIntent != null){
launchIntent.setAction(action);
}
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.when = System.currentTimeMillis();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Set the notification and register the pending intent to it
notification.setLatestEventInfo(context, appName, message, pendingIntent);
// Trigger the notification
notificationManager.notify(0, notification);
}
And then in my activity from where I load the fragments, I get the action and filter it:
Intent intent = getIntent();
try{
String action = intent.getAction().toUpperCase();
if(action != null){
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_friend))){
goFrag(getResources().getInteger(R.integer.FRAG_A_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_article))){
goFrag(getResources().getInteger(R.integer.FRAG_B_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_points))){
goFrag(getResources().getInteger(R.integer.FRAG_C_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_redeemable))){
goFrag(getResources().getInteger(R.integer.FRAG_D_INT));
}
if(action.equalsIgnoreCase(getResources().getString(R.string.notification_action_dance))){
goFrag(getResources().getInteger(R.integer.FRAG_E_INT));
}
}else{
Log.d(TAG, "Intent was null");
}
}catch(Exception e){
Log.e(TAG, "Problem consuming action from intent", e);
}
In my goFrag function I replace the fragment if the required fragment is still in memory (meaning the user was there earlier and it hasn't been destroyed yet), or I create a new fragment required.
I have a Silverlight 5.0 application and prvoide MS Word Automation functionality where the user can edit/add new document. I have gone through to MSDN pages but couldn't find any event that MS Word triggers after saving the document. The only event that talks about saving is the "DocumentBeforeSave" event that dosen't helps. I need to know when the MS Word finishes saving the document so that is it ready to save to server.
Can someone help me with this?
Any idea is very much approciated.
using MSWord = Microsoft.Office.Interop.Word;
namespace ConsoleApplication4
{
class Program
{
static void Main()
{
var app = new MSWord.Application();
var doc = app.Documents.Open(#"..\..\myDoc.docx");
app.DocumentBeforeSave += app_DocumentBeforeSave;
}
static void app_DocumentBeforeSave(MSWord.Document Doc, ref bool SaveAsUI, ref bool Cancel)
{
app.DocumentBeforeSave -= app_DocumentBeforeSave;
Cancel = true;
Doc.Save();
if(Doc.Saved){
//Now you know the document has saved
}
app.DocumentBeforeSave += app_DocumentBeforeSave;
}
}
}
The Save method doesn't run on a seperate thread, so it only returns once the Save is complete.
The DocumentBeforeSave event takes in a boolean call Cancel this is passed with the ref parameter, and setting it to true cancels the save that is about to take place.
You could set this to true, and then call Save yourself, this way you will know when the save has completed, as it runs on the same thread, something like this:
using MSWord = Microsoft.Office.Interop.Word;
namespace ConsoleApplication41
{
class Program
{
static void Main()
{
var app = new MSWord.Application();
var doc = app.Documents.Open(#"..\..\myDoc.docx");
app.DocumentBeforeSave += app_DocumentBeforeSave;
}
static void app_DocumentBeforeSave(MSWord.Document Doc, ref bool SaveAsUI, ref bool Cancel)
{
Cancel = true;
Doc.Save();
//Now you know the document has saved
}
}
}