I would like to know how to respond to a mouse scroll event in C++ only from the user's mouse wheel. I don't really care whether the user scrolls in or out as long as I catch the event that they indeed did scroll with the mouse. Can anyone show me how I can use this for an event?
You need to implement the glutMouseFunc callback like this:
void mouse(int button, int state, int x, int y)
{
// Wheel reports as button 3(scroll up) and button 4(scroll down)
if ((button == 3) || (button == 4))
{
if (state == GLUT_UP) return; // Disregard redundant GLUT_UP events
(button == 3) ? DO_ACTION : DO_SOMETHING_ELSE;
}
glutPostRedisplay();
}
Related
I am trying to implement mouse wheel zoom in/out. It works BUT when I zoom in/out, the image is getting smaller AND scrolls up/down at the same time with zoom function. Look like events exist at the same time and work together.
I cannot find how to disable scrolling with mouse wheel. May be there is a way to make possible scrolling only with mouse cursor (by clicking on scrollbar).
I was overriding the main method of mouse wheel but it was causing the effect I wrote above
void MainWindow::wheelEvent( QWheelEvent* event )
Solved by using event filter. The code below provides zoom in/out with holding ctrl button.
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneWheel)
{
ui->GV_image->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
double scaleFactor = 1.15;
bool ok = QApplication::keyboardModifiers() & Qt::ControlModifier;
if (ok)
{
QGraphicsSceneWheelEvent *scrollevent = static_cast<QGraphicsSceneWheelEvent *>(event);
if (scrollevent->delta() > 0)
{
ui->GV_image->scale(scaleFactor, scaleFactor);
}
else
{
ui->GV_image->scale(1/scaleFactor, 1/scaleFactor);
}
}
event->accept();
return true;
}
return false;
}
Put this line into your constructor or other your init function
QGraphicsView *GV_image;
...
ui->GV_image->scene()->installEventFilter(this);
I'm adapting some skeleton code to learn how OpenGL works and have in SphericalCameraManipulator.cpp which allows me to pan and tilt the camera while I hold down right mouse:
void SphericalCameraManipulator::handleMouseMotion(int x, int y)
{
//Motion
float xMotion = (float)x - previousMousePosition[0];
float yMotion = (float)y - previousMousePosition[1];
if(reset)
{
xMotion = yMotion = 0.0;
reset = false;
}
this->previousMousePosition[0] = (float)x;
this->previousMousePosition[1] = (float)y;
//Right Button Action
if(this->currentButton == GLUT_RIGHT_BUTTON && this->currentState == GLUT_DOWN)
{
this->pan -= xMotion*this->panTiltMouseStep ;
this->tilt += yMotion*this->panTiltMouseStep ;
}
//Enforce Ranges
this->enforceRanges();
}
I deleted the left mouse action as I don't want it to control the camera, and it now actions a command in the main code body.
//Left Button Action
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
... //game action
}
My problem is that when I click the left mouse, the press of the right mouse is cancelled, and I must release and repress the right mouse to continue controlling the camera.
Is there a way to prevent this from happening? It interrupts the flow of the game. I'm using GLUT
Rabbid76's comment saying there is no mouse hold event set me on the right path.
I wrote a small function that simply recorded the last state of mouse button 2 (the 'camera look around' button):
void SphericalCameraManipulator::handleMouse(int button, int state)
{
this->currentButton = button;
this->currentState = state;
//to enable mouse look around
if (this->currentButton == 2) //right mouse
this->lastLookState = this->currentState;
if(this->currentState == GLUT_UP)
{
reset = true;
}
}
This mean even when the current state was regarding the left mouse button (game action) it was still possiblew to look around since a 'mouse two button up' event had not occured:
this->currentButton = 2;
this->currentState = 1;
So i'm trying to capture mouse dragging in my OpenGL application. I've done the following so far:
glfwSetMouseButtonCallback(window, mouse_callback);
static void mouse_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT) {
double x;
double y;
glfwGetCursorPos(window, &x, &y);
if (previous_y_position - y > 0)
{
camera_translation.y -= 1.0f;
previous_y_position = y;
}
else
{
camera_translation.y += 1.0f;
previous_y_position = y;
}
}
}
The problem with this though is if I would like to zoom in I need to move my mouse upwards and then click repeatedly. For some reason if I press down on the left mouse button and drag upwards it does nothing.
In cursor_pos_callback, just confirm if the button is pressed, and that works.
void mouse_cursor_callback( GLFWwindow * window, double xpos, double ypos)
{
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE)
{
return;
}
// `write your drag code here`
}
mouse_callback is stateless. It receives events, momentary "actions".
You need to make your program to "remember" that mouse button is pressed. So that when button is pressed in a frame 1, you can refer to this information in all the frames after that and before mouse button is released.
The simple way is to flip a boolean flag on press/release:
static void mouse_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if(GLFW_PRESS == action)
lbutton_down = true;
else if(GLFW_RELEASE == action)
lbutton_down = false;
}
if(lbutton_down) {
// do your drag here
}
}
Schematically:
state released pressed released
timeline -------------|------------------------------|---------------
^ ^
mouse_callback calls GLFW_PRESS GLFW_RELEASE
The hard way is to use a state machine (especially if you need more complicated combinations of states of input controllers).
I have a subclass of QGraphicsView that should accept two kinds of mouse events: drag and drop for scrolling and simple clicks for item selection/highlight.
So I use
setDragMode(QGraphicsView::ScrollHandDrag);
to enable scrolling the view with the "Hand". And I have a function like this:
void GraphView::mouseReleaseEvent(QMouseEvent* e)
{
if (e->button() == Qt::LeftButton)
emit leftClicked(mapToScene(e->pos()));
else
emit rightClicked(mapToScene(e->pos()));
QGraphicsView::mouseReleaseEvent(e);
}
which creates signal whenever the user clicks on the scene.
However, the problem is: when I stop dragging and release the mouse button, the mouseReleaseEvent function is called, and if the cursor happens to be over some element of the scene, it will get highlighted.
How can I changed the mouseReleaseEvent function so that the signals are created only if there was no previous drag of the mouse?
If you use mousePress and mouseMove in combination with mouseRelease, then you can determine what mouse action the user just performed.
If you have mousePress then mouseRelease, then it must be a simple click.
If you have mousePress, mouseMove, and then mouseRelease, then it must be a drag.
The Qt documentation contains an example of interpreting combinations of mouse events in action in a scribbling program.
http://doc.qt.io/qt-4.8/qt-widgets-scribble-example.html
You can extend the principle to something like this:
private bool MyWidget::dragging = false;
private bool MyWidget::pressed = false;
void MyWidget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
pressed=true;
}
QGraphicsView::mousePressEvent(event)
}
void MyWidget::mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && pressed)
{
dragging=true;
}
QGraphicsView::mouseMoveEvent(event)
}
void MyWidget::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && pressed) {
pressed = false;
if (dragging)
{
dragging = false;
}
else
{
// plain mouse click
// do something here
}
}
QGraphicsView::mouseReleaseEvent(event)
}
Note that this does not address edge cases where a user's mouse action is performed only partially inside the widget. I must also admit that I am relatively new to Qt and have not yet used ScrollHandDrag, but this is how one would go about identifying a certain combination of mouse events.
How to handle TreeView double or right mouse click in WinProc?
i have tried this:
if(LOWORD(wParam) == GetWindowID(g_hWndTV &&
HIWORD(wParam) == WM_RBUTTONUP)
......
but this does not work.
Thanks for answers
Both these events will come via a WM_NOTIFY message sent to the tree control's parent window. You'll get NM_RCLICK for a right-click, and NM_DBLCLK for a double-click.
case WM_NOTIFY:
if (reinterpret_cast<LPNMHDR>(lParam)->hwndFrom == g_hWndTV)
{
if (reinterpret_cast<LPNMHDR>(lParam)->code == NM_RCLICK)
{
// right-click
}
else
if (reinterpret_cast<LPNMHDR>(lParam)->code == NM_DBLCLK)
{
// double-click
}
}
break;