Вместо того, чтобы ступить, когда пользователь щелкает где-нибудь на qslider, я хочу, чтобы ползунок прыгнул в эту позицию. Как это можно реализовать?
Прямой прыжок мыши QSlider
Ответ 1
Ну, я сомневаюсь, что Qt имеет прямую функцию для этой цели.
Попробуйте использовать пользовательские виджеты. Это должно работать!
Попробуйте следующую логику
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);
}
};
Ответ 2
после возникновения проблем со всеми версиями @spyke @Massimo Callegari и @Ben (позиция ползунка не была правильной для всей области). Я обнаружил некоторую функциональность Qt Style в исходном коде QSlider: QStyle::SH_Slider_AbsoluteSetButtons
.
Вам нужно создать новый QStyle, который может быть очень раздражающим, или вы используете ProxyStyle
, как показано пользователем jpn в http://www.qtcentre.org/threads/9208-QSlider-step-customize?p=49035#post49035
Я добавил еще один конструктор и исправил опечатку, но использовал остальную часть исходного исходного кода.
#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);
}
};
теперь вы можете установить стиль слайдера в конструкторе ползунков (если ваш слайдер получен из QSlider):
setStyle(new MyStyle(this->style()));
или он должен работать таким образом, если это стандартный QSlider:
standardSlider.setStyle(new MyStyle(standardSlider->style()));
поэтому вы используете оригинальный стиль этого элемента, но если задано <свойство > t20 > , вы возвращаетесь как хотите;)
возможно, вам придется уничтожить эти проксистилы при удалении ползунка, еще не протестированы.
Ответ 3
Мне тоже понадобилось это и попробовал решение spyke, но ему не хватало двух вещей:
- перевернутый вид
- выбор ручки (когда мышь над ручкой, прямой прыжок не нужен)
Итак, здесь рассмотренный код:
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);
}
Ответ 4
Ответ Massimo Callegari почти прав, но вычисление newVal игнорирует ширину ручки ползунка. Эта проблема возникает, когда вы пытаетесь щелкнуть ближе к концу ползунка.
Следующий код исправляет это для горизонтальных ползунков
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);
Ответ 5
Вот простая реализация в python с использованием 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()))
Ответ 6
Следующий код на самом деле является взломом, но он отлично работает без подкласса QSlider. Единственное, что вам нужно сделать, это подключить сигнал QSlider valueChanged к вашему контейнеру.
Примечание1: Вы должны установить в своем слайдере pageStep > 0
Примечание2: Он работает только для горизонтального ползунка слева направо (вы должны изменить расчет "sliderPosUnderMouse" для работы с вертикальной ориентацией или инвертированным внешним видом)
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;
}
}
// ...
}
Ответ 7
Моя окончательная реализация основана на окружающих комментариях:
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);
}
}
};
Ответ 8
Я пытался и искал это в сети и ожидал Qt для более умного способа сделать это, к сожалению, не было большой помощи (возможно, я не искал должным образом)
Ну, я сделал это в создателе Qt:
- Добавить eventFilter в заголовке (принимает QObject и QEvent как аргумент) (тип возврата bool)
- Инициализировать в конструкторе.. для примера.. если ur ползунок HSLider, тогда ui- > HSlider- > installEventFilter (это);
-
В режиме защиты:
а. проверьте, является ли объект вашим слайдером, например:
ui->HSlider == Object
б. Отметьте для события щелчка мыши что-то вроде:
QEvent::MouseButtonPress == event->type
с. если все вышеперечисленное означает, что у вас есть событие мыши на слайдере, сделайте что-то вроде: в определении:
ui->HSlider->setValue( Qcursor::pos().x() - firstval ); return QMainWindow::eventFilter(object, event);
Примечание: fistVal: можно извлечь, распечатав позицию курсора при 0 = начальном положении ползунка (с помощью QCursor::pos().x()
)
надеюсь, что это поможет
Ответ 9
Я думаю,
может использоваться функция QStyle:: sliderValueFromPosition().
http://qt-project.org/doc/qt-5/qstyle.html#sliderValueFromPosition
Ответ 10
Простым методом будет вывод из QSlider
и reimplement mousePressEvent(....)
для установки позиции маркера с помощью setSliderPosition(int)
.
Ответ 11
Я также встретил эту проблему. Мое решение показано ниже.
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);
}
Вы также можете переопределить эти обработчики событий QSlider.
-
QSlider::mousePressedEvent
-
QSlider::mouseMoveEvent
-
QSlider::mouseDoubleClickEvent
Ответ 12
Эта модификация вышеупомянутого JumpSlider работает в 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)