I am zooming an image on a label using QGraphicsView. But when I zoom out I want to set a specific limit for the zoom out. I am using the following code
scene = new QGraphicsScene(this);
view = new QGraphicsView(label);
QPixmap pix("/root/Image);
Scene->addPixmap(pixmap);
view->setScene(scene);
view->setDragMode(QGraphicsView::scrollHandDrag);
In the slot of wheel event
void MainWindow::wheelEvent(QWheelEvent *ZoomEvent)
{
view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
double scaleFactor = 1.15;
if(ZoomEvent->delta() >0)
{
view->scale(scaleFactor,scaleFactor);
}
else
{
view->scale(1/scaleFactor,1/scaleFactor);
}
}
I want that the image should not zoom out after a certain extent. What should I do?
I tried setting the minimum size for QGraphicsView but that didn't help.
Thank You :)
Maybe something like this would help:
void MainWindow::wheelEvent(QWheelEvent *ZoomEvent)
{
view->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
static const double scaleFactor = 1.15;
static double currentScale = 1.0; // stores the current scale value.
static const double scaleMin = .1; // defines the min scale limit.
if(ZoomEvent->delta() > 0) {
view->scale(scaleFactor, scaleFactor);
currentScale *= scaleFactor;
} else if (currentScale > scaleMin) {
view->scale(1 / scaleFactor, 1 / scaleFactor);
currentScale /= scaleFactor;
}
}
The idea, as you can see, is caching the current scale factor and do not zoom out in case of it smaller than some limit.
Here is one more implementation idea in which the current zoom factor is obtained from the transformation matrix for the view:
void View::wheelEvent(QWheelEvent *event) {
const qreal detail = QStyleOptionGraphicsItem::levelOfDetailFromTransform(transform());
const qreal factor = 1.1;
if ((detail < 10) && (event->angleDelta().y() > 0)) scale(factor, factor);
if ((detail > 0.1) && (event->angleDelta().y() < 0)) scale((1 / factor), (1 / factor));
}
Another way to solve the problem:
void GraphWidget::wheelEvent(QWheelEvent *event)
{
int scaleFactor = pow((double)2, - event->delta() / 240.0);
qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
if (factor < 0.5 || factor > 20)
return;
scale(scaleFactor, scaleFactor);
}
Related
I have a QPushButton with round corners:
Now, I want to changed the button's style when mouse is moving at it:
I used setStyleSheet of QPushButton:
QPushButton{
width:100px;
height:80px;
border-radius:40px;
border: 1px solid #ffffff;
}
QPushButton:hover{
background: red;
}
But not four corners:
as the 3rd image shown, the cursor is pointing at the button's right-bottom corner but aslo triggered the button's hover state. Is there a simple way to prevent this behavior?
Maybe, there exists a more straightforward solution of that, but I just tried and it occured that implementing all the hover behaviour by hand seems the only really working way.
Generally, it's all about checking that the mouse coordinates belong to an ellipse (you can try other geometric considerations).
Something that doesn't work:
ui->myButton->installEventFilter(this);
//----------------------------------------
bool SomeWidget::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverMove)
{
QHoverEvent* hoverEvent = static_cast<QHoverEvent *>(event);
QWidget* target = qobject_cast<QWidget *>(obj);
qreal a = target->width() / 2;
qreal b = target->height() / 2;
qreal x = hoverEvent->posF().x() - a;
qreal y = hoverEvent->posF().y() - b;
double val = (x / a) * (x / a) + (y / b) * (y / b);
bool isInside = val <= 1;
if (!isInside)
return true;
else
return QObject::eventFilter(obj, event);
}
return QObject::eventFilter(obj, event);
}
With SomeWidget, comtaining a button and event filter installed, this looked promising but works awfully =(
Something that works as a Proof-of-Concept:
CustomButton::CustomButton(QWidget *parent)
: QPushButton(parent)
{
setProperty("my_hover", "not_hovered");
}
void CustomButton::mouseMoveEvent(QMouseEvent *event)
{
qreal a = width() / 2;
qreal b = height() / 2;
qreal x = event->pos().x() - a;
qreal y = event->pos().y() - b;
double val = (x / a) * (x / a) + (y / b) * (y / b);
bool isInside = val <= 1;
setProperty("my_hover", isInside ? "hovered" : "not_hovered" );
style()->unpolish(this);
style()->polish(this);
}
Subclassing a QPushButton worked better (code above is made a readble sample, you can improve it, of course). When implemented, it provides the button class with a custom property, which could be used like that:
QPushButton[my_hover="hovered"]
{
background: red;
}
To make it a perfect solution you'll probably have to care about mouseLeaveEvent too, thus getting rid of occasional glitches. Also, the property could probably be made boolean if it works with your Qt.
AFAIK, that's the only sure way to implement the desired behaviour you've descrived.
I make my own class from QWidget with redefine of paintEvent(), mousePressEvent(), mouseReleaseEvent() and mouseMoveEvent(). All that methods for move widgets over other widget (yellow).
When i create my widgets in a layout, it looks like this:
But when I move black widget to the bottom and red to the top like this:
and resize window, all widgets refresh to their align positions:
But i want, when i move one widget higher then another, the widgets should align in layout in new places, like this:
Which function i should redefine to do it?
P.S.
There is a piece of code, that can move widgets positions inside layout (change their indexes), but i don't know how find out their (x,y) position to calculate new indexes in layout. I think, that i can do it in resizeEvent().
But it when it event was emitted, positions already changed to old. (like before moveing on 1 picture), and i need positions after moveing (like on secon picture). How can i get position of widget before it will be aligned?
or How can i change order of widget in layout by drag and drop with the mouse?
I write my own widget, then redefine following methods: mouseReleaseEvent(), paintEvent(), mousePressEvent(), mouseMoveEvent(). In mousePressEvent() I hold old X and Y positions and mouse position on figure. Then in mouseMoveEvent() i calculate if minimum distance of mouse move is riched and move widget to new position (it not moves widget index in layout). After it, if emitted mouseReleaseEvent() i just calculate new index of moving widget and change and update parent layout. If widget moves less then it height, then layout just updates without changing widget index.
void SimpleWidget::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
return;
if (!IsMinimumDistanceRiched(event))
{
return;
}
int y = event->globalY() - mouseClickY + oldY;
int BottomBorder = parentWidget->geometry().height() - this->geometry().height();
if(y < 0) y = 0;
else if(y > BottomBorder) y = BottomBorder;
move(oldX, y);
}
void SimpleWidget::mousePressEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
dragStartPosition = event->pos();
oldX = this->geometry().x();
oldY = this->geometry().y();
mouseClickX = event->globalX();
mouseClickY = event->globalY();
}
bool SimpleWidget::IsMinimumDistanceRiched(QMouseEvent *event)
{
return (event->pos() - dragStartPosition).manhattanLength() >= QApplication::startDragDistance();
}
bool SimpleWidget::moveInLayout(QWidget *widget, MoveDirection direction)
{
QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(widget->parentWidget()->layout());
const int index = myLayout->indexOf(widget);
if (direction == MoveUp && index == 0)
{
return false;
}
if (direction == MoveDown && index == myLayout->count()-1 )
{
return false;
}
const int newIndex = direction == MoveUp ? index - 1 : index + 1;
myLayout->removeWidget(widget);
myLayout->insertWidget(newIndex , widget);
return true;
}
void SimpleWidget::paintEvent(QPaintEvent *)
{
QStyleOption o;
o.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
}
void SimpleWidget::mouseReleaseEvent(QMouseEvent *)
{
int y = geometry().y();
MoveDirection direct;
int offset;
if(oldY > y)
{
offset = oldY - y;
direct = MoveUp;
}
else if(oldY < y)
{
offset = y - oldY;
direct = MoveDown;
}
int count = offset/height();
for(int i = 0; i < count; i++)
{
moveInLayout(this, direct);
}
update();
QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(this->parentWidget->layout());
myLayout->update();
this->saveGeometry();
}
I have a window, in which is a QGraphicsView, which will be displaying an image. I have implemented the wheelEvent(). My images are mostly going to be bigger than the window, so I get scroll bars in the window.
What we normally observe when we rotate the wheel while viewing an image in Windows Photo Viewer is that when we move the wheel up (towards it's wire), the image zooms in and when we move it down (towards out body), the image zooms out.
What I am getting instead is when I move the wheel towards myself (to zoom out) the image instead of zooming out , first scrolls down, and starts zooming out only when the scroll bar touches its bottom most point.
It would be better to understand the problem by trying out the code. I am not able to explain in I guess.
I want the standard behavior. What to do?
Code
#include "viewer.h"
#include "ui_viewer.h"
#include <QGraphicsView>
#include <QGraphicsItem>
#include <QGraphicsPixmapItem>
#include <QWheelEvent>
#include <QDebug>
#include <QImage>
#include <QImageReader>
#include <QApplication>
#include <QDesktopWidget>
viewer::viewer(QWidget *parent) : QWidget(parent),ui2(new Ui::viewer)
{
ui2->setupUi(this);
}
viewer::~viewer()
{
delete ui2;
}
int viewer::show_changes(QString folder)
{
QDesktopWidget *desktop = QApplication::desktop();
int screenWidth = desktop->width();
int screenHeight = desktop->height();
QString filename = "image_bigger_than_window.jpg";
QPixmap pixmap = QPixmap(filename);
QImageReader reader(filename);
QImage image = reader.read();
QSize size = image.size();
int width = 800;
int height = (width * size.height()) / size.width();
int x = (screenWidth - width) / 2;
int y = (screenHeight - height) / 2 - 30;
setGeometry(x,y,width, height);
setWindowTitle("OUTPUT");
ui2->graphicsView->setGeometry(0,0,width,height);
QGraphicsScene* viewScene = new QGraphicsScene(QRectF(0, 0,width, height), 0);
QGraphicsPixmapItem *item = viewScene->addPixmap(pixmap.scaled(QSize((int)viewScene->width(), (int)viewScene->height()),
Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
viewScene->addItem(item);
ui2->graphicsView->fitInView(QRectF(0, 0, width, height),Qt::IgnoreAspectRatio);
ui2->graphicsView->setScene(viewScene);
ui2->graphicsView->show();
return 0;
}
void viewer::wheelEvent(QWheelEvent * event)
{
const int degrees = event->delta() / 8;
qDebug() << degrees;
int steps = degrees / 15;
double scaleFactor = 1.0;
const qreal minFactor = 1.0;
const qreal maxFactor = 10.0;
qreal h11 = 1.0, h22 = 0;
if(steps > 0)
{
h11 = (h11 >= maxFactor) ? h11 : (h11 + scaleFactor);
h22 = (h22 >= maxFactor) ? h22 : (h22 + scaleFactor);
}
else
{
h11 = (h11 <= minFactor) ? minFactor : (h11 - scaleFactor);
h22 = (h22 <= minFactor) ? minFactor : (h22 - scaleFactor);
}
ui2->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
ui2->graphicsView->setTransform(QTransform(h11, 0, 0,0, h22, 0, 0,0,1));
}
EDIT
1)Removed function void viewer::wheelEvent(QWheelEvent * event) from viewer.cpp
2)Put bool viewer::eventFilter(QObject *obj, QEvent *event) in its place as a protected function and void viewer::handleWheelOnGraphicsScene(QGraphicsSceneWheelEvent* scrollevent) as a public slot in viewer.h
bool viewer::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::GraphicsSceneWheel)
{
QGraphicsSceneWheelEvent *scrollevent = static_cast<QGraphicsSceneWheelEvent *>(event);
handleWheelOnGraphicsScene(scrollevent);
return true;
}
// Other events should propagate - what do you mean by propagate here?
return false;
}
void viewer::handleWheelOnGraphicsScene(QGraphicsSceneWheelEvent* scrollevent)
{
const int degrees = scrollevent->delta() / 8;
qDebug() << degrees;
int steps = degrees / 15;
qDebug() << steps;
double scaleFactor = 1.0; //How fast we zoom
const qreal minFactor = 1.0;
const qreal maxFactor = 10.0;
if(steps > 0)
{
h11 = (h11 >= maxFactor) ? h11 : (h11 + scaleFactor);
h22 = (h22 >= maxFactor) ? h22 : (h22 + scaleFactor);
}
else
{
h11 = (h11 <= minFactor) ? minFactor : (h11 - scaleFactor);
h22 = (h22 <= minFactor) ? minFactor : (h22 - scaleFactor);
}
ui2->graphicsView->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
ui2->graphicsView->setTransform(QTransform(h11, 0, 0,0, h22, 0, 0,0,1));
}
The code shows that you didn't subclass QGraphicsView, but instead use one in your own widget.
The wheel event will be first sent to the actual graphics view widget. There it is handled with Qt's default behaviour, namely scrolling. Only if you scrolled to the bottom, the graphics view cannot handle the wheel event, and it is propagated to its parent, your class. That's why you only can zoom when scrolled to the border.
To fix this, you should install an event filter. That allows you to intercept the wheel event and process it in your class:
// Outline, not tested
viewer::viewer(QWidget *parent) : QWidget(parent),ui2(new Ui::viewer)
{
ui2->setupUi(this);
// Let me handle your events
ui2->graphicsView->installEventFilter(this);
}
// should be protected
bool viewer::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::GraphicsSceneWheel) {
// Your implementation.
// You can't use QWheelEvent, as Graphicscene works with its own events...
handleWheelOnGraphicsScene(static_cast<QGraphicsSceneWheelEvent*> (event));
// Don't propagate
return true;
}
// Other events should propagate
return false;
}
Update
I just figured out that the event filter will not recieve GraphicsSceneWheel events on the graphics view. Instead, you have to install the filter on the Graphics Scene. Also, you have to call event->accept() so that it will not propagated.
So Updated Code:
// In Constructor, or where appropriate
ui2->graphicsView->scene()->installEventFilter(this);
bool viewer::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::GraphicsSceneWheel) {
handleWheelOnGraphicsScene(static_cast<QGraphicsSceneWheelEvent*> (event));
// Don't propagate
event->accept();
return true;
}
return false;
}
also note that handleWheelOnGraphicsScene or whatever you want to call it, should be a private method, and doesn't have to be a slot.
Im implementing the zooming of my QGraphicsView using wheelEvent
void View::wheelEvent(QWheelEvent *e)
{
if (e->modifiers().testFlag(Qt::ControlModifier)){ // zoom only when CTRL key pressed
int numSteps = e->delta() / 15 / 8;
if (numSteps == 0) {
e->ignore();
return;
}
qreal sc = pow(1.25, numSteps); // I use scale factor 1.25
this->zoom(sc);
e->accept();
}
}
and the zoom item
void View::zoom(qreal scaleFactor)
{
scale(scaleFactor, scaleFactor);
}
here i don’t want to zoom out too deeper, all i need it to restrict the scaling to certain point , i have to limit the zoom out so i tried to find the transform point
qreal
View::zoomScale() const
{
return transform().m11();
}
but with this i cant able to restrict the zooming .
please help me find the solution.
You can calculate the zoom factor relative to the "normal zoom" and decide if you can zoom or not.
For example, you can take a QRect for reference and check its size after the zoom :
void ClassA::scale(qreal scaleFactor) {
QRectF(0, 0, 1, 1); // A reference
qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(r).width(); // absolute zoom factor
if ( factor > 20 ) { // Don't zoom more than 20x
return;
}
this->scale(scaleFactor, scaleFactor);
}
Instead of stepping when the user clicks somewhere on the qslider I want to make the slider jump to that position. How can this be implemented ?
after having problems with all versions of #spyke #Massimo Callegari and #Ben (slider position wasnt correct for the whole area) I found some Qt Style functionality within QSlider sourcecode: QStyle::SH_Slider_AbsoluteSetButtons.
You have to create a new QStyle which can be a very annoying, or you use ProxyStyle as shown by user jpn in http://www.qtcentre.org/threads/9208-QSlider-step-customize?p=49035#post49035
I've added another constructor and fixed a typo, but used the rest of the original source code.
#include <QProxyStyle>
class MyStyle : public QProxyStyle
{
public:
using QProxyStyle::QProxyStyle;
int styleHint(QStyle::StyleHint hint, const QStyleOption* option = 0, const QWidget* widget = 0, QStyleHintReturn* returnData = 0) const
{
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
return (Qt::LeftButton | Qt::MidButton | Qt::RightButton);
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
};
now you can set the style of your slider in the sliders constructor (if your slider is derived from QSlider):
setStyle(new MyStyle(this->style()));
or it should work this way if it is a standard QSlider:
standardSlider.setStyle(new MyStyle(standardSlider->style()));
so you use the original style of that element, but if the QStyle::SH_Slider_AbsoluteSetButtons "property" is asked you return as you want ;)
maybe you'll have to destroy these proxystyles on slider deletion, not tested yet.
Well, I doubt that Qt has a direct function for this purpose.
Try to use custom widgets. This should work!
Try the following logic
class MySlider : public QSlider
{
protected:
void mousePressEvent ( QMouseEvent * event )
{
if (event->button() == Qt::LeftButton)
{
if (orientation() == Qt::Vertical)
setValue(minimum() + ((maximum()-minimum()) * (height()-event->y())) / height() ) ;
else
setValue(minimum() + ((maximum()-minimum()) * event->x()) / width() ) ;
event->accept();
}
QSlider::mousePressEvent(event);
}
};
I needed this too and tried spyke solution, but it's missing two things:
inverted appearance
handle picking (when the mouse is over the handle, direct jump is not necessary)
So, here's the reviewed code:
void MySlider::mousePressEvent ( QMouseEvent * event )
{
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
if (event->button() == Qt::LeftButton &&
sr.contains(event->pos()) == false)
{
int newVal;
if (orientation() == Qt::Vertical)
newVal = minimum() + ((maximum()-minimum()) * (height()-event->y())) / height();
else
newVal = minimum() + ((maximum()-minimum()) * event->x()) / width();
if (invertedAppearance() == true)
setValue( maximum() - newVal );
else
setValue(newVal);
event->accept();
}
QSlider::mousePressEvent(event);
}
The answer of Massimo Callegari is almost right, but the calculation of newVal ignores the slider handle width. This problem comes up when you try to click near the end of the slider.
The following code fixes this for horizontal sliders
double halfHandleWidth = (0.5 * sr.width()) + 0.5; // Correct rounding
int adaptedPosX = event->x();
if ( adaptedPosX < halfHandleWidth )
adaptedPosX = halfHandleWidth;
if ( adaptedPosX > width() - halfHandleWidth )
adaptedPosX = width() - halfHandleWidth;
// get new dimensions accounting for slider handle width
double newWidth = (width() - halfHandleWidth) - halfHandleWidth;
double normalizedPosition = (adaptedPosX - halfHandleWidth) / newWidth ;
newVal = minimum() + ((maximum()-minimum()) * normalizedPosition);
Here is a simple implementation in python using QStyle.sliderValueFromPosition():
class JumpSlider(QtGui.QSlider):
def mousePressEvent(self, ev):
""" Jump to click position """
self.setValue(QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width()))
def mouseMoveEvent(self, ev):
""" Jump to pointer position while moving """
self.setValue(QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width()))
The following code is actually a hack, but it works fine without sub-classing QSlider. The only thing you need to do is to connect QSlider valueChanged signal to your container.
Note1: You must set a pageStep > 0 in your slider
Note2: It works only for an horizontal, left-to-right slider (you should change the calculation of "sliderPosUnderMouse" to work with vertical orientation or inverted appearance)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// ...
connect(ui->mySlider, SIGNAL(valueChanged(int)),
this, SLOT(mySliderValueChanged(int)));
// ...
}
void MainWindow::mySliderValueChanged(int newPos)
{
// Make slider to follow the mouse directly and not by pageStep steps
Qt::MouseButtons btns = QApplication::mouseButtons();
QPoint localMousePos = ui->mySlider->mapFromGlobal(QCursor::pos());
bool clickOnSlider = (btns & Qt::LeftButton) &&
(localMousePos.x() >= 0 && localMousePos.y() >= 0 &&
localMousePos.x() < ui->mySlider->size().width() &&
localMousePos.y() < ui->mySlider->size().height());
if (clickOnSlider)
{
// Attention! The following works only for Horizontal, Left-to-right sliders
float posRatio = localMousePos.x() / (float )ui->mySlider->size().width();
int sliderRange = ui->mySlider->maximum() - ui->mySlider->minimum();
int sliderPosUnderMouse = ui->mySlider->minimum() + sliderRange * posRatio;
if (sliderPosUnderMouse != newPos)
{
ui->mySlider->setValue(sliderPosUnderMouse);
return;
}
}
// ...
}
My final implementation based on surrounding comments:
class ClickableSlider : public QSlider {
public:
ClickableSlider(QWidget *parent = 0) : QSlider(parent) {}
protected:
void ClickableSlider::mousePressEvent(QMouseEvent *event) {
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
if (event->button() == Qt::LeftButton &&
!sr.contains(event->pos())) {
int newVal;
if (orientation() == Qt::Vertical) {
double halfHandleHeight = (0.5 * sr.height()) + 0.5;
int adaptedPosY = height() - event->y();
if ( adaptedPosY < halfHandleHeight )
adaptedPosY = halfHandleHeight;
if ( adaptedPosY > height() - halfHandleHeight )
adaptedPosY = height() - halfHandleHeight;
double newHeight = (height() - halfHandleHeight) - halfHandleHeight;
double normalizedPosition = (adaptedPosY - halfHandleHeight) / newHeight ;
newVal = minimum() + (maximum()-minimum()) * normalizedPosition;
} else {
double halfHandleWidth = (0.5 * sr.width()) + 0.5;
int adaptedPosX = event->x();
if ( adaptedPosX < halfHandleWidth )
adaptedPosX = halfHandleWidth;
if ( adaptedPosX > width() - halfHandleWidth )
adaptedPosX = width() - halfHandleWidth;
double newWidth = (width() - halfHandleWidth) - halfHandleWidth;
double normalizedPosition = (adaptedPosX - halfHandleWidth) / newWidth ;
newVal = minimum() + ((maximum()-minimum()) * normalizedPosition);
}
if (invertedAppearance())
setValue( maximum() - newVal );
else
setValue(newVal);
event->accept();
} else {
QSlider::mousePressEvent(event);
}
}
};
This modification to the JumpSlider above works in PyQt5:
class JumpSlider(QSlider):
def _FixPositionToInterval(self,ev):
""" Function to force the slider position to be on tick locations """
# Get the value from the slider
Value=QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width())
# Get the desired tick interval from the slider
TickInterval=self.tickInterval()
# Convert the value to be only at the tick interval locations
Value=round(Value/TickInterval)*TickInterval
# Set the position of the slider based on the interval position
self.setValue(Value)
def mousePressEvent(self, ev):
self._FixPositionToInterval(ev)
def mouseMoveEvent(self, ev):
self._FixPositionToInterval(ev)
I think,
the QStyle::sliderValueFromPosition() function can be used.
http://qt-project.org/doc/qt-5/qstyle.html#sliderValueFromPosition
i have been trying and searching this on net and was expecting Qt for a smarter way doing this, unfortunately there was not big help (may be i was not searching properly )
well i have done this in Qt creator:
Add an eventFilter in header ( takes QObject and QEvent as argument ) (bool return type)
Initialize in constructor ..for eg .. if ur slider is HSlider then
ui->HSlider->installEventFilter(this);
In the defination :
a. check if the object is your slider type something like : ui->HSlider == Object
b. Check for mouse click event something like : QEvent::MouseButtonPress == event->type
c. if the above all passes means u have got mouse event on the slider do something like : in definition : ui->HSlider->setValue( Qcursor::pos().x() - firstval ); return QMainWindow::eventFilter(object, event);
Note: fistVal : can be taken out by printing the cursur position at 0 = initial position of the slider ( with help of QCursor::pos().x() )
hope this helps
A simple method would be to derive from QSlider and reimplement mousePressEvent(....) to set the marker position using setSliderPosition(int).
I also met this problem. My solution is shown below.
slider->installEventFilter(this);
---
bool MyDialog::eventFilter(QObject *object, QEvent *event)
{
if (object == slider && slider->isEnabled())
{
if (event->type() == QEvent::MouseButtonPress)
{
auto mevent = static_cast<QMouseEvent *>(event);
qreal value = slider->minimum() + (slider->maximum() - slider->minimum()) * mevent->localPos().x() / slider->width();
if (mevent->button() == Qt::LeftButton)
{
slider->setValue(qRound(value));
}
event->accept();
return true;
}
if (event->type() == QEvent::MouseMove)
{
auto mevent = static_cast<QMouseEvent *>(event);
qreal value = slider->minimum() + (slider->maximum() - slider->minimum()) * mevent->localPos().x() / slider->width();
if (mevent->buttons() & Qt::LeftButton)
{
slider->setValue(qRound(value));
}
event->accept();
return true;
}
if (event->type() == QEvent::MouseButtonDblClick)
{
event->accept();
return true;
}
}
return QDialog::eventFilter(object, event);
}
You can also override these event handlers of QSlider.
QSlider::mousePressedEvent
QSlider::mouseMoveEvent
QSlider::mouseDoubleClickEvent