Reputation: 1313
How is it possible to change the color and/or text(format) of a QProgressBar
if the mouse is over the filled part of the bar?
I have stacked multiple QProgressBar
s on top of each other, each showing more content than the previous.
I want to highlight the biggest bar still under the mouse on mouseover and show some bar-specific text. However, the bars are the same size and therefore I want to recognize the filled area of the bar.
E.g., if the mouse is over the third bar, I want to highlight the part from the left to the third bar and show text specific to the third bar.
This is the code I use for the stacked ProgressBars:
class MultiProgressBar : public QWidget
{
Q_OBJECT
public:
MultiProgressBar( QWidget* parent = Q_NULLPTR ) : QWidget( parent ), layout( new QStackedLayout( this ) )
{
layout->setMargin( 0 );
layout->setStackingMode( QStackedLayout::StackAll );
}
void insertBar( QColor const& color )
{
auto bar = new QProgressBar();
bar->setTextVisible( false );
bar->setRange( 0, 10000 );
QPalette palette = this->palette();
palette.setColor( QPalette::Highlight, QColor( color.red(), color.green(), color.blue(), 100 ) );
palette.setColor( QPalette::Base, QColor( color.red(), color.green(), color.blue(), 0 ) );
bar->setPalette( palette );
layout->addWidget( bar );
progress_bars.push_back( bar );
}
public slots:
void setValues( const std::vector< int >& values, const std::vector< std::string >& names )
{
if ( values.size() < progress_bars.size() )
{
for ( auto* widget : progress_bars )
{
layout->removeWidget( widget );
}
progress_bars.clear();
}
while ( progress_bars.size() < values.size() )
{
insertBar( QColor( 0x46, 0xA1, 0xD9, 255 ) );
}
for ( auto i = 0; i < progress_bars.size(); ++i )
{
progress_bars[ i ]->setValue( values[ i ] );
// progress_bars[ i ]->setFormat( QString::fromStdString( names[ i ] ) );
}
}
private:
std::vector< QProgressBar* > progress_bars;
QStackedLayout* layout;
};
Upvotes: 0
Views: 623
Reputation: 101
1) To change color of filled area you can set new color to the palette of progressbar like this:
QPalette newPalette = bar.palette();
newPalette.setColor(QPalette::Highlight, "red"); // setting color to red
bar.setPalette(newPalette);
2.1) Assign text to progressbar you can with void setFormat(const QString &format);
function like in your commented string
progress_bars[ i ]->setFormat( QString::fromStdString( names[ i ] ) );
2.2) Get this text you can by calling QProgressBar::text()
function;
3) If you want to highlight specific progressbars you can reimplement
QWidget::mouseMoveEvent(QMouseEvent *event);
in which you can calculate margins of filled area:
void mouseMoveEvent(QMouseEvent *e){
highlightProgressBars(e->pos()); // passing position of mouse cursor
}
NOTE: Don't forget to enable mouse tracking for progressbars and your MultiProgressBar
widget:
bar->setMouseTracking(true);
4) Function below gets position of mouse in parameter. It highlights area from left to pointed progressbar inclusively and shows in console text assigned to highlighted progressbars through format
property
void highlightProgressBars(QPoint point){
int widthOfBar = ((QProgressBar*)progress_bars.at(0))->width();
int valueForPoint = 10000 / widthOfBar; // value of progressbar for width==1
for (auto pb = this->progress_bars.begin(); pb != this->progress_bars.end(); ++pb) { // iterating vector to paint progressbars
int leftMargin = 0; // "left margin" of current progressbar is in fact right margin of filled area of previous progressbar
if(pb != this->progress_bars.begin()){ // except first progressbar in vector which doesn't have previous progressbar
--pb; // get previous progressbar
leftMargin = ((QProgressBar*)*pb)->value() / valueForPoint; // get width of filled area
++pb; // return to current progressbar
}
if(leftMargin < point.x()) { // if position of cursor is to the right of "left margin" of current progressbar we highlight it
QPalette newPal = ((QProgressBar*)*pb)->palette(); //getting palette
newPal.setColor(QPalette::Highlight,"red"); // and setting color of filled area
((QProgressBar*)*pb)->setPalette(newPal); // finally setting palette to widget
qDebug() << ((QProgressBar*)*pb)->text(); // show text of highlighted progressbar in console
}
else{ // if not we highlight it another way
QPalette newPal = ((QProgressBar*)*pb)->palette();
newPal.setColor(QPalette::Highlight,"lightblue");
((QProgressBar*)*pb)->setPalette(newPal);
}
}
}
If you want to highlight only one progressbar you should change in code above this:
if(leftMargin < point.x()) {
to:
int rightMargin = ((QProgressBar*)*pb)->value() / valueForPoint;
if(leftMargin < point.x() && point.x() < rightMargin) {
Upvotes: 2