Сложность управления QSlider в QGridLayout

#qt #qt4 #qslider

#qt #qt4 #qslider

Вопрос:

Я пытаюсь создать динамический QSlider, который принимает QVector целочисленных значений и отображает их под QSlider относительно того, какую позицию они представляют.

Вот скриншот того, что у меня есть сейчас: Мой слайдер http://dev.kyleswebspace.com/images/QInteractiveSlider.jpg

Как вы можете видеть, отметки не совпадают с их значениями. Это одна из проблем.

Основная проблема, с которой я борюсь, заключается в том, что независимо от того, на что я меняю значение заполнения (см. qinteractiveslider.h), QSlider в моем виджете остается того же размера по отношению к сетке значений.

  1. Почему аргументы моего QGridLayout не предоставляют правильное количество отступов?
  2. Как я могу принудительно использовать эти поля в QSlider?
  3. Есть ли лучший способ позиционирования этих меток? Я открыт для предложений.

Вот код:

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();
}
  

Комментарии:

1. В итоге я согласился с предложением Лиз, и оно отлично сработало. Спасибо, Лиз!

Ответ №1:

Я не уверен, что макет сетки — лучший способ добиться этого.

Во-первых, я бы позволил слайдеру позаботиться о себе — в макете. И тогда большой задачей было бы разместить метки там, где они должны быть.

Вместо того, чтобы использовать макет для этого, я бы просто привязал метки к родительскому QWidget, а затем вызвал

QWidget::move(int x, int y)

Однако это сработает только в первый раз, но поскольку вы очень хорошо изолированы в QWidget (пользовательском элементе управления), вы можете повторно настроить позиции меток при изменении размера родительского элемента следующим образом:

 void QInteractiveSlider::resizeEvent(QResizeEvent *event)
{
   QWidget::resizeEvent(event);

   //  Loop through the labels and adjust their location.
   label->move(...);
}
  

Это должно сработать.

Если вы столкнетесь с какими-либо проблемами с этим, дайте мне знать, и мы посмотрим, что мы можем сделать.

Комментарии:

1. В итоге я выбрал именно этот метод, и он работал фантастически. Большое спасибо.

Ответ №2:

Я не могу напрямую ответить на 1-й и 2-й вопросы. Отображать числа по отдельности — плохая идея. Поскольку теперь вы должны знать, где вручную отображать числа. Это не очень переносимо и нарушает инкапсуляцию. Это также может неправильно масштабироваться при изменении размеров QSlider. Поскольку QSlider не предоставляет возможности отображения чисел под тиками, вам следует либо расширить QSlider и переписать функцию paint(), либо использовать QWT. http://qwt.sourceforge.net/class_qwt_slider.html

Комментарии:

1. Я также должен иметь возможность сделать эти отображаемые числа интерактивными, чтобы нажатие на число регулировало ползунок. Как я могу этого добиться, если я пойду по пути переопределения paint ()?

Ответ №3:

Возможно, вы также могли бы вместо этого использовать комбинацию QHBoxLayouts, чтобы вы могли правильно размещать объекты без особых проблем с полями.

Вот скриншот того, что выдает следующий код:

введите описание изображения здесь

Вы могли бы сделать это немного красивее, указав максимальную ширину надписей. Таким образом, вы могли бы избежать необходимости устанавливать для них выравнивание по левому краю.

 #ifndef DESIGNERLS7532_H
#define DESIGNERLS7532_H

#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QHBoxLayout>
#include <QtGui/QHeaderView>
#include <QtGui/QLabel>
#include <QtGui/QSlider>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWidget>

QT_BEGIN_NAMESPACE

class Ui_Form
{
public:
    QVBoxLayout *verticalLayout;
    QWidget *widget;
    QHBoxLayout *horizontalLayout;
    QSlider *horizontalSlider;
    QWidget *widget_2;
    QHBoxLayout *horizontalLayout_2;
    QLabel *label;
    QLabel *label_4;
    QLabel *label_2;
    QLabel *label_5;
    QLabel *label_3;

    void setupUi(QWidget *Form)
    {
        if (Form->objectName().isEmpty())
            Form->setObjectName(QString::fromUtf8("Form"));
        Form->resize(268, 55);
        verticalLayout = new QVBoxLayout(Form);
        verticalLayout->setSpacing(0);
        verticalLayout->setContentsMargins(0, 0, 0, 0);
        verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
        widget = new QWidget(Form);
        widget->setObjectName(QString::fromUtf8("widget"));
        horizontalLayout = new QHBoxLayout(widget);
        horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
        horizontalLayout->setContentsMargins(-1, -1, -1, 0);
        horizontalSlider = new QSlider(widget);
        horizontalSlider->setObjectName(QString::fromUtf8("horizontalSlider"));
        horizontalSlider->setOrientation(Qt::Horizontal);
        horizontalSlider->setTickPosition(QSlider::TicksBelow);

        horizontalLayout->addWidget(horizontalSlider);


        verticalLayout->addWidget(widget);

        widget_2 = new QWidget(Form);
        widget_2->setObjectName(QString::fromUtf8("widget_2"));
        horizontalLayout_2 = new QHBoxLayout(widget_2);
        horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2"));
        horizontalLayout_2->setContentsMargins(-1, 0, -1, -1);
        label = new QLabel(widget_2);
        label->setObjectName(QString::fromUtf8("label"));

        horizontalLayout_2->addWidget(label);

        label_4 = new QLabel(widget_2);
        label_4->setObjectName(QString::fromUtf8("label_4"));
        label_4->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);

        horizontalLayout_2->addWidget(label_4);

        label_2 = new QLabel(widget_2);
        label_2->setObjectName(QString::fromUtf8("label_2"));
        label_2->setAlignment(Qt::AlignCenter);

        horizontalLayout_2->addWidget(label_2);

        label_5 = new QLabel(widget_2);
        label_5->setObjectName(QString::fromUtf8("label_5"));
        label_5->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

        horizontalLayout_2->addWidget(label_5);

        label_3 = new QLabel(widget_2);
        label_3->setObjectName(QString::fromUtf8("label_3"));
        label_3->setAlignment(Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter);

        horizontalLayout_2->addWidget(label_3);

        horizontalLayout_2->setStretch(0, 1);
        horizontalLayout_2->setStretch(1, 1);
        horizontalLayout_2->setStretch(2, 1);
        horizontalLayout_2->setStretch(3, 1);
        horizontalLayout_2->setStretch(4, 1);

        verticalLayout->addWidget(widget_2);


        retranslateUi(Form);

        QMetaObject::connectSlotsByName(Form);
    } // setupUi

    void retranslateUi(QWidget *Form)
    {
        Form->setWindowTitle(QApplication::translate("Form", "Form", 0, QApplication::UnicodeUTF8));
        label->setText(QApplication::translate("Form", "0", 0, QApplication::UnicodeUTF8));
        label_4->setText(QApplication::translate("Form", "25", 0, QApplication::UnicodeUTF8));
        label_2->setText(QApplication::translate("Form", "50", 0, QApplication::UnicodeUTF8));
        label_5->setText(QString());
        label_3->setText(QApplication::translate("Form", "100", 0, QApplication::UnicodeUTF8));
    } // retranslateUi

};

namespace Ui {
    class Form: public Ui_Form {};
} // namespace Ui

QT_END_NAMESPACE

#endif // DESIGNERLS7532_H
  

Комментарии:

1. Спасибо за усилия, но мне нужно иметь возможность принимать неопределенное количество неопределенных целых чисел для неопределенного диапазона (вся эта информация будет передана в конструктор).

2. Понял. Планируете ли вы просто увеличить размер слайдера, чтобы компенсировать добавленные целые числа, или отфильтровать их, когда их наберется слишком много? В примере показана статическая версия, однако вы могли бы динамически добавлять qlabels для целых чисел, которые вы показывали в horizontalLayout_2.