QT 中的 QSlider 在新的 MacOS Monterey (v12.0.1) 中行为异常。任何解决方法?
QSlider in QT misbehaves in new MacOS Monterey (v12.0.1) . Any workaround?
如此处所述 (https://bugreports.qt.io/browse/QTBUG-98093),QT 中的 QSlider 组件在新的 MacOS 更新中运行不正常。
如果我在同一个 window 中添加两个或多个水平滑块,拖动一个滑块中的手柄会影响其他滑块。这可能会导致它们一起移动,或者可能使下一个跳到意想不到的位置。
下面的代码可以重现问题:
#include <QApplication>
#include <QDialog>
#include <QVBoxLayout>
#include <QSlider>
class Dialog: public QDialog
{
QSlider* brokenSlider;
public:
explicit Dialog(QWidget *parent = nullptr):QDialog(parent){
auto mainLayout = new QVBoxLayout;
brokenSlider = new QSlider(Qt::Horizontal, this);
mainLayout->addWidget(brokenSlider);
connect(brokenSlider, &QSlider::valueChanged, [&](){this->update();});
mainLayout->addWidget(new QSlider(Qt::Horizontal, this));
mainLayout->addWidget(new QSlider(Qt::Horizontal, this));
setLayout(mainLayout);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Dialog g;
g.exec();
}
我正在寻找这个 Apple/QT 错误的解决方法。
我能够解决将自定义样式表应用于滑块的问题。但是,这样做也会导致不显示刻度的问题。
我找到的解决方案是扩展 QSlider 并手动绘制:
myslider.h:
#pragma once
#include <QStylePainter>
#include <QStyleOptionSlider>
#include <QStyleOptionComplex>
#include <QSlider>
#include <QColor>
#include "math.h"
class MySlider:public QSlider
{
public:
explicit MySlider(Qt::Orientation orientation, QWidget *parent = nullptr):QSlider(orientation, parent){};
explicit MySlider(QWidget *parent = nullptr):QSlider(parent){
this->setStyleSheet("\
QSlider::groove:horizontal {\
height: 8px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ \
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);\
margin: 2px 0;\
}\
\
QSlider::handle:horizontal {\
background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);\
border: 1px solid #5c5c5c;\
width: 18px;\
margin: -2px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ \
border-radius: 3px;\
}\
");
};
protected:
virtual void paintEvent(QPaintEvent *ev)
{
QStylePainter p(this);
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
// draw tick marks
// do this manually because they are very badly behaved with style sheets
int interval = tickInterval();
if (interval == 0)
{
interval = pageStep();
}
if (tickPosition() != NoTicks)
{
for (int i = minimum(); i <= maximum(); i += interval)
{
int x = std::round((double)((double)((double)(i - this->minimum()) / (double)(this->maximum() - this->minimum())) * (double)(this->width() - handle.width()) + (double)(handle.width() / 2.0))) - 1;
int h = 4;
p.setPen(QColor("#a5a294"));
if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove)
{
int y = this->rect().top();
p.drawLine(x, y, x, y + h);
}
if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow)
{
int y = this->rect().bottom();
p.drawLine(x, y, x, y - h);
}
}
}
QSlider::paintEvent(ev);
}
};
在QT Creator中,如果使用表单,需要将上面的文件添加到提升的widgets列表中,然后需要提升每个QSlider才能使用这个class。
部分归功于:
更新(2021 年 12 月):QT 在 QT 6.2.3 中修复了这个问题
如此处所述 (https://bugreports.qt.io/browse/QTBUG-98093),QT 中的 QSlider 组件在新的 MacOS 更新中运行不正常。
如果我在同一个 window 中添加两个或多个水平滑块,拖动一个滑块中的手柄会影响其他滑块。这可能会导致它们一起移动,或者可能使下一个跳到意想不到的位置。
下面的代码可以重现问题:
#include <QApplication>
#include <QDialog>
#include <QVBoxLayout>
#include <QSlider>
class Dialog: public QDialog
{
QSlider* brokenSlider;
public:
explicit Dialog(QWidget *parent = nullptr):QDialog(parent){
auto mainLayout = new QVBoxLayout;
brokenSlider = new QSlider(Qt::Horizontal, this);
mainLayout->addWidget(brokenSlider);
connect(brokenSlider, &QSlider::valueChanged, [&](){this->update();});
mainLayout->addWidget(new QSlider(Qt::Horizontal, this));
mainLayout->addWidget(new QSlider(Qt::Horizontal, this));
setLayout(mainLayout);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Dialog g;
g.exec();
}
我正在寻找这个 Apple/QT 错误的解决方法。
我能够解决将自定义样式表应用于滑块的问题。但是,这样做也会导致不显示刻度的问题。 我找到的解决方案是扩展 QSlider 并手动绘制:
myslider.h:
#pragma once
#include <QStylePainter>
#include <QStyleOptionSlider>
#include <QStyleOptionComplex>
#include <QSlider>
#include <QColor>
#include "math.h"
class MySlider:public QSlider
{
public:
explicit MySlider(Qt::Orientation orientation, QWidget *parent = nullptr):QSlider(orientation, parent){};
explicit MySlider(QWidget *parent = nullptr):QSlider(parent){
this->setStyleSheet("\
QSlider::groove:horizontal {\
height: 8px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ \
background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);\
margin: 2px 0;\
}\
\
QSlider::handle:horizontal {\
background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);\
border: 1px solid #5c5c5c;\
width: 18px;\
margin: -2px 0; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ \
border-radius: 3px;\
}\
");
};
protected:
virtual void paintEvent(QPaintEvent *ev)
{
QStylePainter p(this);
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect handle = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
// draw tick marks
// do this manually because they are very badly behaved with style sheets
int interval = tickInterval();
if (interval == 0)
{
interval = pageStep();
}
if (tickPosition() != NoTicks)
{
for (int i = minimum(); i <= maximum(); i += interval)
{
int x = std::round((double)((double)((double)(i - this->minimum()) / (double)(this->maximum() - this->minimum())) * (double)(this->width() - handle.width()) + (double)(handle.width() / 2.0))) - 1;
int h = 4;
p.setPen(QColor("#a5a294"));
if (tickPosition() == TicksBothSides || tickPosition() == TicksAbove)
{
int y = this->rect().top();
p.drawLine(x, y, x, y + h);
}
if (tickPosition() == TicksBothSides || tickPosition() == TicksBelow)
{
int y = this->rect().bottom();
p.drawLine(x, y, x, y - h);
}
}
}
QSlider::paintEvent(ev);
}
};
在QT Creator中,如果使用表单,需要将上面的文件添加到提升的widgets列表中,然后需要提升每个QSlider才能使用这个class。
部分归功于:
更新(2021 年 12 月):QT 在 QT 6.2.3 中修复了这个问题