Qt: Open links with target in default browser, without leaking memory
Searching through the Internet, I've come across so many ways, mostly nonfunctional, nonspecific, or partially functional, to do various things with QWebView
and opening URLs.
After much swearing and cursing, I've managed to get an example to do what I want, which is open normal links normally, and open anything that requests a new window in the external browser; however, there's a hitch. It leaks memory, because I make a bunch of extra WebViews
that aren't cleaned up until the process exits. How can I do this without leaking memory?
Please forgive my rather sophomoric understanding of Qt in advance. I've only been using it for a handful of hours at this point.
SSCCE:
test.hpp
#include <QMainWindow>
#include <QWebView>
class Window : public QMainWindow {
Q_OBJECT
public:
Window();
private:
QWebView* m_web;
private slots:
};
class WebPage : public QWebPage {
Q_OBJECT
public:
bool acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, NavigationType type);
};
class WebView : public QWebView {
Q_OBJECT
public:
QWebView* createWindow(QWebPage::WebWindowType type);
};
test.cpp
#include <QApplication>
#include <QGridLayout>
#include <QNetworkRequest>
#include <QDesktopServices>
#include "test.hpp"
Window::Window() :
QMainWindow() {
m_web = new WebView;
m_web->setHtml("<div align="center"><a href="http://www.google.com/">Same Window</a> <a href="http://www.google.com/" target="_blank">New Window</a></div>");
setCentralWidget(m_web);
}
bool WebPage::acceptNavigationRequest(QWebFrame*, QNetworkRequest const& request, NavigationType) {
QDesktopServices::openUrl(request.url());
return false;
}
QWebView* WebView::createWindow(QWebPage::WebWindowType) {
auto res = new WebView;
auto page = new WebPage;
res->setPage(page);
return res;
}
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
test.pro
QT += core gui network webkitwidgets widgets
TEMPLATE = app
TARGET = test
INCLUDEPATH += .
CONFIG += c++11
# Input
SOURCES += test.cpp
HEADERS += test.hpp
To Compile and Run
qmake test.pro
make
./test
It seems the view becomes useless after the page is rendered in the extern browser. You might just schedule the ExternalWebView for deletetion with deleteLater():
#include <iostream>
#include <QApplication>
#include <QGridLayout>
#include <QNetworkRequest>
#include <QDesktopServices>
#include <QEvent>
#include <QMainWindow>
#include <QWebView>
class ExternWebPage : public QWebPage {
//Q_OBJECT
public:
ExternWebPage(QObject* parent = 0)
: QWebPage(parent)
{
std::cout << "ExternWebPage" << std::endl;
}
~ExternWebPage() {
std::cout << "Destroy ExternWebPage" << std::endl;
}
virtual bool event(QEvent *e) {
static unsigned counter;
std::cout << ++counter << " ExternWebPage: " << e->type() << std::endl;
return QWebPage::event(e);
}
bool acceptNavigationRequest(QWebFrame *, const QNetworkRequest &request, NavigationType) {
QDesktopServices::openUrl(request.url());
return false;
}
};
class ExternWebView : public QWebView {
//Q_OBJECT
public:
ExternWebView(QWidget* parent = 0)
: QWebView(parent)
{
std::cout << "ExternWebView" << std::endl;
}
~ExternWebView() { std::cout << "Destroy ExternWebView" << std::endl; }
virtual bool event(QEvent *e) {
static unsigned counter;
std::cout << ++counter << " ExternWebView: " << e->type() << std::endl;
return QWebView::event(e);
}
};
class InternalWebView : public QWebView {
//Q_OBJECT
public:
InternalWebView(QWidget* parent = 0)
: QWebView(parent)
{}
QWebView* createWindow(QWebPage::WebWindowType) {
auto res = new ExternWebView();
res->setPage(new ExternWebPage(res));
res->deleteLater();
return res;
}
};
class Window : public QMainWindow {
//Q_OBJECT
public:
Window()
: QMainWindow()
{
std::cout << "Window" << std::endl;
auto web = new InternalWebView(this);
web->setHtml("<div align="center"><a href="http://www.google.com/">Same Window</a> <a href="http://www.google.com/" target="_blank">New Window</a></div>");
setCentralWidget(web);
}
~Window() { std::cout << "Destroy Window" << std::endl; }
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
Test without deletion:
Window
ExternWebView
1 ExternWebView: 68
ExternWebPage
2 ExternWebView: 74
3 ExternWebView: 75
1 ExternWebPage: 43
2 ExternWebPage: 43
3 ExternWebPage: 43
4 ExternWebPage: 43
5 ExternWebPage: 43
Destroy Window
Test with delete later:
ExternWebView
1 ExternWebView: 68
ExternWebPage
2 ExternWebView: 74
3 ExternWebView: 75
4 ExternWebView: 52
Destroy ExternWebView
Destroy ExternWebPage
Destroy Window
QDesktopServices::openUrl(QUrl("http://stackoverflow.com/"));
由于这是内置函数,因此不应该有任何内存泄漏。
There are no leaks in the program, because the qt memory management system is going to take care of the objects created on the heap.
First, setPage is going to make your view object parent of the page object. That means that the page object will be deleted when the view object gets destroyed.
Second, since the view has no parent, you are always going to get a window. It will be released when you close the window, or end the program. That is why I said it is going to be taken cared by the qt's memory management system.
Now, when you run your program using memory profiler program (like valgrind), you may get leaks, which may or may not be real leaks. You need to identify them, and filter them out.
链接地址: http://www.djcxy.com/p/75934.html上一篇: 与供应商目录的git工作流程