Touch freeze in QtWebEngine after opening a DropDown menu - qt

I stumbled across a QtWebEngine problem while using a touch display. I can browse through all websites via my touch display, but when I click on a DropDown menu (for example on https://www.ebay.com/ clicking on "All categories" next to the search field), touch is not working anymore (or 1/30 touch clicks works). I can still close it via mouse/keyboard. After closing the DropDown menu, touch is working again.
I created a small example browser:
BrowserWidget::BrowserWidget(QWidget *parent)
: QWidget(parent), ui(new Ui::BrowserWidget),
m_webView(new QWebEngineView(this)), m_page(new QWebEnginePage(this)) {
ui->setupUi(this);
ui->verticalLayout->addWidget(m_webView);
m_page->setUrl(QUrl(QStringLiteral("https://www.ebay.com/")));
m_webView->setPage(m_page);
m_webView->setAttribute(Qt::WA_AcceptTouchEvents);
m_webView->installEventFilter(this);
}
bool BrowserWidget::eventFilter(QObject *watched, QEvent *e) {
qDebug() << "event: " << e->type();
if (e->type() == QEvent::ChildAdded) {
QChildEvent *ce = static_cast<QChildEvent *>(e);
if (ce && ce->child()) {
ce->child()->installEventFilter(this);
}
}
return false;
}
I installed my event filter to the widgets in the QEvent::ChildAdded for a better debugging (so I can observe more events).
This behaviour is always reproducable and I don't know if I did something wrong, because I can operate the browser via touch. I also added the Qt::WA_AcceptTouchEvents to the child widgets, but it didn't make any difference.
I hope somebody of you can help me out, thank you!

Found out that it is a Qt-bug
https://bugreports.qt.io/browse/QTBUG-79254
I created a workaround for this problem, maybe somebody needs this in the future:
bool WebEngineView::event(QEvent *e)
{
// Workaround for QTBUG-79254: DropDown-menus are not accepting any touchevents
if (e->type() == QEvent::ChildAdded) {
QChildEvent *ce = static_cast<QChildEvent *>(e);
if (ce && ce->child() && ce->child()->isWidgetType()) {
QWidget *child = static_cast<QWidget *>(ce->child());
if (child->windowFlags() & Qt::Popup) {
Qt::WindowFlags flags = child->windowFlags();
flags = flags & (~Qt::Popup) | Qt::Dialog;
child->setWindowFlags(flags);
}
}
}
return QWebEngineView::event(e);
}

Related

How to re-enable close button in qt dialog

I am using QProgressDialogand I disable the close (x) button when I start the progress bar.
progress->setWindowFlags(progress->windowFlags() & ~Qt::WindowCloseButtonHint);
After the operation is complete in QProcess, in the finished slot, I am re-enabling the close button but it doesn't work. It instead closes the progress window. I have tried both lines below but it does the same.
progress->setWindowFlags(progress->windowFlags() | Qt::WindowCloseButtonHint);
or
progress->setWindowFlags(progress->windowFlags() | Qt::WindowCloseButtonHint | Qt::CustomizeWindowHint);
Why is it not working the way it should?
I figured out problem. You dialog is hidden and there are no way to solve that. You can only show() it again.
As doc said:
Note: This function calls setParent() when changing the flags for a
window, causing the widget to be hidden. You must call show() to make
the widget visible again.
From Qt source:
void QWidget::setWindowFlags(Qt::WindowFlags flags)
{
if (data->window_flags == flags)
return;
Q_D(QWidget);
if ((data->window_flags | flags) & Qt::Window) {
// the old type was a window and/or the new type is a window
QPoint oldPos = pos();
bool visible = isVisible();
setParent(parentWidget(), flags);
^^^^^^^^^
// if both types are windows or neither of them are, we restore
// the old position
if (!((data->window_flags ^ flags) & Qt::Window)
&& (visible || testAttribute(Qt::WA_Moved))) {
move(oldPos);
}
// for backward-compatibility we change Qt::WA_QuitOnClose attribute value only when the window was recreated.
d->adjustQuitOnCloseAttribute();
} else {
data->window_flags = flags;
}
}
And as doc said again:
Note: The widget becomes invisible as part of changing its parent,
even if it was previously visible. You must call show() to make the
widget visible again.
For example:
MainWindow w;w.show();
w.setWindowFlags(w.windowFlags() & ~Qt::WindowCloseButtonHint);
w.setWindowFlags(w.windowFlags() | Qt::WindowCloseButtonHint);
w.show();

Qt wheelEvent over all

I have app window with many layouts and widget. I have also scrollarea with switch-off scrollbars. I am able to create slots for scrollareaup and scrollareadown. But when I create wheelEvent for all App it's working only for items int app NOT in scrollarea. When I just try this:
void TContic_win::wheelEvent(QWheelEvent *event) {
cout << "-" << endl;
}
I don't know how I can fix it. My idea is something like:
bool TContic_win::eventFilter(QObject *obj, QEvent *e) {
if (isChildOfScrollWidget(obj) { if (e == wheel) scroll Up or Down }
}
You may do something like this (in case if your widgets have Your_Scrol_Widget as parent):
void TContic_win::wheelEvent(QWheelEvent *we)
{
if (this->childAt( we->pos() )->parent() == Your_Scrol_Widget)
qDebug() << "-" ;
}
You must got an idea.
I am sorry. It's my mistake. I had a wrong event filter. I used 'return true' in bad conditions so due to this mistake I was always ignore other events and my event filter doesn't work over child items. By the way, thanks for your effort.

How to make QComboBox popup upwards?

my QComboBox-derived class lives in a QGraphicsScene at the bottom end of the (visible) screen - but it pops up downwards, thus out of view.
(How) is it possible to force the popup to open above the widget?
I've tried re-implementing showPopup like this:
void MyComboBox::showPopup()
{
QAbstractItemView *popupView = view();
popupView->move(0,-100);
//popupView->window->move(0,-100);
QComboBox::showPopup();
}
The result is, that the content seems to be shifted, but not the underlying popup object.
I think it might be possible to find a solution with styles as indicated in
this article, but I can't find any Styles control that might be helpful here. I am rather new to C++ as well as Qt, so I might be missing something obvious.
I'd appreciate any help on this matter!
Best regards,
Sebastian
With the information found here, I was able to get it done this way:
void SteuerQComboBox::showPopup() {
QComboBox::showPopup();
QWidget *popup = this->findChild<QFrame*>();
popup->move(popup->x(),popup->y()-this->height()-popup->height());
}
Note that it's crucially important to call the base classes "showPopup" first.
Thanks to everybody who was reading my question and thinking about it!
user1319422's solution isn't bad, but it has two problems.
If your platform has GUI animation, the listbox will animate opening downwards, then is moved above the text box.
If you disable combobox animation (or you don't have it), the call to QComboBox::showPopup() still makes the GUI element start to appear on the screen already. So, moving it there would cause it to flicker as it appears in the first place and moves to the next.
So, to address the first problem, I just switched off animation:
void MyComboBox::showPopup()
{
bool oldAnimationEffects = qApp->isEffectEnabled(Qt::UI_AnimateCombo);
qApp->setEffectEnabled(Qt::UI_AnimateCombo, false);
QComboBox::showPopup();
qApp->setEffectEnabled(Qt::UI_AnimateCombo, oldAnimationEffects);
}
Then, for the second problem, I moved the frame in the Show event:
bool MyComboBox::eventFilter(QObject *o, QEvent *e)
{
bool handled = false;
if (e->type() == QEvent::Show)
{
if (o == view())
{
QWidget *frame = findChild<QFrame*>();
//For some reason, the frame's geometry is GLOBAL, not relative to the QComboBox!
frame->move(frame->x(),
mapToGlobal(lineEdit()->geometry().topLeft()).y() - frame->height());
}
}
/*else if other filters here*/
if (!handled)
handled = QComboBox::eventFilter(o, e);
return handled;
}
if you want to force popup to open above only when it is out of view you can do this:
void SteuerQComboBox::showPopup() {
QComboBox::showPopup();
QWidget *popup = this->findChild<QFrame*>();
if((popup->y() + popup->height()) > this->window()->height())
popup->move(popup->x(),popup->y()-this->height()-popup->height());
}

How to tell the mouse button using QApplication::mouseButtons() in a "click" slot?

I have a QMainWindow, and want to handle the "clicked" signal from a smaller widget (such as tableview) inside it.
Originally I connect the signal to a slot of this QMainWindow, this is the most common approach.
Now I need to tell which mouse button is clicked, and do different things for left and right button, I found that the "clicked" signal don't have the mouse event information.
I tried to implement the "mousePressEvent" function,but there are still some problem. if the mouse action is acted on the smaller widget, the MainWindow won't go into its mousePressEvent.
Some document says that we can tell the button by QQApplication::mousebuttons()
http://bugreports.qt-project.org/browse/QTBUG-1067
and I also found some sample code. However, this is for "press event", but I want to get the mouse button for "click event".
Follows is the sample code :
connect(moduleTree,SIGNAL(itemPressed(QTreeWidgetItem *, int)),this,SLOT(SlotItemClicked(QTreeWidgetItem *, int)));
void CGuiMainwindow::SlotItemClicked(QTreeWidgetItem *item, int column)
{
if (qApp->mouseButtons() == Qt::LeftButton)
{ return; }
if (qApp->mouseButtons() == Qt::RightButton)
{
......
}
}
When I try to do this, neither of the 2 if statements will be satisfied, I don't know why. the qApp->mouseButtons() always return 0, how can I get the clicked mouse button by QApplication::mouseButtons?
In my code, the slot looks like that :
void clickItem( const QModelIndex & idx){.....}
You get 0 becouse clicked is emited after mouse release, not at mouse press. What do you want to achieve ? Maybe try settings on you widget contextMenuPolicy to custom, and than connect to signal contextMenuRequested (for the right click) and clicked for the left click ?
for "connect" use this:
connect(moduleTree,SIGNAL(itemClicked(QTreeWidgetItem *,int )),this
,SLOT(SlotItemClicked(QTreeWidgetItem *, int)));
define a global flag:
public:
Qt::MouseButton mouseClickedBtnFlag;
and then reimplement "mouseReleaseEvent":
CGuiMainwindow::mouseReleaseEvent ( QMouseEvent * event )
{
mouseClickedBtnFlag = event->button();
}
and then:
void CGuiMainwindow::SlotItemClicked(QTreeWidgetItem *item, int column)
{
if (mouseClickedBtnFlag == Qt::LeftButton)
{ return; }
if (mouseClickedBtnFlag == Qt::RightButton)
{
......
}
}
Qt::MouseButtons is a QFlags type. You can't test it with == operator. Use & operator for testing:
if(QApplication::mouseButtons() & Qt:LeftButton) {
...
}

Getting MouseMoveEvents in Qt

In my program, I'd like to have mouseMoveEvent(QMouseEvent* event) called whenever the mouse moves (even when it's over another window).
Right now, in my mainwindow.cpp file, I have:
void MainWindow::mouseMoveEvent(QMouseEvent* event) {
qDebug() << QString::number(event->pos().x());
qDebug() << QString::number(event->pos().y());
}
But this seems to only be called when I click and drag the mouse while over the window of the program itself. I've tried calling
setMouseTracking(true);
in MainWindow's constructor, but this doesn't seem to do anything differently (mouseMoveEvent still is only called when I hold a mouse button down, regardless of where it is). What's the easiest way to track the mouse position globally?
You can use an event filter on the application.
Define and implement bool MainWindow::eventFilter(QObject*, QEvent*). For example
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
statusBar()->showMessage(QString("Mouse move (%1,%2)").arg(mouseEvent->pos().x()).arg(mouseEvent->pos().y()));
}
return false;
}
Install the event filter when the MainWindows is constructed (or somewhere else). For example
MainWindow::MainWindow(...)
{
...
qApp->installEventFilter(this);
...
}
I had the same problem, further exacerbated by the fact that I was trying to call this->update() to repaint the window on a mouse move and nothing would happen.
You can avoid having to create the event filter by calling setMouseTracking(true) as #Kyberias noted. However, this must be done on the viewport, not your main window itself. (Same goes for update).
So in your constructor you can add a line this->viewport()->setMouseTracking(true) and then override mouseMoveEvent rather than creating this filter and installing it.

Resources