Search code examples
qtqt4qslider

Difficulty Manipulating QSlider in a QGridLayout


I'm trying to create a dynamic QSlider that accepts a QVector of integer values and maps them underneath the QSlider relative to what position they represent.

Here's a screenshot of what I have now: My Slider http://dev.kyleswebspace.com/images/QInteractiveSlider.jpg

As you can see, the ticks don't line up with their values. This is one of the issues.

The main issue I'm struggling with though, is that no matter what I change my PADDING value to (see qinteractiveslider.h), the QSlider in my widget remains the same size in relation to the grid of values.

  1. Why isn't my QGridLayout's arguments providing the correct amount of padding?
  2. How can I enforce these margins on the QSlider?
  3. Is there a better way of positioning these labels? I'm open to suggestions.

Here is the code:

qinteractiveslider.h

#ifndef QINTERACTIVESLIDER_H
#define QINTERACTIVESLIDER_H

#include <QtGui/QGridLayout>
#include <QtGui/QLabel>
#include <QtGui/QSlider>
#include <QtGui/QWidget>

class QInteractiveSlider : public QWidget
 {
     Q_OBJECT

public:
    QInteractiveSlider(QVector<int>* values, int min, int max, QWidget *parent = 0, Qt::WFlags flags = 0);
    ~QInteractiveSlider();

private:
    static const int GRID_WIDTH = 10000;
    static const int PADDING = GRID_WIDTH / 3;

    QGridLayout* m_layout;
    QSlider* m_slider;
    QVector<int>* m_values;
};

qinteractiveslider.cpp

#include "qinteractiveslider.h"

QInteractiveSlider::QInteractiveSlider(QVector<int>* values, int min, int max, QWidget *parent, Qt::WFlags flags)
    : QWidget(parent, flags)
{
    m_layout = new QGridLayout();
    m_layout->setSpacing(0);

    m_slider = new QSlider(Qt::Horizontal);
    m_slider->setTickInterval(25);
    m_slider->setTickPosition(QSlider::TicksBelow);

    m_layout->addWidget(m_slider, 0, PADDING, 1, GRID_WIDTH - PADDING, Qt::AlignBottom);

    //populate bottom row with labels
    QVector<int>::Iterator iterator = values->begin();
    while(iterator != values->end()) {
        //place the label at the relative position under the slider
        int columnIndex = ((double)*iterator / (double)max) * (double)GRID_WIDTH;
        QString labelString = QString::number(*iterator);
        QLabel* label = new QLabel(labelString);
        m_layout->addWidget(label, 1, columnIndex, 1, 1, Qt::AlignTop);

        iterator++;
    }

    this->setLayout(m_layout);
}

QInteractiveSlider::~QInteractiveSlider()
{

}

main.cpp

#include "qinteractiveslider.h"
#include <QtGui/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QVector<int>* testVector = new QVector<int>();
    testVector->append(0);
    testVector->append(50);
    testVector->append(25);
    testVector->append(100);

    QInteractiveSlider* w = new QInteractiveSlider(testVector, 0, 100);
    w->show();

    return a.exec();
}

Solution

  • I'm not sure that a grid layout is the best way to go about this.

    Firstly, I would let the slider take care of itself - in a layout. And then the big job would be to place the labels where they should go.

    Instead of using a layout for this, I would just parent the labels to the parent QWidget and then call

    QWidget::move(int x, int y)

    However, this will only work the first time, but since you are very nicely isolated in a QWidget (custom control) you can re-adjust the label positions when the parent resizes as follows:

    void QInteractiveSlider::resizeEvent(QResizeEvent *event)
    {
       QWidget::resizeEvent(event);
    
       //  Loop through the labels and adjust their location.
       label->move(...);
    }
    

    That should do the trick.

    If you run across any problems with this, let me know, and we'll see what we can do.