I have an application where I want to pick up the position of the mouse in a graphics view and use this to draw a pair of threshold markers to adjust a gradation scale within the same graphics view.
The graphicsView_gradbar widget is 162x22 pixels with a 1 pixel border, leaving 160x20 pixels for the greyscale plot.
I'm installing the event filter to this view and then with an event handler picking out the mouse coordinates relative to this view.
If I set the return values as I think they should be once the event has been handled, the mouse click, and mouse move is correctly handled, except that the graphics view is not shown correctly - the right side is blank and the border is not drawn. But clicking in this area will pick up the mouse move correctly and move the cursor drawn in the application in the part of the graphics view that is drawn correctly. Clicking in the correctly drawn part of the view only responds to the mouse click and not the movement when the mouse is clicked and held down.
If I set the return values to "false" the gradation bar is drawn correctly but it only responds to mouse clicks and not to mouse moves when the mouse is clicked and held down.
The mainwindow function sets everything up. The GradbarRefresh function redraws the gradation bar when new mouse clicks or movements occur. The eventFilter handles the events and generates the new coordinates for the thresholds (red lines) drawn in the gradation bar.
I just cannot figure out why the graphics view is corrupted like this.
Here's the header:- `
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QEvent>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QGraphicsScene *scene_gradbar;
bool eventFilter(QObject *obj, QEvent *event);
private slots:
void GradbarRefresh(int status);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
```
Here's the main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Here's the source:-
#include "mainwindow.h"
#include "ui_mainwindow.h"
int gradfull_lower; // Full range 255 steps (slider is 160)
int gradfull_upper; // Full range 255 steps (slider is 160)
int grad_lower; // Gradation lower threshold
int grad_upper; // Gradation upper threshold
QGraphicsPixmapItem *histgradbarItem; // Gradation bar pixmap
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
{
ui->setupUi(this);
scene_gradbar = new QGraphicsScene(this);
ui->graphicsView_gradbar->setScene(scene_gradbar);
ui->graphicsView_gradbar->installEventFilter(this); // Install the event filter to this graphics view will send mouse events
// to the filter with the coordinates of this graphicsview item relative mouse position
// ui->graphicsView_gradbar->setMouseTracking(true);
// Initialise gradation range
grad_lower = 0;
grad_upper = 159;
// Set the full histogram ranges from the gradbar values
gradfull_lower = (grad_lower + 1) * 255 / 160;
gradfull_upper = (grad_upper +1) * 255/ 160;
// Initialise the gradation bar
GradbarRefresh(0);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::GradbarRefresh(int status)
{
unsigned char gradationbar[12800]; // Storage for the gradation bar graphic (160x20 pixels, x4 bytes per pixel)
quint8 gradbarval[3]; // For future pseudo red, green or blue scale option may need to set colour
int width;
int height;
int index;
int grad_range;
// Make the gradation bar under the histogram
height = 0;
index = 0;
// Calculate the range of levels
grad_range = grad_upper - grad_lower + 1;
// Greyscale (still RGBA)
// Must be able to do this with one pass of height then some memcopy function for the 19 other rows
do {
width = 0;
do {
if (width < grad_lower ) {
gradbarval[0] = 255; // White if less than the offset
gradbarval[1] = 255;
}
else {
gradbarval[0] = 255 - ((width - grad_lower) * 255 )/ (grad_range); // Calculate the greyscale (0-159 grad_bar range scaled to 0-255 greyscale range)
gradbarval[1] = gradbarval[0]; // For now greyscale and not pseudo colour
}
if (width > (grad_upper)) {
gradbarval[0] = 0; // Black if beyond the gradbar upper level
gradbarval[1] = 0;
}
if ((width == grad_lower) || (width == grad_upper)) { // Set to red if on one of the thresholds
gradbarval[0] = 255;
gradbarval[1] = 0;
}
gradationbar[index] = gradbarval[0]; // Red
index += 1;
gradationbar[index] = gradbarval[1]; // Green
index += 1;
gradationbar[index] = gradbarval[1]; // Blue
index += 1;
gradationbar[index] = 255; // A
index += 1;
width += 1;
} while (width < 160);
height += 1;
} while (height < 20);
// First time pass (status 0) add a pixmap, thereafter (status 1) update the first pixmap
if (status == 0){
histgradbarItem = scene_gradbar->addPixmap(QPixmap::fromImage(QImage(gradationbar, 160, 20, QImage::Format_RGBA8888)));
histgradbarItem->setPos(0 , 0);
} else {
histgradbarItem->setPixmap(QPixmap::fromImage(QImage(gradationbar, 160, 20, QImage::Format_RGBA8888)));
scene_gradbar->update();
}
}
The event filter code that handles the mouse click and movement:-
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
int xPos, yPos; // x and y coordinates of the mouse when pressed
int grad_midpos; // Position half way betweent he markers
char labeltext[10]; // Temp text storage for writing to labels
QMouseEvent* mEvent = (QMouseEvent*)event;
// Look for mouse press in the gradation bar, then get x value and move lower/upper range accordingly
if (obj == ui->graphicsView_gradbar){ // Only need this if more than one event filter has been installed
if ((event->type() == QEvent::MouseButtonPress) || (event->type() == QEvent::MouseMove)){ // Check if it's a mouse press or mouse move
QPoint point = mEvent->pos();
xPos = point.x(); // Values 1-162 as it gives coordinates inluding the frame around the scale drawn within it.
yPos = point.y(); // The y-coord is interesting to see if it returns a value outside of the gradbar (only applies to MouseMove)
sprintf(labeltext, "%03i", xPos); // Write x-coordinate to the label
ui->label_xvalue->setText(labeltext);
sprintf(labeltext, "%03i", yPos); // Write x-coordinate to the label
ui->label_yvalue->setText(labeltext);
qDebug() << "Mouse Press x" << xPos; // Output to debug for good measure
qDebug() << "Mouse Press y" << xPos;
if ((xPos < 2) || (xPos > 161)) { // If on the box frame or outside, return
return true;
}
xPos = xPos - 2; // Convert to a coordinate in the scene, range 0-159 (160 picels)
// Calculate the gradbar middle
grad_midpos = grad_lower + ((grad_upper-grad_lower)/2);
// Check to see which to grab and move
if (xPos < (grad_midpos - 1) ) { // If less than half mid position reassign to lower threshold - keep a 2 pix gap in the middle
grad_lower = xPos;
} else if (xPos > grad_midpos){ // If at or beyond the mid position reassign to the upper threshold
grad_upper = xPos;
}
// Refresh the gradation bar
GradbarRefresh(1);
return true; // This event has been dealt with so stop handling it
} // ******************* NOTE **********
// Set BOTH theser return values to false and the histogram is drawn properly but only
// responds to mouse clicks, not the mouse move
return true; // Finished handling this event
}
return false; // Returning false means events are still handled. If set to true, no more events are
// Handled and the histogram won't draw properly
}
Here's the form:-
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QGraphicsView" name="graphicsView_gradbar">
<property name="geometry">
<rect>
<x>230</x>
<y>200</y>
<width>162</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QGraphicsView" name="graphicsView_histogram">
<property name="geometry">
<rect>
<x>230</x>
<y>120</y>
<width>162</width>
<height>83</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="label_xtext">
<property name="geometry">
<rect>
<x>230</x>
<y>230</y>
<width>49</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>x-coord</string>
</property>
</widget>
<widget class="QLabel" name="label_ytext">
<property name="geometry">
<rect>
<x>230</x>
<y>260</y>
<width>49</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>y-coord</string>
</property>
</widget>
<widget class="QLabel" name="label_xvalue">
<property name="geometry">
<rect>
<x>280</x>
<y>230</y>
<width>49</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>x-value</string>
</property>
</widget>
<widget class="QLabel" name="label_yvalue">
<property name="geometry">
<rect>
<x>280</x>
<y>260</y>
<width>49</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>y-value</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>