I've reimp. QWebView::contextMenuEvent(QContextMenuEvent*) and it takes no effect on right click on the widget.
Here is my code:
void ExtendedWebView::contextMenuEvent(QContextMenuEvent *event)
{
qDebug() << "called";
m_copyAction->setEnabled(!selectedHtml().isEmpty());
m_contextMenu->setVisible(true);
m_contextMenu->exec(event->globalPos());
}
When I make right-click on the widget, it takes no effect - no menu is shown. What am I doing wrong?
UPD: http://paste.kde.org/640508/ - full code
The current version of Marble's PopupItem where this QWebView is running in does not forward the contextMenuEvent. Change its eventFilter to do that and you'll receive the event.
Related
I'm running a Qt 5.9.4 app with QWebView on a touch linux device displaying HTML webpages.
When users pinch their fingers on the screen, they zoom into the webpage. I want to disable that behaviour, because all the webpages should be 100% fullscreen.
I could temporarily disable it in the webpages (since I own their code) by adding user-scalable=no to the viewport, but that wont work in the long run because not every webpage will have that.
I tried to use eventFilter on different elements of my app, but couldn't get any Gesture or even Mouse event to catch.
This is how I create my webview (in a QDialog):
void Dialog::createWebView() {
view = new QWebEngineView(this);
profile = new QWebEngineProfile();
page = new QWeEnginePage(profile);
view->setPage(page);
view->setUrl(QUrl(path));
}
This is my eventFilter class:
EvFilter::EvFilter(QObject *parent) : QObject(parent)
{
}
bool EvFilter::eventFilter(QObject *obj, QEvent *event)
{
qDebug() << event->type() << "\n";
return QObject::eventFilter(obj, event);
}
I have tried doing
EvFilter* evf = new EvFilter();
view->installEventFilter(evf);
And also on every other element (profile, page, dialog) but couldn't seem to get any events corresponding to mouse or gesture.
What am I doing wrong? How could I prevent that behaviour in the entire webview?
After adding the event listener to the QApplication object, I can detect TouchBegin, TouchUpdate, TouchCancel and TouchEnd events, but nothing else (no Gesture event). I dont know how could I detect if the touchevent is the zoom gesture.
I think you could use this on the Dialog (didn't test it). I had some other widget showing a QML QtWebView and what I did to prevent the widget's children to get Pinch Gestures is:
this->grabGesture(Qt::PinchGesture, Qt::DontStartGestureOnChildren);
This prevents the underlying widget from receiving the PinchGesture, so that you can handle it yourself.
I am using Qt but have run into a problem.
I want to register when the mouse is pressed and released on a QTableWidget. There are signals only for pressed, not released. Therefore I use mousePressEvent and mouseReleaseEvent instead.
MyWidget.h
protected:
void mousePressEvent(QMouseEvent * event);
void mouseReleaseEvent(QMouseEvent * event);
MyWidget.cpp
void MyWidget::mousePressEvent(QMouseEvent *event)
{
qDebug() << "Pressed";
}
void MyWidget::mouseReleaseEvent(QMouseEvent *event)
{
qDebug() << "Released";
}
It prints "Released" when the left, right or middle mouse button is released over the table. However, it prints "Pressed" only when the right or middle button is pressed.
What could be wrong? How can I register when the left button is pressed?
The cell widget probably consumes the mousePressEvent on the left mouse button, so you (the parent widget) are not receiving it.
In the documentation of QMouseEvent, it is said that:
A mouse event contains a special accept flag that indicates whether the receiver wants the event. You should call ignore() if the mouse event is not handled by your widget. A mouse event is propagated up the parent widget chain until a widget accepts it with accept(), or an event filter consumes it.
Because of that, we can suppose that probably the events you mentioned are consumed by some other actors.
It would help knowing who are those actors.
I found the solution (with help from the other answers):
There was a QFrame on top of the widget that consumed the event. I didn't think of that since it worked for the other buttons. It was solved by:
ui->frame->setAttribute(Qt::WA_TransparentForMouseEvents, true);
Environment: Qt 5.1 OSX 10.7.5
I am showing a contextMenu when a Qt::RightButton event is received.
Issue: It works fine except that the initial display is very slow and can take 3-5 seconds to display the menu. Any subsequent displays are immediate. The delay is long enough so that the user can think nothing is happening.
Question: Is there any way to preload or otherwise speed up the initial display of the contextMenu?
I've tried initializing it in my class constructor:
contextMenu = new QMenu(this);
QAction *saveAction=contextMenu->addAction("Save");
connect(saveAction,SIGNAL(triggered()),this,SLOT(saveSlot()));
I've tried declaring it as a pointer and as a... (not pointer? ;-)
QMenu *contextMenu;
This is the mousePressEvent that executes to show the contextMenu.
void RPImageLabel::mousePressEvent(QMouseEvent *event)
{
if (!imageRect.contains(event->pos())) return;
origin = event->pos();
this->setFocus();
if (event->button()==Qt::RightButton){
if (selectionRect.contains(origin))
// contextMenu.exec(this->mapToGlobal(origin));
contextMenu->exec(this->mapToGlobal(origin));
} else {
selectionStarted=true;
selectionRect.setTopLeft(origin);
selectionRect.setBottomRight(origin);
if (rubberBand->isHidden()){
rubberBand->setGeometry(QRect(origin, origin));
rubberBand->show();
repaint();
}
}
}
Ok, I solved this by changing the contextMenuPolicy from DefaultContextMenu to ActionsContextMenu for the widget in Qt Creator.
I'm new to Qt so just guessing here but perhaps this uses a Qt contextMenu instead of the OSX menu? In any event, it displays immediately now. However it does throw an alert on certain conditions:
QNSView mouseDragged:
Internal mouse button tracking invalid (missing Qt::LeftButton)
Not clear what is going on but I see that there has been a bug report filed which may be related.
This is sort of a chicken and egg problem. I'd like my widget window to be closed when the mouse clicks outside. As I understand it, there will be no mouse events for my widget for a click occurring outside of it. There is a SetFocus slot, but where is its counterpart or focus loss? "focusOutEvent" doesn't get called for my class.
My widget window is a child window of a widget always shown on my main window and it's a "Qt::ToolTip", so I assume some problems could arise from that fact. Any way around that?
My Goal: I have a custom toolbar widget where buttons on it may have “drop down” widgets. These drop down widgets have no standard windows frame. I don’t want them to “steal” caption focus from the main window and I want them to disappear as soon as the user clicks ANYWHERE on the screen outside of their region. I have having serious difficulties finding a strategy that’s not compromise on Qt to get this done.
Am I missing something? (bet I am).
I used:
setWindowFlags(Qt::FramelessWindowHint | Qt::Popup);
This seems to work well on OSX and Windows. My window appears correctly, does not steal the focus from my main window's caption, and the focus loss event is called correctly as soon as I click outside of it.
If your widget could have focus, and 'steal' the caption focus of some of your other widgets, it would have been easier. Something like this could work:
class ToolBarWidget : public QWidget
{
Q_OBJECT
public:
explicit ToolBarWidget(QWidget * parent = 0)
{
setFocusPolicy(Qt::ClickFocus);
}
protected:
void focusOutEvent(QFocusEvent * event)
{
close();
}
}
And when you create any of your widgets you'd do:
ToolBarWidget * pWidget = new ToolBarWidget(this);
pWidget->show();
pWidget->setFocus();
Done! Well, I guess not quiet. first, you don't want the ToolBarWidget to get any focus in the first place. And second, you want for the user to be able to click anywhere and the ToolBarWidget to be hidden.
So, you may keep track of every ToolBarWidget that you create. For example, in a 'QList ttWidgets' member variable. Then, whenever you create a new ToolBarWidget, you'd do this:
ToolBarWidget * pWidget = new ToolBarWidget(this);
pWidget->installEventFilter(this);
pWidget->show();
and in your main widget class, implement the eventFilter() function. Something like:
bool MainWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::FocusOut ||
event->type() == QEvent::KeyPress ||
event->type() == QEvent::MouseButtonPress)
{
while (!ttWidgets.isEmpty()) {
ToolBarWidget * p = ttWidgets->takeFirst();
p->close();
p->deleteLater();
}
}
return MainWidget::eventFilter(obj, event);
}
And that will work. Because this way, even though your ToolTabWidgets aren't getting focus, some other widget in your main widget has focus. And once that changes (whether the user clicked out of your window, or on another control inside it, or in this case, a key or mouse button is pressed, the control will reach that eventFilter() function and close all your tab widgets.
BTW, in order to capture the MouseButtonPress, KeyPress etc. from the other widgets, you would either need to installEventFilter on them too, or just reimplement the QWidget::event(QEvent * event) function in your main widget, and look for those events there.
you can do this by using QDesktopWidget.h like this
void MainWindow::on_actionAbout_triggered()
{
AboutDialog aboutDialog;
//Set location of player in center of display
aboutDialog.move(QApplication::desktop()->screen()->rect().center() -aboutDialog.rect().center());
// Adding popup flags so that dialog closes when it losses focus
aboutDialog.setWindowFlags(Qt::Popup);
//finally opening dialog
aboutDialog.exec();
}
This is what worked for me in order to not steel the focus from the main application:
.h
bool eventFilter(QObject *obj, QEvent *event) override;
.cpp
bool Notification::eventFilter(QObject *obj, QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
deleteLater();
return QObject::eventFilter(obj, event);
}
...
// somewhere else (i.e. constructor, main window,...)
qApp->installEventFilter(this);
OP's own answer is great for Qt versions below 4.8, but as they mention in their answer, it does not work for versions above that. The Qt::Popup widget will not disappear when the mouse is clicked outside of the widget, and it will sink all of the input that would normally close it.
Upon further investigation, this is only an issue for non-dialog widgets. A QDialog using Qt::Popup will properly close when the user clicks outside of it, but any other QWidget, like a QFrame, will not. So in order to work around this behavior change in Qt 4.8, all that is necessary is to wrap the widget in a QDialog.
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.