How to get the MainWindow winId from a subclass? - c++

When i have the subclass below running in two different 'MainWindow' guis, how i could get the winId from the 'MainWindow' which this widget belongs to?
I tried:
class Test: public QFrame
{
Q_OBJECT
public:
Test(QWidget* parent = 0) : QFrame(parent)
{
QWidget* widget = this;
while (widget->parentWidget() != NULL)
{
widget = widget->parentWidget();
//qDebug() << "name: " << widget->objectName();
}
HWND id = (HWND)widget->winId();
}
}
Theres another way than walking over parentWidget()?

Related

How to detect when a QWebEngineView widget is opened/closed?

I'm adding the discord widget from widgetbot to a grid layout in a way it can expand above other widgets, the problem is, even when the widget is 'closed' the QWebEngineView widget occupies the entire area blocking things below it to be clicked:
I thought of setting a maximum size to the widget when it is opened and another when it's closed so it doesn't overlay other widgets when it's not 'opened'.
I tried installing an event filter but it didn't throw any event when the widget is opened/closed, would like to ask what other way I could detect it?
#include "discordwidget.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
auto wdgt = new DiscordWidget(this);
}
//discordwidget.h
#include <QtWebEngineWidgets>
class DiscordWidget : public QWebEngineView
{
Q_OBJECT
public:
DiscordWidget(QWidget* parent = 0) : QWebEngineView(parent)
{
this->page()->setBackgroundColor(Qt::transparent);
// Tutorial: https://docs.widgetbot.io/embed/crate/tutorial/#getting-started
this->page()->setHtml(R"(
<script src='https://cdn.jsdelivr.net/npm/#widgetbot/crate#3' async defer>
new Crate({
server: '', // Replace with your discord server
channel: '' // ... channel
})
</script>
)");
this->installEventFilter(this);
this->page()->installEventFilter(this);
}
bool eventFilter(QObject *obj, QEvent *e)
{
qDebug() << e->type();
if( e->type() == QEvent::ChildAdded )
{
QChildEvent *ce = static_cast<QChildEvent*>(e);
ce->child()->installEventFilter(this);
}
return false;
}
};

QEvent on property set in QML

I would like to catch QEvent in my custom cpp QObject (MyObject) if some of the properties is changed (QEvent::DynamicPropertyChange):
class MyObject : public QObject
{
Q_OBJECT
Q_PROPERTY(bool value MEMBER mValue)
public:
MyObject();
bool event(QEvent *e) override
{
qDebug() << "EVENT RECIEVED" << e->type();
return QObject::event(e);
}
private:
bool mValue = false;
};
It works great if i do this in cpp:
MyObject obj = MyObject();
obj.setProperty("val", true);
But it does not if I try to change property in QML:
MyObject {
id: obj
}
Button{
id: button
text: "set value"
onClicked: function () {
console.log('button clicked');
obj.value = true;
}
}
This is a simple github example of this.
Any ideas ?

Qt: propagate mouse clicks through a transparent widget

I'm trying to create a widget which, when shown, it will intercept any mouse clicks, process them, but then forward the click to the widget that was under the mouse when it was clicked. I've created a class that represents this widget; all it does for now is capture mouse release events, hide itself and post the event to the widget the click was intended for using QApplication::postEvent:
class Overlay : public QWidget
{
Q_OBJECT
public:
Overlay(QWidget* parent)
: QWidget(parent){}
protected:
void mouseReleaseEvent(QMouseEvent* event)
{
hide();
auto child = parentWidget()->childAt(event->pos()); // get the child widget the event was intended for
auto e = new QMouseEvent(*event);
if(child) QCoreApplication::postEvent(child, e); // why doesn't this have any effect?
event->accept();
}
void paintEvent(QPaintEvent* event)
{
QPainter p(this);
p.fillRect(rect(), QColor(0,0,0,150));
}
};
Unfortunately, the call to postEvent doesn't seem to have any effect at all. Here is an example where I'm setting up some child widgets; clicking on any widget will print something out:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr)
{
m_overlay = new Overlay(this);
m_overlay->hide();
auto button = new QPushButton("Add overlay");
auto button2 = new QPushButton("PushButton");
auto list = new QListWidget();
list->addItems(QStringList() << "item1" << "item2" << "item3");
connect(list, &QListWidget::itemClicked, [](const QListWidgetItem* item)
{
qDebug() << item->text();
});
connect(button2, &QPushButton::clicked, []()
{
qDebug() << "Button clicked";
});
connect(button, &QPushButton::clicked, [this]()
{
m_overlay->setGeometry(rect());
m_overlay->raise();
m_overlay->show();
});
auto layout = new QVBoxLayout(this);
layout->addWidget(list);
layout->addWidget(button);
layout->addWidget(button2);
}
public:
~Widget(){}
private:
Overlay* m_overlay;
};
I've confirmed that clicks on the overlay are captured and the overlay is hidden as intended but the event is not propagated to the underlying widget. Using QApplication::sendEvent doesn't work either. What am I missing?
Using Qt 5.15.1 on MacOS 11.2.3. Thanks

Custom QML QQuickPainted Item Member anchors not set to parent in qml

I am having a problem getting a member of a custom QQuickItem I created to anchor to its parent. I know that it is loading and the constructor is running because of some debug statements I placed, however for some reason anchoring to parent is not working on the sub-object.
Note: lots of shortening of code happened here. I hope everything is relevant without being overwhelming
qml Snippet
PDFDocument
{
id: pdfDocument
anchors.fill: parent
visible: false
pageView
{
dpi: 200
//this is not working and paint is not being called
//QML PDFPageView: Cannot anchor to an item that isn't a parent or sibling.
anchors.fill: parent
}
}
c++ code snippets
// PDFPageView.h
namespace TechnicalPublications
{
class PDFPageView : public QQuickPaintedItem
{
public:
Q_OBJECT
Q_PROPERTY( int dpi MEMBER m_dpi NOTIFY dpiChanged )
Q_SIGNALS:
void dpiChanged();
public:
PDFPageView( QQuickItem* parent = nullptr );
~PDFPageView();
void setPage( Poppler::Page* page_p );
void paint( QPainter* painter_p );
private:
Poppler::Page* m_page_p;
};
}
//PDFPage.cpp
namespace TechnicalPublications
{
PDFPageView::PDFPageView( QQuickItem* parent )
: QQuickPaintedItem( parent )
{
LOG_DEBUG( __FILE__, __LINE__ ) << "Page parent" << parent;
LOG_DEBUG( __FILE__, __LINE__ ) << "constructing PageView" << this;
}
void PDFPageView::setPage( Poppler::Page* page_p )
{
m_page_p = page_p;
update();
}
void PDFPageView::paint( QPainter* painter_p )
{
LOG_DEBUG( __FILE__, __LINE__ ) << "painting pdf page";
//deleted sections for spacing, point is paint is not called because size is 0
}
}
//PDFDocument.h
class PDFDocument : public QQuickItem
{
public:
Q_OBJECT
Q_PROPERTY( TechnicalPublications::PDFPageView* pageView READ getPageView )
PDFDocument( QQuickItem* parent = nullptr );
~PDFDocument();
PDFPageView* getPageView() { return &m_pageView; }
private:
PDFPageView m_pageView;
};
}
#endif // PDFDOCUMENT_H
//PDFDocument.cpp
namespace TechnicalPublications
{
PDFDocument::PDFDocument( QQuickItem* parent /*= nullptr*/ )
: QQuickItem( parent ),
m_pageView( this )
{
LOG_DEBUG( __FILE__, __LINE__ ) << "Document parent " << parent;
LOG_DEBUG( __FILE__, __LINE__ ) << "constructing Document " << this;
}
PDFDocument::~PDFDocument()
{
}
}
I would even be happy to set the anchors to always take the parent in the c++ is possible, but I know visual settings like that are supposed to be handled in QML specifically. Any thoughts on why this is being a problem?
It's because the scope of your grouped property (just a nested QObject* property), is the same of the parent object.
so when you do:
PDFDocument {
id: pdfDocument
pageView {
anchors.fill: parent
}
}
parent is referring to the parent of pdfDocument.
You want to do anchors.fill: pdfDocument.
Alternatively it might makes sense to anchor it in c++ and avoid doing it in QML if always need to do it.

How to make QMenu Item checkable in QT

How to give Qmenu item checkable using QT
QMenu *preferenceMenu = new QMenu();
preferenceMenu = editMenu->addMenu(tr("&Preferences"));
QMenu *Mode1 = new QMenu();
Mode1 = preferenceMenu->addMenu(tr("&Mode 1"));
Mode1->addAction(new QAction(tr("&Menu1"), this));
QMenu *Mode2 = new QMenu();
Mode2 = preferenceMenu->addMenu(tr("&Mode 2"));
Mode2->addAction(new QAction(tr("&Menu2"), this));
Mode2->addAction(new QAction(tr("&Menu3"), this));
On QAction I called slot "slotActionTriggered(QAction* actionSelected)"
void csTitleBar::slotActionTriggered(QAction* actionSelected)
{
actionSelected->setChecked(true);
}
How to show small TICK in the selected Menu# so that user can know which is selected
Currently I am able to change to all Menu#, but I need to show a small tick on menu so that the selected one can be easly Identified
Small example:
cmainwindow.h
#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H
#include <QMainWindow>
#include <QPointer>
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
CMainWindow(QWidget *parent = 0);
~CMainWindow();
private slots:
void slot_SomethingChecked();
private:
QPointer<QAction> m_p_Act_Button1 = nullptr;
QPointer<QAction> m_p_Act_Button2 = nullptr;
};
#endif // CMAINWINDOW_H
cmainwindow.cpp
#include "cmainwindow.h"
#include <QtWidgets>
#include <QDebug>
CMainWindow::CMainWindow(QWidget *parent)
: QMainWindow(parent)
{
m_p_Act_Button1 = new QAction("Super Button 1", this);
m_p_Act_Button1->setCheckable(true);
m_p_Act_Button1->setChecked(true);
connect(m_p_Act_Button1, SIGNAL(triggered()), this, SLOT(slot_SomethingChecked()));
m_p_Act_Button2 = new QAction("Super Button 2", this);
m_p_Act_Button2->setCheckable(true);
m_p_Act_Button2->setChecked(true);
connect(m_p_Act_Button2, SIGNAL(triggered()), this, SLOT(slot_SomethingChecked()));
QMenu *p_menu = menuBar()->addMenu("My Menu");
p_menu->addAction(m_p_Act_Button1);
p_menu->addAction(m_p_Act_Button2);
}
CMainWindow::~CMainWindow() { }
void CMainWindow::slot_SomethingChecked()
{
if(!m_p_Act_Button1 || !m_p_Act_Button2) {return;}
qDebug() << "Hi";
if(m_p_Act_Button1->isChecked())
{
qDebug() << "The action 1 is now checked";
}
else
{
qDebug() << "The action 1 is now unchecked";
}
if(m_p_Act_Button2->isChecked())
{
qDebug() << "The action 2 is now checked";
}
else
{
qDebug() << "The action 2 is now unchecked";
}
}
Modern connection syntax is preferable.
Checkable items can also be used on context menu as follow :
void MyWidget::initContextMenu()
{
if( _contextMenu)
{
delete _contextMenu;
}
_contextMenu = new QMenu(this);
auto action1 = new QAction("Action Item 1", &_contextMenu);
action1->setCheckable(true);
action1->setChecked(getMyProperty1());
connect(action1 , &QAction::triggered, this, &MyWidget::setMyProperty1);
_contextMenu->AddAction( action1 );
}
void MyWidget::contextMenuEvent(QContextMenuEvent *event)
{
initContextMenu();
_contextMenu.popup(
this->viewport()->mapToGlobal(
event->pos()));
}
bool MyWidget::setMyProperty1(bool state)
{
_myProperty1 = state;
emit MyPropertyChanged(_myProperty);
}