reimplement the shouldInterruptJavaScript() in Qt (C++) - c++

According to the help of Qt for QWebPage [Slot ShoudInteruptJavaScript], located here:
This function is called when a JavaScript program is running for a long period of time.
If the user wanted to stop the JavaScript the implementation should return true; otherwise false.
The default implementation executes the query using QMessageBox::information with QMessageBox::Yes and QMessageBox::No buttons.
Warning: Because of binary compatibility constraints, this function is not virtual. If you want to provide your own implementation in a QWebPage subclass, reimplement the shouldInterruptJavaScript() slot in your subclass instead. QtWebKit will dynamically detect the slot and call it.
I don't want qt show a message when javascript runnig for long period of time.
So, how can i reimplement ShoudInteruptJavaScript? and where should i create it?
Please show me a sample
Thanks

All the info you need is in the documentation.
Create a new custom class that inherits from QWebPage, make sure it's a Q_OBJECT to receive signals.
class MyFunkyPage : public QWebPage {
Q_OBJECT
public slots:
bool shouldInterruptJavaScript() {
QApplication::processEvents(QEventLoop::AllEvents, 42);
// Ignore the error
return false;
}
};
Set the page of your QWebView to a custom subclass of QWebPage.
setPage(new MyFunkyPage());
Then when your page gets this signal it won't stop the script from executing, and it won't show a dialog.

The MyFunkyPage solution potentially leaks memory and causes crashes because the object passed to setPage has no parent and setPage does not take ownership. Instead,
class QWebPageWithoutJsWarning : public QWebPage {
Q_OBJECT
public:
QWebPageWithoutJsWarning(QObject* parent = 0) : QWebPage(parent) {}
public slots:
bool shouldInterruptJavaScript() {
return false;
}
};
Set the page of your QWebView to the custom subclass of QWebPage, parented on the WebView,
void suppressJSWarning(QWebView& webView) {
webView.setPage(new QWebPageWithoutJsWarning(&webView));
}

#anson-mackeracher almost had it right.
Qt needs it to be a private slot, not a public one. Here's what works for my class:
class MyFunkyPage : public QWebPage {
Q_OBJECT
private slots:
bool shouldInterruptJavaScript() {
// Ignore the error (return true to kill the runaway JavaScript)
return false;
}
};
Set the page of your QWebView to a custom subclass of QWebPage.
setPage(new MyFunkyPage());
I just tested this with Qt 4.8.4 and it works like a charm. I didn't need the processEvents call.

Related

Qt: How to display an hourglass on a QML Page while a lengthy C++ operation is executed in background

Problem: A QML action must call a Q_INVOKABLE C++ function that takes some time to run.
When we do it the simple way: as soon as a user presses the Enter key, the method is called and the GUI freezes immediately while the code is executed, which is to be expected.
We'd like to update the GUI first (e.g. to display an hourglass) and then to execute the C++ method once the QML page has been updated.
(I imagine we've got to put a Qt event at the end of the Event Queue so it's processed after the others events that will update the QML page).
QML:
...
...
Keys.onEnterPressed: {
MyCplusplusClass.myInvokableMethod();
}
..
C++:
class MyCplusplusClass : public QObject
{
Q_OBJECT
...
Q_INVOKABLE void myInvokableMethod();
...
}
Now we want to run it asynchronously so the GUI won't freeze while it is executed. How is the best method to do that. I'll reproduce below the solution we're using, but I feel there is better to do (I'm not a Qt expert at all and would need some pointer).
QML:
...
property bool _displayHourglass;
...
Keys.onEnterPressed: {
_displayHourglass = true ;
MyCplusplusClass.asynchronousInvokableMethod();
}
...
...
Connections {
target: MyCplusplusClass
signal signalSynchronousMethodFinished
onSignalSynchronousMethodFinished: {
_displayHourglass = false ;
}
}
...
Image {
visible: _displayHourglass
anchors.centerIn: parent;
source: "qrc:/images/icons/hourglass.png"
}
C++:
class MyCplusplusClass : public QObject
{
Q_OBJECT
...
Q_INVOKABLE void asynchronousInvokableMethod() {
QTimer::singleShot(1, this, SLOT(synchronousMethod()));
}
...
private slots:
void synchronousMethod() {
...
emit signalSynchronousMethodFinished() ;
}
signals:
...
signalSynchronousMethodFinished();
...
}
What would be a better solution, please?
I'd prefer to avoid the solution with a worker thread, it's okay for the GUI to freeze if there is an hourglass displayed.

Overriding JUCE ButtonStateChange / Listener Issues

I'm struggling to figure out how to properly override a button's ButtonStateChange in the JUCE library. I'm wanting to change the what happens when a button is held down. I'm fairly new to overriding, but I've been able to successfully override other elements in the JUCE library. Though I am having an issue with this topic.
1) I know you create a new class, maybe MyCustomButton, then
2) Inherit the class you are looking to modify, Button::Listener (not sure if I should do private or public inheritance)
3) Copy and paste the code of the function you want to alter, applying the override keyword to the prototype,
but after this, I'm lost. I'm not sure how to let this new class affect a button that already exists. I know i need to add a listener to an existing button in the constructor and remove the listener in the destructor of the GUI component, but still, I don't know how to apply this new ButtonChangeState listener to an existing button.
Any help would be greatly appreciated.
You can create a new class which inherits from one of Juce's button classes (e.g juce::TextButton) and override buttonStateChanged()
class MyCustomButton : public juce::TextButton
{
public:
MyCustomButton();
protected:
void buttonStateChanged() override
{
// do what you want here
}
};
To apply to your already existing button, just change its type to MyCustomButton.
Alternatively, you can make the class where you use the button inherit from juce::Button::Listener and override buttonStateChanged(Button*).
Then all you need is to attach the listener to your button:
class MyWindow : public Component, private juce::Button::Listener
{
public:
MyWindow()
{
m_button.addListener(this);
}
~MyWindow()
{
m_button.removeListener(this);
}
private:
juce::TextButton m_button;
void buttonStateChanged(Button* button) override
{
if (button == &m_button)
{
// do what you want
}
}
};

Overridden slot shouldInterruptJavaScript() not being called

I want to suppress the Javascript timeout warning in QtWebkit from Qt4.8.6. I created a subclass of QWebPage (shown below) and used setPage to add it to the QWebView. However, the dialog is still appearing. Searching on the internet I have found example that look like my code that people say are working (e.g.reimplement the shouldInterruptJavaScript() in Qt (C++)). I must be doing something silly. If I override a function like javascriptConsoleMessage that gets called OK.
My class:
class NoDialogWebPage : public QWebPage
{
Q_OBJECT
public:
NoDialogWebPage(QObject * parent = 0) : QWebPage(parent) {}
public slots:
bool shouldInterruptJavaScript()
{
return false;
}
};
How it is called from the QWebView's container:
m_pWebView = new QWebView(this);
m_pWebPage = new NoDialogWebPage(m_pWebView);
m_pWebView->setPage(m_pWebPage);
Qt needs it to be a private slot, not a public one. Just change
public slots:
bool shouldInterruptJavaScript()
to
private slots:
bool shouldInterruptJavaScript()
I just tested this with Qt 4.8.4 and it works like a charm.

Qt4: connect slot and signal from other forms

I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.

Using QMDIArea with Qt 4.4.

I'm using the QMdiArea in Qt 4.4.
If a new project is created, I add a number of sub windows to a QMdiArea. I'd like to disallow the user to close a sub window during runtime. The sub windows should only be closed if the whole application is closed or if a new project is created.
How can I do this?
You need to define your own subWindow. create a subclass of QMdiSubWindow and override the closeEvent(QCloseEvent *closeEvent). you can control it by argument. for example:
void ChildWindow::closeEvent(QCloseEvent *closeEvent)
{
if(/*condition C*/)
closeEvent->accept();
else
closeEvent->ignore(); // you can do something else, like
// writing a string in status bar ...
}
then subclass the QMdiArea and override QMdiArea::closeAllSubWindows () like this:
class MainWindowArea : public QMdiArea
{
Q_OBJECT
public:
explicit MainWindowArea(QWidget *parent = 0);
signals:
void closeAllSubWindows();
public slots:
};
// Implementation:
MainWindowArea::closeAllSubWindows()
{
// set close condition (new project is creating, C = true)
foreach(QMdiSubWindow* sub,this->subWindowList())
{
(qobject_cast<ChildWindow*>(sub))->close();
}
}
you may also need to override close slot of your mdi area.
You'd do this the same as for a top-level window: process and ignore the QCloseEvent it sent. QMdiArea::closeActiveSubWindow/QMdiArea::closeAllSubWindows just call QWidget::close, which sends a closeEvent and confirms that it was accepted before proceeding.
You can process this event by subclassing QMdiSubWindow and reimplementing QWidget::closeEvent, or by using an event filter to intercept it..