Wt C++ make window unclickable after button click - c++

Edit: solution below
Using Wt (version 3) C++ framework:
When clicking on a WPushButton which calls a function:
button->clicked(boost::bind(&Service::burn, this));
How can one freeze the screen(or all the buttons) in such a way, that nothing can be clicked while the function runs (runs quite a long time). Currently, when the function Service::burn() runs, I can click other buttons which get queued up and executed after the function Service::burn() has finished.
Note that all buttons/screen needs to be restored after freeze. Also there's a function:
Solution:
Wt::WPushButton* spec_button;
void testclass::test_only()
{
spec_button = new Wt::WPushButton("slow func");
auto some_long_func = [&](){
cout << "#######start \n";
std::this_thread::sleep_for(std::chrono::seconds(1));
cout << "#######end \n";
spec_button->setDisabled(false);
};
content()->addWidget(spec_button);
spec_button->clicked().connect(spec_button, &WPushButton::disable);
spec_button->clicked().connect(boost::bind<void>(some_long_func));
}

This should work:
button->clicked(button, &WPushButton::disable);
button->clicked(boost::bind(&Service::burn, this));
So, you disable the UI using the first handler and then launch your heavy long process using the second one.
If you put those two handlers into a single call, it won't work, because the UI changes won't be propagated to a browser until that call is finished.

Wt doesn't send widget tree modifications to the browser until the event handling is completed, which means that the effect pf button disable will not become visible until after some_long_func completes.
One way around this is to call wApp->processEvents() after disabling the button and before calling some_long_func. This will cause an intermediate update of the widget tree to be sent to the browser immediately. The button clicked() handler can thus look like this (as one function to ensure the order of execution of the signal handers):
{
spec_button->disable();
wApp->processEvents();
some_long_func();
}

The Wt application have a main container with my own class like :
WtMain::WtMain ( void )
:Wt::WContainerWidget ( ) {
setId ( "wkmain-apps" ) ;
}
this class is create on a pointer C_Main.
When i will freeze the all application run this :
C_Main->doJavaScript ( "$('#wkmain-apps').css({'opacity': 0.5,'z-index': 5,'pointer-events': 'none' });" ) ;
and when your function finish is work do :
C_Main->doJavaScript ( "$('#wkmain-apps').css({'opacity': 1,'z-index': 'auto','pointer-events': 'all' });" ) ;
to un-freeze the screen.

Related

Animated gif image isn't being animated in my modeless Gtk::Dialog

My goal is to show a brief "Please Wait..." dialog with an animated gif (spinner) in a Gtk::Dialog.
My problem is that when I do not use Gtk:Dialog::run(), the gif won't be animated, and when I do use the Gtk:Dialog::run() method it completely blocks my running code afterwards. And since I don't have any buttons in my dialog it would hang there indefinitely. Is there a way around that? I have had no success in getting the animated gif to work in a non-modal dialog, i.e without using the run() method.
I'm using gtkmm 3.0
Compile with : g++ examplewindow.cc main.cc -o main `pkg-config gtkmm-3.0 --cflags --libs`
main.cc
#include "examplewindow.h"
#include <gtkmm/application.h>
#include <iostream>
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create("org.gtkmm.example");
ExampleWindow window;
//Shows the window and returns when it is closed.
//return app->make_window_and_run<ExampleWindow>(argc, argv);
return app->run(window);
}
examplewindow.h
#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow();
virtual ~ExampleWindow();
protected:
//Signal handlers:
void on_button_clicked();
//Child widgets:
Gtk::Box m_VBox;
Gtk::Box m_ButtonBox;
Gtk::Button m_Button;
};
#endif //GTKMM_EXAMPLEWINDOW_H
examplewindow.cc
#include "examplewindow.h"
#include <iostream>
ExampleWindow::ExampleWindow()
: m_VBox(Gtk::Orientation::ORIENTATION_VERTICAL),
m_ButtonBox(Gtk::Orientation::ORIENTATION_VERTICAL),
m_Button("Show Dialog")
{
set_title("Test animated gif");
set_default_size(800, 600);
add(m_VBox);
m_VBox.pack_start(m_ButtonBox);
m_ButtonBox.pack_start(m_Button);
m_Button.set_hexpand(true);
m_Button.set_halign(Gtk::Align::ALIGN_CENTER);
m_Button.set_valign(Gtk::Align::ALIGN_CENTER);
m_Button.grab_focus();
m_Button.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_clicked));
show_all_children();
}
ExampleWindow::~ExampleWindow()
{
}
void ExampleWindow::on_button_clicked()
{
Gtk::Dialog m_Dialog;
m_Dialog.set_transient_for(*this);
m_Dialog.set_size_request(200, 200);
m_Dialog.set_decorated(false);
Gtk::Image imageLoading = Gtk::Image();
imageLoading.property_pixbuf_animation() = Gdk::PixbufAnimation::create_from_file("gtkmm_logo.gif");
m_Dialog.get_vbox()->pack_start(imageLoading);
m_Dialog.show_all();
m_Dialog.run();
/******** This, below, never gets executed as run() is blocking the program...********/
// Dummy "long" operation
for (int i = 0; i <= 2010101010; i++)
{
if (i == 2010101010)
std::cout << "Done" << std::endl;
}
m_Dialog.response(Gtk::RESPONSE_ACCEPT);
m_Dialog.hide();
}
Let us look at the original problem. You created a dialog, called show() on it, did some long-running process, then closed the dialog. The process worked, but your program froze during the processing. Why is that?
A graphical interface works by processing messages (events). Some events run off a timer, such as the ones that tell an animation to go to the next frame. Some are generated as needed, such as the ones that tell an image to draw the current frame. These events need to be both triggered and processed to be effective. You triggered the appropriate events with your call to show_all(), but you did not give your program a chance to handle those events.
You used a button click to start your long-running process. That click is an event that was handled by your main event handling loop. That loop then waited for the click to be fully handled before moving on to the next event. However, you have your long-running process in the handler. The main event loop had to wait for that process to finish before it could handle new events, such as the ones to show and animate your image. You never gave your dialog a chance to do its job before you destroyed it.
Calling the dialog's run() method partially fixed the situation by starting a new event loop for the dialog. So even though the main event loop was still blocked by your click handler, new events could be handled. The dialog's event loop received the events required to show an animation, hence your program was again responsive. Unfortunately, run() blocked your long-running process, so we're not really any better off.
The simplest fix is to no longer completely block your main event loop. You could have your long-running process periodically allow events to be processed via Gtk::Main::iteration(). This function invokes an iteration of the main event loop, allowing your program to stay responsive. Pass it a false argument so that it only processes events if there are some to process (rather than waiting for an event to occur).
for (unsigned long i = 0; i <= 2010101010; i++)
{
if (i == 2010101010)
std::cout << "Done" << std::endl;
// Periodically process events
if ( i % 10000 == 0 ) // <---- after some suitable amount of work
if ( !Gtk::Main::iteration(false) ) // <---- allow events to be processed
// Abort the work.
break;
}
The return value is supposed to tell you if you should quit or not, but I didn't get this working in my test (and the return value seemed to have the opposite meaning compared to the documentation). Maybe the dialog itself was keeping the app alive? Eh, that can be the next question, once this part is working.
Other approaches would move your long-running process out of the click handler. If you let the click handler end quickly, the main event loop can do its job without the extra prompting from you. However, this requires a few adjustments so that the Gtk::Dialog outlives the call to on_button_clicked(). That's a bit of refactoring, but it might be worth the time. I'll present two options (without code).
You could have your work operate on multiple timeout signals. Divide your long-running process into smaller chunks, each chunk suitably sized for a callback. (How big is that? Not sure. For now, let's say at most a few milliseconds.) Have the button click event start the first timeout signal with a priority that allows the GUI to update. (As I recall, PRIORITY_DEFAULT_IDLE should work.) For the interval, I would try 0 if that does not overly confuse Gtk+. (I have not tried it, but it seems plausible.) If the 0-interval works, it might be wise to use connect_once() instead of connect(), and have each chunk schedule the next with another timeout. The final chunk would be responsible for closing the dialog.
You could move your long-running process to another thread. Multi-threaded programming has its own set of problems and sometimes a lot of setup, but this is something it is well-suited for. If your long-running process is in a different thread than your main event loop, the operating system becomes responsible for making sure each thread gets some CPU time. Your long-running process can chug away, and the main event loop would simultaneously be able to process events with no special intervention from you.
Final notes:
If your dialog is for one-way communication to the user, it seems more like a monologue than a dialogue. Excuse me, more like an ordinary window than a dialog. Also, I'll make sure you are aware of Gtk::ProgressBar, which "is typically used to display the progress of a long running operation." Just an option; preferring your image is understandable.

How to handle touch events for cocos?

Is it possible to handle touch enter or touch leave in cocos creator 1.9?
I don't find any.
i tried to do it with touch move but it doesn't worked.
You need to register callback for touch event.
Read manual here first.
In the sample code:
onLoad: function () {
this.node.on('mousedown', function ( event ) {
console.log('Hello!');
});}
Use cc.Node.EventType.TOUCH_START for touch enter (TOUCH_MOVE / TOUCH_END / TOUCH_CANCEL for other purpose) instead of 'mousedown';

Qt didn't continue run instructions after specific code

I'm trying to make QInputDialog put values into an array using a for loop but after reaching the max value it didn't continue to run code after the loop until I exit my program
void MainWindow::on_pushButton_clicked()
{
nb = ui->lineEdit->text().toInt();
for(i=1;i<=nb;i++)
{
QInputDialog *ValDialog = new QInputDialog();
b[i] =ValDialog->getInt(this,"Best Fit","Block No : " + i,1,0,100000,1);
}
std::cout << "aAA\n" + b[0];
//UNRUNABBLE instructions
}
Code after the for loop didn't run at all until I stopped the run.
According to Qt's documentation: https://doc.qt.io/qt-5/qinputdialog.html#getInt QInputDialog::getInt(...) will create a modal window. A modal window is basically blocking the main window (your MainWindow class) until a user closes it.
This is intentional, so that you do not continue in the code, until a result is ready. If you wish to execute something after the dialog is shown, but not yet closed, you should probably use a different approach (maybe derive your own QDialog).

WT widget not updating in boost thread

I have run into an interesting problem with WT, I have solved it, but I do not understand WHY my solution solved the problem. I've dug through WT documentation for the widgets and have come up empty handed so far, so maybe someone who knows more about WT can help me out here.
Anyway, the problem is with a WComboBox widget in a boost thread not updating it's data when clicked on and having it's selection changed.
I created a boost thread in a class
class MyConsole: public WApplication
{
private:
boost::shared_ptr<boost::thread> _thread;
WComboBox* _combo_box;
bool running;
//Thread function
void my_thread(Wt::WApplication *app);
}
Then I fill the combo box with data, lets use "foo" and "goya" as the 2 entries. I made a function for the thread, and put a loop into it.
void MyConsole::my_thread(Wt::WApplication *app)
{
while(running)
{
std::string test;
Wt::WApplication::UpdateLock lock(app);
if(lock)
{
test = _combo_box->valueText().narrow();
}
if (strcmp("foo", test.c_str()) == 0)
{
cout << "we got foo" << endl;
}
else if (strcmp("goya", test.c_str()) == 0)
{
cout << "we got goya" << endl;
}
}
}
Without changing the initial selection of the combo box, the above code always enters the foo if statement, which is expected. However, when I change the selection of the _combo_box to "goya" the above code still enters the "foo" if statement, which is very unexpected. Investigating the matter further such as printing out the current index of the combo box before the if statement showed me that it is always 0 and never gets incremented when the selection changes.
The way I fixed it was by connecting the combo box changed() signal to a do nothing function that I added to the class.
class MyConsole: public WApplication
{
private:
...
void WWidgetForceUpdate(void)
{
}
...
}
...
_combo_box->changed().connect(this, &MyConsole::WWidgetForceUpdate);
With the addition of that function call when the selection changes, the "foo" and "goya" if statements worked properly, and printing out the current index of the combo box before the if statement confirmed that the index was now changing.
Why did connecting the changed() signal to a do nothing function remedy the situation? I am sure there is a bigger problem that I am not seeing here :(
Any help would be much appreciated.
Wt sends changes from the browser to the server when events happen. If your program is not interested in an event, this synchronisation will not take place (otherwise synchronisation would take place on every character of text you enter in an input box, on every mose movement, .... even if your application is not doing anything with it). Nothing connected to changed() means that nothing is interested in that specific event, and the browser will not notify the server when it happens.
Any event that is being listened upon will send all changes of all widgets to the server, so that the full widget tree is synchronised. So if you have a button with clicked() listener, and a combobox without a changed() listener, the state of the combobox will still be updated in the widget tree when you click the button.
There is however a bug in your code: you cannot just access the widget tree from a random thread without grabbing the update lock (WApplication::UpdateLock).

Terminating thread

I've a dialog displaying progress bar + some other data, and I also have a cancel button on this dialog. While this dialog is displayed there is potentially heavy computation going on, which is show on progress bar. This computation is started from withing this dialog code so I have:
Counting_Progress_Dialog::Counting_Progress_Dialog(QWidget *parent) :
QDialog(parent)
{
setupUi(this);
thread_ = new Threaded;//THIS IS THE THREAD IN WHICH COMPUTATION IS BEING PERFORMED
connect(thread_,SIGNAL(counter_value(int)),this,SLOT(update_progress_bar(int)));
connect(this,SIGNAL(rejected()),thread_,SLOT(terminate()),Qt::QueuedConnection);//
HERE I'M CONNECTING REJECTED ON DIALOG TO TERMINATE ON THREAD
}
void Counting_Progress_Dialog::start()
{
thread_->start(QThread::LowestPriority);
}
and I do invoke this in part of the program:
void My_Class::dummy_()
{
auto old_priority = this->thread()->priority();
this->thread()->setPriority(QThread::HighestPriority);
Counting_Progress_Dialog progress;
progress.start();//this will start thread
progress.exec();//this will enter it's event loop
progress.wait();//this will wait until thread is finished
this->thread()->setPriority(QThread::NormalPriority);
}
But despite all this, when I press cancel on my dialog, the whole application freezes. What am I doing wrong? How to make it behave correctly?
UPDATED:
void Counting_Progress_Dialog::wait()
{
thread_->wait();
}
I see that you are connecting using 2 different strategies. But if thread_ and this(counting dialog) are really within two separated threads then the connection will always be Qt::QueuedConnection. Well that's not the issue.
progress.exec();//this will enter it's event loop
Calling exec() suspend the execution of dummy_() until the dialog have to return. And when the dialog return your thread is terminated. So I don't see the purpose of
progress.wait();//this will wait until thread is finished
By the way which function is that? the only one I know is Qthread::wait(). I am pretty confident the issue is here...
edit:
progress.wait() is not the issue... But it is possible that the events sent by the thread are causing trouble in some way. Use the debugger or some qDebug() to see if update_progress_bar is called after you push cancel.