I's using the QWebEngineView to render a h5 page, the h5 page use our custom scheme protocol to communicate with native.
For example, when the native receive the 'scheme_name://close' message from h5 page, the native will close the h5 page.
How can i know the message from which page?
Firstly, i use QDesktopServices::setUrlHandler() to set a url handler, but it's a global handler, and the callback must accepts a single QUrl argument, i can not know the page which the request from.
class Dialog : public QDialog {
public:
void Close() {
web_view_->close();
close();
}
private:
QWebEngineView *web_view_;
}
void OnCustomScheme(const QUrl &url) {
if (url.scheme() != "scheme_name") {
return;
}
if (url.host() == "close") {
// call Dialog::Close();
// who->Close();
}
}
Secondly,i try to use QWebEngineProfile::installUrlSchemeHandler, the receive can use a member of my page, like:
class SchemeHandler : public QWebEngineUrlSchemeHandler {
public:
void requestStarted(QWebEngineUrlRequestJob *job) override {
emit SignalSchemeRequest(job->requestUrl());
}
signals:
void SignalSchemeRequest(const QUrl &url);
};
class Dialog : public QDialog {
public:
Dialog() {
handler_ = new SchemeHandler(this);
connect(handler_, &SchemeHandler::SignalSchemeRequest,
this, &Dialog::SlotSchemeRequest);
profile_ = new QWebEngineProfile(this);
profile_->installUrlSchemeHandler("scheme_name", handler_);
}
void LoadPage(const QUrl &url) {
QWebEnginePage *page = new QWebEnginePage(profile_, this);
web_view_->setPage(page);
page->load(url);
}
void Close() {
web_view_->close();
close();
}
private slots:
coid SlotSchemeRequest(const QUrl &url) {
if (url.host() == "close") {
Close();
}
}
private:
QWebEngineView *web_view_;
SchemeHandler *handler_;
QWebEngineProfile *profile_;
}
Does it has any better way to do?
Everytime to load a page, i have to new a QWebEnginePage.
Related
I have a simple BB10 app with a QML front end.
The GUI consists of a couple of buttons and a label
Page {
Container {
Label {
text: app.alarmCount()
}
Button {
text: qsTr("Resend Notification")
onClicked: {
app.resendNotification();
}
}
Button {
text: qsTr("Stop Service")
onClicked: {
app.stopService();
}
}
Button {
text: qsTr("Kill Service")
onClicked: {
app.killService();
}
}
}
}
And the C++ class
class ApplicationUI: public QObject
{
Q_OBJECT
Q_PROPERTY(QString alarmCount READ alarmCount NOTIFY AlarmUpdate)
public:
ApplicationUI();
virtual ~ApplicationUI() { }
Q_INVOKABLE void resendNotification();
Q_INVOKABLE void stopService();
Q_INVOKABLE void killService();
QString alarmCount() const;
void setAlamCount(int newCount);
signals:
void AlarmUpdate();
private:
bb::system::InvokeManager* m_invokeManager;
QString m_alarmCountDisplay;
};
and the hopefully relevant bit of the class
QString ApplicationUI::alarmCount() const
{
return m_alarmCountDisplay;
}
void ApplicationUI::setAlamCount(int newCount)
{
m_alarmCountDisplay = QString("%1 Alarms").arg(newCount);
emit AlarmUpdate();
}
My problem is the label never displays the alarm count string property. I have set a breakpoint on the emit and can see it's getting called and on the alarmCount() getter and can see that's returning the correct value but my front end never actually shows a value for the label.
You did not actually make a binding to the variable. Correct binding will look like:
text: app.alarmCount
But in your code it is:
text: app.alarmCount()
With your code it makes an error because you can't access any method of Q_OBJECT which is not Q_INVOKABLE or public slot. But even if you make such mark to your methods it means that you get alarmCount property only one single time and it will not be updated since you did not make a binding but just one method call.
How I can do this:
When signal finishedreply(from c++) send variable replydata(from c++) to TextArea(qml)
How i can connect this? Maybe Q_PROPERTY is a good way?
I use Qt 5.3
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
SendGetSMS *Connection = new SendGetSMS();
engine.rootContext()->setContextProperty("abc1", Connection);
QObject::connect(Connection,&SendGetSMS::finishedReply,engine,...);
from the documentation
in the c++:
class Message : public QObject
{
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
public:
void setAuthor(const QString &a) {
if (a != m_author) {
m_author = a;
emit authorChanged();
}
}
QString author() const {
return m_author;
}
private:
QString m_author;
};
Message msg;
engine.rootContext()->setContextProperty("msg", &msg);
in the qml:
Text {
width: 100; height: 100
text: msg.author // invokes Message::author() to get this value
Component.onCompleted: {
msg.author = "Jonah" // invokes Message::setAuthor()
}
}
I have a sub-class of QWidget that is a popup widget. I would like to add some animation when it shows and disappears. So I re-implemented showEvent(QShowEvent * event) and hideEvent and added some QPropertyAnimation in the functions. The showEvent works just fine for me but the hideEvent doesn't. Because
Hide events are sent to widgets immediately after they have been hidden.
Any idea about how to do it?
Update:
I don't think it's the right reason. When I use Nejat's solution. The show part works. But when I click outside the widget. It disappears immediately.
You should override QWidget::closeEvent() so when trying to close immediatly it will be ignored AND we start our animation and after finishing (QPropertyAnimation::finished()) we close the widget as normal.
Here is a demo to demonstrate:
class AnimatedWidget : public QWidget {
Q_OBJECT
Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha)
public:
AnimatedWidget(QWidget* parent = nullptr) :QWidget{ parent }, opacityAnimation{ new QPropertyAnimation{this, "alpha",this} } {
setWindowFlags(windowFlags() | Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::Tool);
auto pal = palette();
pal.setColor(QPalette::Background, Qt::cyan);
setAutoFillBackground(true);
setPalette(pal);
setFixedSize(200, 200);
}
qreal alpha() const {
return windowOpacity();
}
void setAlpha(qreal level) {
setWindowOpacity(level);
update();
}
protected:
void closeEvent(QCloseEvent* e) override {
if (opacityAnimation->currentValue().toReal() == 1.0) { // Ignore event + start animation
e->ignore();
startHide();
QObject::connect(opacityAnimation, SIGNAL(finished()), this, SLOT(onAnimationCallBack()), Qt::UniqueConnection);
} else {
e->accept();
if (!isHidden())
hide();
QWidget::close(); // necessary actions
}
}
public Q_SLOTS:
void show() {
startShow();
QWidget::show(); // necessary actions
}
private Q_SLOTS:
void onAnimationCallBack() {
if (opacityAnimation->currentValue().toReal() == 0.0) { // we're finished so let's really close the widget
QCloseEvent ev;
QApplication::sendEvent(this, &ev);
qApp->sendEvent(this, &ev);
}
}
void startHide() {
opacityAnimation->setStartValue(1.0);
opacityAnimation->setEndValue(0.0);
opacityAnimation->setDuration(1500);
opacityAnimation->start();
}
void startShow() {
opacityAnimation->setStartValue(0.0);
opacityAnimation->setEndValue(1.0);
opacityAnimation->setDuration(1500);
opacityAnimation->start();
}
private:
QPropertyAnimation* opacityAnimation = nullptr;
};
class Base : public QWidget {
public:
Base(QWidget* parent = nullptr) :QWidget{ parent }, widget{ new AnimatedWidget{} } {
}
private:
AnimatedWidget* widget;
protected:
void mouseReleaseEvent(QMouseEvent* e) override {
if (widget->isHidden())
widget->show();
else
widget->close();
QWidget::mouseReleaseEvent(e);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Base base;
base.show();
return app.exec();
}
You can override the eventFilter in your widget and check for QEvent::Show and QEvent::Close events.
bool MyWidget::eventFilter(QObject * obj, QEvent * event)
{
if(obj == this && event->type() == QEvent::Show)
{
//about to show
}
else if(obj == this && event->type() == QEvent::Close)
{
//about to close
}
return false;
}
You should also install the event filter in the constructor by:
this->installEventFilter(this);
I am doing something like this:
MyClass::MyClass(QWidget *parent) : QLabel(parent)
{
this->MyMenu = new QMenu();
QAction* act_del = new QAction(MyMenu);
act_delete->setText("MyAction");
MyMenu->addAction(act_del);
QObject::connect(act_del,SIGNAL(triggered()),this,SLOT(MySlot()));
}
void MyClass::MySlot()
{
//Not called
}
Any suggestion on when the SIGNAL is triggered the SLOT is not called. Here is where the menu is displayed:
void MyClass::contextMenuEvent(QContextMenuEvent *ev)
{
QPoint globalPos = this->mapToGlobal(ev->pos());
QAction* selectedItem = MyMenu->exec(globalPos);
if (selectedItem)
{
}
else
{
// nothing was chosen
}
}
Any suggestions on why the SLOT is not called?
MyClass needs to contain the Q_OBJECT macro for the signal-slot connections to work.
i have popup window that is opened from web page ( its paypal popup)
i capture it and then i try to fix this error as the document suggesting here http://qt-project.org/doc/note_revisions/84/125/view
but still im getting this error
here is my QWebView class
class WebView : public QWebView
{
Q_OBJECT
public:
WebView()
{
connect( this->page()->networkAccessManager(),
SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError> & )),
this,
SLOT(sslErrorHandler(QNetworkReply*, const QList<QSslError> & )));
}
private slots:
void sslErrorHandler( QNetworkReply *reply, const QList<QSslError> &errors)
{
qDebug() << "sslErrorHandler:";
foreach (QSslError err, errors)
qDebug() << "ssl error: " << err;
reply->ignoreSslErrors();
}
protected:
QWebView *createWindow(QWebPage::WebWindowType type)
{
QWebView *webview = new QWebView;
QUrl tmpUrl = webview->url();
QNetworkRequest request(tmpUrl);
//request.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/x-www-form-urlencoded"));
request.setHeader(QNetworkRequest::ContentTypeHeader,"application/octet-stream");
//webview->show();
webview->load(request,QNetworkAccessManager::PostOperation);
return webview;
}
};
what im doing wrong here ?