How to open links on new window in QWebView?

By default, if you click a link on a QWebView window, QWebView will open the url in its own window if the link has not a target=”_blank” attribute, and do nothing if the link has target=”_blank”. If you right-click the link, a context menu is shown with four menu items: “Open Link”, “Open Link in New Window”, “Save Link…”, “Copy Link”. However, only “Open Link” takes effect, i.e., opens the link in the current QWebView window. The other menu items do not take any effect.  If the link(for example <a href=”http://myprogrammingnotes.com” target=”_blank”>myprogrammingnotes.com</a>) has the attribute “target” set to “_blank” which means opening the link in a new window, none of the four menu items takes effect. In all, you just can not bring up a new window from the existing QWebView window.

There are several methods you can use to open a link on a new window.

The first method is to intercept linkClicked signal. First, you should set the link delegation policy of current page to “QWebPage::DelegateAllLinks”:

view1->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);

 

Now, when you click a link(whether it has the target=”_blank” or not) on the current view, the view will emit a linkClicked signal. You can connect the linkClicked signal to a slot where you can load the url(the parameter of the signal) in another QWebView.

However, the behavior of the right-click menu remains unchanged even you set the DelegateAllLinks policy. If you click the “Open Link” menu item, the link is opened on the current window; if you click “Open Link in New Window” item, nothing happens. You should know the right-click menu mechanism before changing this default behavior. The menu items are associated with various QAction objects. Specifically, the “Open Link in New Window” is associated with the QWebPage::OpenLinkInNewWindow QAction object. The QAction object’s trigger signal is connected to a default slot which does nothing. To change this, we should disconnect the default signal-slot connection first and then connect the signal to our slot.

QAction *action=pageAction(QWebPage::OpenLinkInNewWindow);
disconnect(action, SIGNAL(triggered()));
connect(action, SIGNAL(triggered()),this,SLOT(onopennewwindow()));

 

Now onopennewwindow slot gets called when you click the “Open Link in New Window” menu option. But it is not enough yet because we have not gotten the url to be opened yet(there is no parameter called url for the triggered signal). To get the url the user is clicking, you should re-implement the contextMenuEvent function to save the clicking position first(http://stackoverflow.com/questions/20340809/howto-use-qt-qwebviewcreatewindowqwebpagewebwindowtype-type-correctly):

void contextMenuEvent(QContextMenuEvent * event)
{
  this->clickpos = event->pos();
  QWebView::contextMenuEvent(event);
}

 

Now we store the clicking point in the clickpos variable, which can be used to get the url in the onopennewwindow() slot:

QUrl url=page()->mainFrame()->hitTestContent(clickpos).linkUrl();

 

With the url, we can open it in any window we want.

The third method to open a link in another view(another QWebView instance) is quite simple. Remember we mentioned about the default slot for the QWebPage::OpenLinkInNewWindow action? It will call the QWebView’s virtual function createWindow() to get a new  QWebView instance to load the url. The default implementation of createWindow() returns null so no new window is shown up. We can reimplement createWindow() to return a valid pointer to another QWebView instance to load the url.

QWebView* createWindow(QWebPage::WebWindowType)
{
  return newview;
}

 

In general, to open links in new window, you should have two QWebView instances, one(QWebView1) for current url, the other(QWebView2) for loading the new url. But if the two QWebView instances are independent from each other, there might be some problem. For example, if you login the website in QWebView1, and the clicked url is a restricted resource on the website that only allows access from the authenticated user, you will meet error in QWebView2 because the two QWebView instances do not share cookies or sessions that are used for authentication. To resolve this problem, the two QWebView instances should use the same networkAccessManager as follows:

view2->page()->setNetworkAccessManager(view1->page()->networkAccessManager());

 

Now the two views will share the same cookies/sessions.

Posted in

Comments are closed, but trackbacks and pingbacks are open.