I am porting my project from Qt WebKit to Qt WebEngine in Qt5.6. I want to emit linkClicked(QUrl) signal when a href is clicked on the QWebView, but QWebEngineView has no signal linkClicked(QUrl).
How to emulate linkClickedSignal(QUrl)?
Porting from Qt WebKit to Qt WebEngine.
Thank you #Alexis P. I have got it.
class MyWebPage : public QWebEnginePage
{
Q_OBJECT
public:
MyWebPage(QObject* parent = 0) : QWebEnginePage(parent){}
bool acceptNavigationRequest(const QUrl & url, QWebEnginePage::NavigationType type, bool)
{
if (type == QWebEnginePage::NavigationTypeLinkClicked)
{
//QDesktopServices::openUrl(url);
emit linkClicked(url);
return false;
}
return true;
}
signals:
void linkClicked(const QUrl&);
};
In my window class:
webView = new QWebEngineView(ui->verticalLayoutWidget);
webView->setPage(new MyWebPage());
ui->verticalLayout->addWidget(webView);
connect(webView- >page(),SIGNAL(linkClicked(QUrl)),this,SLOT(linkClicked(QUrl)));
I am not sure it will be useful for you, but in my app using QWebEngineView, I have clickable links which must open the corresponding website in a browser.
The way I am doing it is like that :
class MyQWebEnginePage : public QWebEnginePage
{
Q_OBJECT
public:
MyQWebEnginePage(QObject* parent = 0) : QWebEnginePage(parent){}
bool acceptNavigationRequest(const QUrl & url, QWebEnginePage::NavigationType type, bool)
{
if (type == QWebEnginePage::NavigationTypeLinkClicked)
{
QDesktopServices::openUrl(url);
return false;
}
return true;
}
};
As you can see, I just reimplemented the virtual method acceptNavigationRequest of QWebEnginePage in order to retrieve the url from the link clicked : url. I don't know it is what you want to achieve, but I hope that helps.
Related
I created myself simple window for debugging purposes. It's completely separate QMainWindow, so that I can put it on the other monitor when testing the app. But when there's a dialog in my application, I cannot access the window. Right now, this is exactly the time I WANT to access it.
I tried to override QWidget::event like so:
DebugWindow.h
#include <QtWidgets/QMainWindow>
QT_BEGIN_NAMESPACE
class QEvent;
QT_END_NAMESPACE
class DebugWindow : public QMainWindow
{
Q_OBJECT
public:
DebugWindow(QWidget *parent = 0);
virtual ~DebugWindow();
protected:
virtual bool event(QEvent*);
};
DebugWindow.cpp
bool TechadminScript::event(QEvent* e)
{
if (e->type() == QEvent::WindowBlocked) {
// accept the event to stop propagation
e->accept();
return true;
}
return false;
}
I have set up breakpoint in the overriden function and it was hit - that means I did something right. But the window is still blocked as it was before.
So I am probably missing something, can somebody help me finish this?
It worked for me setting the window modality as #king_nak suggested. Mind you have to hide() beforehand and show() according to the documentation: https://doc.qt.io/qt-5/qwidget.html#windowModality-prop
bool Object::eventFilter(QObject *, QEvent * const event)
{
if (event->type() != QEvent::WindowBlocked)
return false;
for (auto&& widget : qApp->topLevelWidgets())
{
if (!widget->isModal())
continue;
widget->hide();
widget->setWindowModality(Qt::NonModal);
widget->show();
}
return true;
}
TL;DR
I want to register a Qt Designer extension but don't want any widget plugin, so any of the following can solve my problem:
How do I create a plugin in Qt Designer that doesn't expose any widget in the widget box but that can register extensions?
How do I register the extension without subclassing of QDesignerCustomWidgetInterface?
I'm working on a set of plugins for Qt Designer. These plugins expose custom widgets to the designer. All widgets (some dozens) inherit from a common class (CCommonWidget), such as:
CCommonWidget
|-> CLabel
|-> CPushButton
...
CCommonWidget define some common properties for all widgets. I'd like to expose them to Qt Designer through extensions (for example, the QDesignerTaskMenuExtension).
I started with a test in the CLabel plugin. Here the two relevant methods:
// Register the extensions in Qt Designer
void CLabelPlugin::initialize(QDesignerFormEditorInterface *formEditor)
{
if (m_initialized) return;
auto extensionManager = formEditor->extensionManager();
Q_ASSERT(extensionManager);
extensionManager->registerExtensions(new CLabelPluginFactory(extensionManager), Q_TYPEID(QDesignerTaskMenuExtension));
m_initialized = true;
}
// The factory creates the menu extension if the widget is a CLabel
QObject* CLabelPluginFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const
{
if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) return nullptr;
if (auto label = dynamic_cast<CLabel*>(object))
return new CLabelPluginMenu(label, parent);
return nullptr;
}
It worked flawlessly and I was about to extend the idea to the rest of the plugins. Instead of copy/pasting the code I started with a CCommonPlugin and make every one to inherit from it. In order to make it as re-usable as possible I changed the createExtension method to:
QObject* CCommonPluginFactory::createExtension(QObject *object, const QString &iid, QObject *parent) const
{
if (iid != Q_TYPEID(QDesignerTaskMenuExtension)) return nullptr;
if (auto label = dynamic_cast<CCommonWidget*>(object))
return new CCommnPluginMenu(label, parent);
return nullptr;
}
Here I realized that even if only on plugin (CLabelPlugin) was registering the extension factory, any other widget which inherits from CCommonWidget will show the menu! (It was pretty obvious once I discovered it but before I just didn't think on it).
Now it was easier since I hadn't to change all the plugins (dozens) but just to create a new one, a dummy common plugin, that registers the extension factory.
The dummy plugin I've first created:
class CPluginCommon : public QObject, public QDesignerCustomWidgetInterface {
Q_OBJECT
Q_INTERFACES( QDesignerCustomWidgetInterface )
public:
explicit CPluginCommon( QObject* parent=0 );
public: // QDesignerCustomWidgetInterface
QWidget* createWidget( QWidget* parent ) { return nullptr; }
QString group() const { return QString(); }
QIcon icon() const { return QIcon(); }
QString includeFile() const { return QString(); }
bool isContainer() const { return false; }
QString name() const { return QString(); }
QString toolTip() const { return QString(); }
QString whatsThis() const { return QString(); }
virtual bool isInitialized() const override {
return m_initialized;
}
virtual void initialize(QDesignerFormEditorInterface *formEditor) override;
private:
bool m_initialized;
};
But a blank widget is displayed in the widget box of Qt Designer. I don't want an empty widget, I want no widget!
Another option is not to use these kind of plugins but I'm struggling to find a way to register the extension without a QDesignerCustomWidgetInterface, but all that I can find is to get the extensions manager within QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface *formEditor) (using formEditor->extensionManager()).
Quick answer
To hide the widget from the widget box just return an empty XML (this is an undocumented feature):
class CPluginCommon : public QObject, public QDesignerCustomWidgetInterface {
// ...
public:
QString domXml() const { return QString(); }
};
Reviewing the code of the plugins manager of Qt Designer, I found in the QDesignerPluginManagerPrivate::addCustomWidget method the following (c is a pointer to QDesignerCustomWidgetInterface)
const QString domXml = c->domXml();
if (!domXml.isEmpty()) { // Legacy: Empty XML means: Do not show up in widget box.
Given that, I saw that the default implementation of domXml does return a tiny XML fragment for a generic widget:
virtual QString domXml() const
{
return QString::fromUtf8("<widget class=\"%1\" name=\"%2\"/>")
.arg(name()).arg(name().toLower());
}
For completeness, as far as I have seen in the source code of the plugins manager of the Qt Designer, there is no way to load a plugin that doesn't inherits from QDesignerCustomWidgetInterface:
// Load plugins into widget database and factory.
void QDesignerIntegration::initializePlugins(QDesignerFormEditorInterface *formEditor)
{
// load the plugins
WidgetDataBase *widgetDataBase = qobject_cast<WidgetDataBase*>(formEditor->widgetDataBase());
if (widgetDataBase) {
widgetDataBase->loadPlugins();
}
if (WidgetFactory *widgetFactory = qobject_cast<WidgetFactory*>(formEditor->widgetFactory())) {
widgetFactory->loadPlugins();
}
if (widgetDataBase) {
widgetDataBase->grabDefaultPropertyValues();
}
}
where
void WidgetDataBase::loadPlugins()
{
// ...
// 2) create a list plugins
ItemList pluginList;
const QDesignerPluginManager *pm = m_core->pluginManager();
foreach(QDesignerCustomWidgetInterface* c, pm->registeredCustomWidgets())
pluginList += createCustomWidgetItem(c, pm->customWidgetData(c));
// ...
}
void WidgetFactory::loadPlugins()
{
m_customFactory.clear();
QDesignerPluginManager *pluginManager = m_core->pluginManager();
QList<QDesignerCustomWidgetInterface*> lst = pluginManager->registeredCustomWidgets();
foreach (QDesignerCustomWidgetInterface *c, lst) {
m_customFactory.insert(c->name(), c);
}
}
I have a TextEdit in my QML file and I have a QSyntaxHighlighter C++ class. I want to specify the highlighting logic in the C++ class and apply it to the TextEdit, but I am not sure how to make the connection between the QML object and the C++ class. Can you also please provide some sample code? I couldn't find how to implement it with the Qt documentation.
You can use TextEdit::textDocument, which holds an instance of QQuickTextDocument, to gain access to the underlying QTextDocument that you can pass to QSyntaxHighlighter constructor.
In case someone needs a more detailed explanation for this.
First, I created a Q_PROPERTY inside a custom C++ class.
Q_PROPERTY(QQuickTextDocument* mainTextEdit READ mainTextEdit WRITE setMainTextEdit NOTIFY mainTextEditChanged)
Then I assign textEdit.textDocument to the Q_PROPERTY in the QML.
customClass.mainTextEdit = textEdit.textDocument
Then I call initHighlighter() (the function has to be Q_INVOKABLE) in my QML which calls the constructor of my highlighter class and passes it the text document of the textEdit.
void initHighlighter()
{
Highlighter *highlighter;
highlighter = new Highlighter(m_mainTextEdit->textDocument());
}
Note: The custom highlighter class needs to be derived from QSyntaxHighlighter.
Sample implementation:
HighlightComponent.h
class HighlightComponent : public QObject
{
Q_OBJECT
//#formatter:off
Q_PROPERTY(QString text
READ getText
WRITE setText
NOTIFY textChanged)
//#formatter:on
using inherited = QObject;
public:
explicit HighlightComponent(QObject* parent = nullptr);
static void registerQmlType();
const QString& getText()
{
return _text;
}
void setText(const QString& newText)
{
if (newText != _text)
{
_text = newText;
emit textChanged();
}
}
Q_INVOKABLE void onCompleted();
signals:
void textChanged();
private:
std::unique_ptr<QSyntaxHighlighter> _highlight;
QString _text = "";
};
HighlightComponent.cpp
HighlightComponent::HighlightComponent(QObject* parent)
: inherited(parent)
{
}
void HighlightComponent::onCompleted()
{
auto property = parent()->property("textDocument");
auto textDocument = property.value<QQuickTextDocument*>();
auto document = textDocument->textDocument();
//TODO init here your QSyntaxHighlighter
}
void HighlightComponent::registerQmlType()
{
qmlRegisterType<HighlightComponent>("com.HighlightComponent", 1, 0, "HighlightComponent");
}
main.cpp
int main(int argc, char* argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
HighlightComponent::registerQmlType();
engine.load(QUrl(QStringLiteral("qrc:/view/main.qml")));
return app.exec();
}
Sample QML
TextArea {
id: testTextArea
text: testTextArea.text
//inputMethodHints: Qt.ImhNoPredictiveText
onTextChanged: {
testTextArea.text = text
}
HighlightComponent {
id: testTextArea
Component.onCompleted: onCompleted()
}
}
Links:
https://wiki.qt.io/How_to_Bind_a_QML_Property_to_a_C%2B%2B_Function
http://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html
http://wiki.qt.io/Spell-Checking-with-Hunspell
http://doc.qt.io/qt-5/qtqml-cppintegration-interactqmlfromcpp.html
http://doc.qt.io/qt-5/qtwidgets-richtext-syntaxhighlighter-example.html
I'm working on an application that uses a MDI. I have a bunch of toolbox and menu bar defined in a main window containing the QMDIArea.
All subwindows are of the same class. In order to connect the buttons to the active sub window, I did the following think:
void MainWindow::zoomOut() {
QMdiSubWindow* sub_window = central_document_interface->currentSubWindow();
if (sub_window) {
PlanWindow* plan_window = (PlanWindow*)(sub_window->widget());
plan_window->zoomOut();
}
}
I think it would be smarter to reconnect the signals using the subWindowActivated signal. But the problem I have is that I intend to have several types of sub window (different classes). All signal aren't used by all these classes.
I can't manage to find a clean way to differentiate them and connect or not the signals according to their class. How would you do this ?
I created this code for my project:
void MainWindow::slot_menuEditZoomOut() {
WindowAreaManagerInterface::instance()->
LambaOnCurrentCustomWindow<CAbstractZoomAction>([](CAbstractZoomAction *zoom){ zoom->zoomOut(); });
}
Where the WindowAreaManagerInterface is
class WindowAreaManagerInterface : public QMdiArea {
Q_OBJECT
public:
static WindowAreaManagerInterface *instance();
template<class T>
T *currentCustomWindow() {
QWidget *widget = 0;
QMdiSubWindow *subWindow = currentSubWindow();
if (subWindow) widget = subWindow->widget();
return dynamic_cast<T *> (widget);
}
template<class T, typename Func>
void LambaOnCurrentCustomWindow(Func F) {
T *window = currentCustomWindow<T>();
if (window)
F(window);
}
//other methods follow..
}
Hope this help.
How would one extend the standard icons provided by the QStyle class with support for Windows and Linux in mind?
namespace Ui {
class TVLoader;
}
class TVLoader : public QMainWindow
{
Q_OBJECT
public:
explicit TVLoader(QWidget *parent = 0) :
QMainWindow(parent),
ui(new Ui::TVLoader)
{
ui->setupUi(this);
ui->actionAdd_TV_Show->setIcon(style()->standardIcon(?)); // this is where I would need some kind of "Add" icon which unfortunately doesn't exist
}
You man want to subclass QStyle if you want to provide your own icons, reimplement the standardIconImplementation() slot in your subclass and return a new icon from there. Below is an example:
class MyProxyStyle : public QProxyStyle
{
Q_OBJECT
public:
MyProxyStyle(QStyle *style = 0) : QProxyStyle(style) { }
public slots:
QIcon standardIconImplementation(StandardPixmap standardIcon,
const QStyleOption *option = 0,
const QWidget *widget = 0) const
{
// check the standardIcon parameter for the icon type
if (standardIcon==QStyle::SP_DesktopIcon)
{
// return your new icon here
standardIcon = QStyle::SP_DirIcon;
}
return QProxyStyle::standardIconImplementation(standardIcon, option, widget);
}
};
here's how can you use it:
// set new style for your widget
setStyle(new MyProxyStyle(style()));
// return different icon for QStyle::SP_DesktopIcon
action0->setIcon(style()->standardIcon(QStyle::SP_DesktopIcon));
hope this helps, regards
Since 4.6, Qt can use freedesktop icon theme:
QIcon undo_icon = QIcon::fromTheme("edit-undo");
But there is no icon themes in Windows (and MacOS). However, you can use any theme you want there, all you need is put this theme into (or part of it) into :/icons resource directory and do following in main():
if (!QIcon::hasThemeIcon("document-open")) {
QIcon::setThemeName("/");
}
(it is hack for QTBUG-16697).