如何更改Qt中进度条默认样式的颜色
How to change color of default style for progressbar in Qt
如何在不更改其他默认渐变和效果的情况下更改默认 QProgressbar 样式中的绿色色调(有点明显的 "flow white chunk" 效果):
默认 QProgressbar 样式
.
我尝试使用 qlineargradient 为 QProgressBar::chunk:horizontal 设置新的背景颜色组合,但我没有成功使用任何此类样式表保持提到的效果。
可能尝试像这样使用计时器更新样式表:
mRunner = 0.1;
QTimer *mTimer = new QTimer(this);
connect(mTimer, SIGNAL(timeout()), this, SLOT(updateProgress()));
mTimer->start(40);
并且方法应该为每个新步骤更改梯度:
void MainWindow::updateProgress()
{
QString lStyle = QString("QProgressBar::chunk {background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:%1 white, stop:1 #b4b4b4);}").arg(mRunner);
ui->progressBar->setStyleSheet(lStyle);
mRunner += 0.01;
if (mRunner > 1) {
mRunner = 0.1;
}
}
我也在做同样的事情。在改变块颜色的同时保持白色流动的块是困难的部分。白色流动的块也有它自己的条件。部分使用 Volodymyr 的例子,这就是我想出的
首先我们将 QProgressBar 子类化
ProgressBar.h
class AnimProgressBar : public QProgressBar
{
Q_OBJECT
private:
const double c_overtime = 0.25;
const double c_speed = 0.025;
const double c_gsize = 0.02;
const double c_gap = 0.1;
const double opq = 180;
double overtime = c_overtime;
double speed = c_speed;
double gsize = c_gsize;
double gap = c_gap;
double aRunner = -0.2;
QString hue = "120";
QString val = "170";
const QString sat = "255";
std::mutex pbmtx;
std::condition_variable pbcv;
std::atomic<int> trueValue = 0;
std::atomic_flag setFlag{};
public:
QString font = "";
AnimProgressBar(QWidget* parent = nullptr);
private:
void valueUpdate();
void commitValue(int value);
public slots:
void ForeverLoop();
void newValue(int value);
};
ProgressBar.cpp
AnimProgressBar::AnimProgressBar(QWidget * parent)
{
QTimer *mTimer = new QTimer(this);
connect(mTimer, SIGNAL(timeout()), this, SLOT(ForeverLoop()));
mTimer->start(50);
}
然后我们设置颜色变化。在这种情况下,我使用的是 hsv。每个时钟周期1 + overtime
是白色流动块的每个周期。时钟速度为 speed
。以下是进度条流程中可能发生的所有场景
void AnimProgressBar::ForeverLoop()
{
QString color = hue + ", " + sat + ", " + val;
QString style
= font + "QProgressBar::chunk {background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, ";
QString trueopq = QString::number(255 - opq);
double bRunner = aRunner + gsize;
double aGap = aRunner - gap;
double bGap = bRunner + gap;
const auto BigOrEqual = [](double a, double b) { return a > b || AreDoubleSame(a, b); };
const auto SmallOrEqual = [](double a, double b) { return a < b || AreDoubleSame(a, b); };
// Symbols below are used to illustrate the progress bar coordination as visual representation
// [xx] : this is the opaque block
// [ : left side of the opaque block (aRunner)
// ] : right side of the opaque block (bRunner)
// xx : size of the opaque block (gap)
// ---- : this is the solid color section
// |S| : this is the start point
// |E| : this is the end point
// <== : this is the gradient gap
// |S|----------<==[xx]==>--------|E|
// Illustration above is visual for progress bar where the opaque block is flowing within the visible section
// Note: Visible section only exists between start point and end point, meaning in between |S| and |E|
if (SmallOrEqual(bGap, 0) || BigOrEqual(aGap, 1))
{
// <==[xx]==>--|S|---
// --|E|---<==[xx]==>
// block and gradient gap are outside of visible section
style.append("stop:0 hsv(%1)), stop:1 hsv(%1)");
}
else if (BigOrEqual(aRunner, 1))
{
if (SmallOrEqual(aGap, 0))
{
// <=|S|=|E|[xx]
// whole chunk only contains the gradient gap area
double num = 255 - std::fmin(255, std::fabs(aGap) / gap * opq);
style.append("stop:0 hsv(%1, " + QString::number(num) + ")");
}
else
{
// --|S|----------<=|E|=[xx]==>
// small gradient gap still within visible section
style.append("stop:" + QString::number(1 - gap) + " hsv(%1)");
}
double num = 255 - std::fmin(255, (1 + gap - aRunner) / gap * opq);
style.append(", stop:1 hsv(%1, " + QString::number(num) + ")");
}
else if (SmallOrEqual(bRunner, 0))
{
// <==[xx]=|S|=>----------
// only the gradient part of the opaque block is within the visible section at the start
double num = 255 - std::fmax(0, bGap / gap * opq);
style.append("stop:0 hsv(%1, " + QString::number(num) + "), stop:" + QString::number(bGap)
+ " hsv(%1)");
}
else if (SmallOrEqual(aRunner, 0))
{
// <==[x|S|x]==>
// only part of the opaque block is within the visible section at the start
style.append("stop:0 hsv(%1, " + trueopq + ")");
if (SmallOrEqual(bRunner, 1))
{
style.append(", stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq + ")");
if (BigOrEqual(bGap, 1))
{
// <==[x|S|x]==|E|>
// the progress bar's chunk is small that right end of the gradient gap is hitting the end of the progress bar chunk
double num = 255 - std::fmin(255, bGap - 1 / gap * opq);
style.append(", stop:1 hsv(%1, " + QString::number(num) + ")");
}
else
{
// <==[x|S|x]==>---------|E|
// ^
// bRunner
// the progress bar's chunk gradient gap not hitting the end
style.append(", stop:" + QString::number(bGap) + " hsv(%1)");
}
}
else
{
// <==[x|S|x|E|]==>
// the progress bar's chunk is so small that fits within the whole block
}
}
else if (SmallOrEqual(aGap, 0))
{
// <=|S|=[xx]
// part of the left gradient is outside of the start point
double anum = 255 - std::fmin(255, std::fabs(aGap) / gap * opq);
style.append("stop:0 hsv(%1, " + QString::number(anum) + "), stop:" + QString::number(aRunner) + " hsv(%1, " + trueopq + ")");
if (SmallOrEqual(bRunner, 1))
{
style.append(", stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq + ")");
if (BigOrEqual(bGap, 1))
{
// <=|S|=[xx]=|E|=>
// the part of the gradient area at left and right are outside of the start point and end point respectively
double bextra = bGap - 1;
double num = 255 - std::fmin(255, gap + bextra / gap * opq);
style.append(", stop:1 hsv(%1, " + QString::number(num) + ")");
}
else
{
// <=|S|=[xx]==>-------|E|
// part of the left gradient is outside of the start point
style.append(", stop:" + QString::number(bGap) + " hsv(%1)");
}
}
else
{
// <=|S|=[x|E|x]==>
// the part of the gradient area at left is outside of the start point while the block is outside of the end point
}
}
else if (BigOrEqual(bRunner, 1))
{
// ------<==[x|E|x]==>
// only part of the opaque block is within the end point
style.append("stop:" + QString::number(aGap) + " hsv(%1), stop:" + QString::number(aRunner) + " hsv(%1, "
+ trueopq + "), stop:0.99995 hsv(%1, " + trueopq + "), stop:1 hsv(%1)");
}
else if (BigOrEqual(bGap, 1))
{
// ------<==[xx]=|E|=>
// part of the right gradient is outside of the end point
double bextra = bGap - 1;
double bnum = 255 - std::fmin(255, gap + bextra / gap * opq);
style.append("stop:" + QString::number(aGap) + " hsv(%1), stop:" + QString::number(aRunner)
+ " hsv(%1, " + trueopq + "), stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq
+ "), stop:1 hsv(%1, " + QString::number(bnum) + ")");
}
else
{
// |S|----------<==[xx]==>--------|E|
// the opaque block is flowing within the visible section
style.append("stop:" + QString::number(aGap) + " hsv(%1), stop:" + QString::number(aRunner)
+ " hsv(%1, " + trueopq + "), stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq
+ "), stop:" + QString::number(bGap) + " hsv(%1)");
}
style.append(");}");
setStyleSheet(style.arg(color));
aRunner += speed;
if (aRunner < 0 - overtime || aGap > 1 + overtime) aRunner = 0 - overtime;
}
对于值的每一次变化,我们都会修改 hsv、gap 和时钟速度
void AnimProgressBar::newValue(int value)
{
int max = maximum();
if (0 < value && value <= max)
{
double decivalue = value;
double power = decivalue / max;
double mult = max / std::min(max, value);
overtime = c_overtime * mult;
speed = c_spped * mult;
gsize = c_gsize * mult;
gap = c_gap * mult;
hue = QString::number(static_cast<int>(120 - (decivalue / max * 120)));
val = QString::number(static_cast<int>(170 + (decivalue / max* 55)));
}
if (value == max * 7 / 10) font = "QProgressBar { color: rgb(255, 255, 255); } ";
setValue(value);
}
编辑:重写了更新循环
如何在不更改其他默认渐变和效果的情况下更改默认 QProgressbar 样式中的绿色色调(有点明显的 "flow white chunk" 效果):
默认 QProgressbar 样式
我尝试使用 qlineargradient 为 QProgressBar::chunk:horizontal 设置新的背景颜色组合,但我没有成功使用任何此类样式表保持提到的效果。
可能尝试像这样使用计时器更新样式表:
mRunner = 0.1;
QTimer *mTimer = new QTimer(this);
connect(mTimer, SIGNAL(timeout()), this, SLOT(updateProgress()));
mTimer->start(40);
并且方法应该为每个新步骤更改梯度:
void MainWindow::updateProgress()
{
QString lStyle = QString("QProgressBar::chunk {background-color: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:%1 white, stop:1 #b4b4b4);}").arg(mRunner);
ui->progressBar->setStyleSheet(lStyle);
mRunner += 0.01;
if (mRunner > 1) {
mRunner = 0.1;
}
}
我也在做同样的事情。在改变块颜色的同时保持白色流动的块是困难的部分。白色流动的块也有它自己的条件。部分使用 Volodymyr 的例子,这就是我想出的
首先我们将 QProgressBar 子类化
ProgressBar.h
class AnimProgressBar : public QProgressBar
{
Q_OBJECT
private:
const double c_overtime = 0.25;
const double c_speed = 0.025;
const double c_gsize = 0.02;
const double c_gap = 0.1;
const double opq = 180;
double overtime = c_overtime;
double speed = c_speed;
double gsize = c_gsize;
double gap = c_gap;
double aRunner = -0.2;
QString hue = "120";
QString val = "170";
const QString sat = "255";
std::mutex pbmtx;
std::condition_variable pbcv;
std::atomic<int> trueValue = 0;
std::atomic_flag setFlag{};
public:
QString font = "";
AnimProgressBar(QWidget* parent = nullptr);
private:
void valueUpdate();
void commitValue(int value);
public slots:
void ForeverLoop();
void newValue(int value);
};
ProgressBar.cpp
AnimProgressBar::AnimProgressBar(QWidget * parent)
{
QTimer *mTimer = new QTimer(this);
connect(mTimer, SIGNAL(timeout()), this, SLOT(ForeverLoop()));
mTimer->start(50);
}
然后我们设置颜色变化。在这种情况下,我使用的是 hsv。每个时钟周期1 + overtime
是白色流动块的每个周期。时钟速度为 speed
。以下是进度条流程中可能发生的所有场景
void AnimProgressBar::ForeverLoop()
{
QString color = hue + ", " + sat + ", " + val;
QString style
= font + "QProgressBar::chunk {background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, ";
QString trueopq = QString::number(255 - opq);
double bRunner = aRunner + gsize;
double aGap = aRunner - gap;
double bGap = bRunner + gap;
const auto BigOrEqual = [](double a, double b) { return a > b || AreDoubleSame(a, b); };
const auto SmallOrEqual = [](double a, double b) { return a < b || AreDoubleSame(a, b); };
// Symbols below are used to illustrate the progress bar coordination as visual representation
// [xx] : this is the opaque block
// [ : left side of the opaque block (aRunner)
// ] : right side of the opaque block (bRunner)
// xx : size of the opaque block (gap)
// ---- : this is the solid color section
// |S| : this is the start point
// |E| : this is the end point
// <== : this is the gradient gap
// |S|----------<==[xx]==>--------|E|
// Illustration above is visual for progress bar where the opaque block is flowing within the visible section
// Note: Visible section only exists between start point and end point, meaning in between |S| and |E|
if (SmallOrEqual(bGap, 0) || BigOrEqual(aGap, 1))
{
// <==[xx]==>--|S|---
// --|E|---<==[xx]==>
// block and gradient gap are outside of visible section
style.append("stop:0 hsv(%1)), stop:1 hsv(%1)");
}
else if (BigOrEqual(aRunner, 1))
{
if (SmallOrEqual(aGap, 0))
{
// <=|S|=|E|[xx]
// whole chunk only contains the gradient gap area
double num = 255 - std::fmin(255, std::fabs(aGap) / gap * opq);
style.append("stop:0 hsv(%1, " + QString::number(num) + ")");
}
else
{
// --|S|----------<=|E|=[xx]==>
// small gradient gap still within visible section
style.append("stop:" + QString::number(1 - gap) + " hsv(%1)");
}
double num = 255 - std::fmin(255, (1 + gap - aRunner) / gap * opq);
style.append(", stop:1 hsv(%1, " + QString::number(num) + ")");
}
else if (SmallOrEqual(bRunner, 0))
{
// <==[xx]=|S|=>----------
// only the gradient part of the opaque block is within the visible section at the start
double num = 255 - std::fmax(0, bGap / gap * opq);
style.append("stop:0 hsv(%1, " + QString::number(num) + "), stop:" + QString::number(bGap)
+ " hsv(%1)");
}
else if (SmallOrEqual(aRunner, 0))
{
// <==[x|S|x]==>
// only part of the opaque block is within the visible section at the start
style.append("stop:0 hsv(%1, " + trueopq + ")");
if (SmallOrEqual(bRunner, 1))
{
style.append(", stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq + ")");
if (BigOrEqual(bGap, 1))
{
// <==[x|S|x]==|E|>
// the progress bar's chunk is small that right end of the gradient gap is hitting the end of the progress bar chunk
double num = 255 - std::fmin(255, bGap - 1 / gap * opq);
style.append(", stop:1 hsv(%1, " + QString::number(num) + ")");
}
else
{
// <==[x|S|x]==>---------|E|
// ^
// bRunner
// the progress bar's chunk gradient gap not hitting the end
style.append(", stop:" + QString::number(bGap) + " hsv(%1)");
}
}
else
{
// <==[x|S|x|E|]==>
// the progress bar's chunk is so small that fits within the whole block
}
}
else if (SmallOrEqual(aGap, 0))
{
// <=|S|=[xx]
// part of the left gradient is outside of the start point
double anum = 255 - std::fmin(255, std::fabs(aGap) / gap * opq);
style.append("stop:0 hsv(%1, " + QString::number(anum) + "), stop:" + QString::number(aRunner) + " hsv(%1, " + trueopq + ")");
if (SmallOrEqual(bRunner, 1))
{
style.append(", stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq + ")");
if (BigOrEqual(bGap, 1))
{
// <=|S|=[xx]=|E|=>
// the part of the gradient area at left and right are outside of the start point and end point respectively
double bextra = bGap - 1;
double num = 255 - std::fmin(255, gap + bextra / gap * opq);
style.append(", stop:1 hsv(%1, " + QString::number(num) + ")");
}
else
{
// <=|S|=[xx]==>-------|E|
// part of the left gradient is outside of the start point
style.append(", stop:" + QString::number(bGap) + " hsv(%1)");
}
}
else
{
// <=|S|=[x|E|x]==>
// the part of the gradient area at left is outside of the start point while the block is outside of the end point
}
}
else if (BigOrEqual(bRunner, 1))
{
// ------<==[x|E|x]==>
// only part of the opaque block is within the end point
style.append("stop:" + QString::number(aGap) + " hsv(%1), stop:" + QString::number(aRunner) + " hsv(%1, "
+ trueopq + "), stop:0.99995 hsv(%1, " + trueopq + "), stop:1 hsv(%1)");
}
else if (BigOrEqual(bGap, 1))
{
// ------<==[xx]=|E|=>
// part of the right gradient is outside of the end point
double bextra = bGap - 1;
double bnum = 255 - std::fmin(255, gap + bextra / gap * opq);
style.append("stop:" + QString::number(aGap) + " hsv(%1), stop:" + QString::number(aRunner)
+ " hsv(%1, " + trueopq + "), stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq
+ "), stop:1 hsv(%1, " + QString::number(bnum) + ")");
}
else
{
// |S|----------<==[xx]==>--------|E|
// the opaque block is flowing within the visible section
style.append("stop:" + QString::number(aGap) + " hsv(%1), stop:" + QString::number(aRunner)
+ " hsv(%1, " + trueopq + "), stop:" + QString::number(bRunner) + " hsv(%1, " + trueopq
+ "), stop:" + QString::number(bGap) + " hsv(%1)");
}
style.append(");}");
setStyleSheet(style.arg(color));
aRunner += speed;
if (aRunner < 0 - overtime || aGap > 1 + overtime) aRunner = 0 - overtime;
}
对于值的每一次变化,我们都会修改 hsv、gap 和时钟速度
void AnimProgressBar::newValue(int value)
{
int max = maximum();
if (0 < value && value <= max)
{
double decivalue = value;
double power = decivalue / max;
double mult = max / std::min(max, value);
overtime = c_overtime * mult;
speed = c_spped * mult;
gsize = c_gsize * mult;
gap = c_gap * mult;
hue = QString::number(static_cast<int>(120 - (decivalue / max * 120)));
val = QString::number(static_cast<int>(170 + (decivalue / max* 55)));
}
if (value == max * 7 / 10) font = "QProgressBar { color: rgb(255, 255, 255); } ";
setValue(value);
}
编辑:重写了更新循环