Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: QWizard
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt GUI
FladeX
При помощи QWizard создана программа - набор страниц, связанных "назад"/"далее" кнопками.
Задача - при помощи чекбоксов, выводимых на первой странице, выводить или не выводить последующие страницы. Как это реализовать?

Т.е. на первой странице чекбоксы "страница 2", "страница 3", "страница 4". Если мы отмечаем "страница 2" и "страница 4", то по нажатию "далее" будет показана страница 2, а затем 4, то есть страница 3 будет пропущена.
FladeX
Какие-нибудь идеи есть?
SABROG
Такая есть идея http://doc.trolltech.com/4.5/qwizard.html#...-linear-wizards
FladeX
Теперь такой вопрос - как из первого листа назначить nextId() для всех остальных? Пробовал по-всякому, результата нет(

class Func01Page : public QWizardPage
{
    Q_OBJECT
public:
    Func01Page(QWidget *parent = 0);

    int nextId() const;
    int IDValue;
};

и аналогичный Func02Page.
Нужно в
int Func01Page::nextId() const
{
    return ExpertSystem::Page_Func02;
}

изменить nextId() для Func02Page. Как это сделать?
FladeX
class ExpertSystem : public QWizard
{
    Q_OBJECT

public:
    enum
    {
        Page_Intro,
        Page_Func01,
        // ...
        Page_Func27,
        Page_Outro
    };

    ExpertSystem(QWidget *parent = 0);

private slots:
    void showHelp();
};

Так и не понял, как обращаться к enum {}...
В документации нашел такую фразу:
Цитата
If you want to register an enum that is declared in another class, the enum must be fully qualified with the name of the class defining it. In addition, the class defining the enum has to inherit QObject as well as declare the enum using Q_ENUMS().

Подскажите плиз.
AD
ExpertsSystem:: Page_Intro


В данном случае лучше, чтобы enum имел иия.
Например, так:
enum PAGES
{
Page_Intro,
Page_Func01,
// ...
};

Тогда можно будет использовать в качестве типа:
ExpertsSystem:: PAGES
.
Если же Вы имели что-то другое, то, пожалуйста, конкретнее проблему опишите! :)
kwisp
Цитата(FladeX @ 19.3.2009, 15:24) *
Так и не понял, как обращаться к enum {}...

ну назови его
enum EPages{...};

и обращайся
в нутри класса
Page_Intro;

за пределами класса
ExpertSystem::Page_Intro;
FladeX
На основе этого примера сделал визард. Но отличие в том, что на первой странице список чекбоксов, которые и определяют, какие страницы будут показаны, а какие нет. Собственно проблема в том, что кроме первой страницы я не могу ничего изменить...

Итак, есть класс:
код класса
class ExpertSystem : public QWizard
{
    Q_OBJECT

public:
    enum
    {
        Page_Intro,
        Page_Func01,
        // ...
        Page_Func27,
        Page_Outro
    };

    ExpertSystem(QWidget *parent = 0);

private slots:
    void showHelp();
};

Есть первая страница с чекбоксами:
первая страница
class IntroPage : public QWizardPage
{
    Q_OBJECT

public:
    IntroPage(QWidget *parent = 0);

    int nextId() const;
    int IDValue;

//private:
public:
    QCheckBox *func01;
    QCheckBox *func02;
    //..
    QCheckBox *func26;
    QCheckBox *func27;
};

Enum с страницами связан так:
конструктор
ExpertSystem::ExpertSystem(QWidget *parent)
    : QWizard(parent)
{
    setPage(Page_Intro, new IntroPage);
    setPage(Page_Func01, new Func01Page);
    setPage(Page_Func02, new Func02Page);
    //..
    setPage(Page_Func27, new Func27Page);
    setPage(Page_Outro, new OutroPage);

    setStartId(Page_Intro);
}

Как теперь изменить значение int nextId() const к примеру для Page_Func27 ? Изменять отсюда (ибо чекбоксы только на первой странице):
int IntroPage::nextId() const
{
FladeX
Ну подскажите же эту строчку)
kwisp
FladeX,
по аналогии действуй
Раскрывающийся текст

int IntroPage::nextId() const
{
     if (evaluateRadioButton->isChecked()) {
         return LicenseWizard::Page_Evaluate;
     } else {
         return LicenseWizard::Page_Register;
     }
}

int EvaluatePage::nextId() const
{
     return LicenseWizard::Page_Conclusion;
}

int RegisterPage::nextId() const
{
     if (upgradeKeyLineEdit->text().isEmpty()) {
         return LicenseWizard::Page_Details;
     } else {
         return LicenseWizard::Page_Conclusion;
     }
}

int DetailsPage::nextId() const
{
     return LicenseWizard::Page_Conclusion;
}

int ConclusionPage::nextId() const
{
     return -1;
}

It would also be possible to put all the logic in one place, in a QWizard::nextId() reimplementation. For example:
 int LicenseWizard::nextId() const
{
     switch (currentId()) {
     case Page_Intro:
         if (field("intro.evaluate").toBool()) {
             return Page_Evaluate;
         } else {
             return Page_Register;
         }
     case Page_Evaluate:
         return Page_Conclusion;
     case Page_Register:
         if (field("register.upgradeKey").toString().isEmpty()) {
             return Page_Details;
         } else {
             return Page_Conclusion;
         }
     case Page_Details:
         return Page_Conclusion;
     case Page_Conclusion:
     default:
         return -1;
     }
}


получается тебя надо вернуть Page_Outro или я так чего то и не понял.
FladeX
Уже что-то, спасибо!
Допустим есть конструкция вида
 int LicenseWizard::nextId() const
{
     switch (currentId()) {
     }
}

Как оттуда узнать состояния чекбоксов (напоминаю, что они на первой странице визарда расположены)?
Litkevich Yuriy
Цитата(FladeX @ 21.3.2009, 17:22) *
узнать состояния чекбоксов
насколько я помню, в мастерах Qt есть понятие "полей", и используется манипуляция с полями, а не с виджетами, т.е. ты их должен создавать/инициализировать/изменять. Поля видны на всех страницах мастера.

П.С. с терминами могу ошибаться

Пример, хоть и на аглицком
FladeX
Спасибо, вроде именно то что надо.
Только вот не компилиться теперь:
moc_expertsystem.o:(.rodata._ZTV10Func02Page[vtable for Func02Page]+0xf0): undefined reference to `Func02Page::nextId() const'
moc_expertsystem.o:(.rodata._ZTV10Func01Page[vtable for Func01Page]+0xf0): undefined reference to `Func01Page::nextId() const'
moc_expertsystem.o:(.rodata._ZTV9IntroPage[vtable for IntroPage]+0xf0): undefined reference to `IntroPage::nextId() const'

Это что за ошибка такая?
Litkevich Yuriy
Цитата(FladeX @ 22.3.2009, 0:57) *
Это что за ошибка такая?
Цитата(FladeX @ 22.3.2009, 0:57) *
moc_expertsystem.o
возможно ты добавил где-то макрос Q_OBJECT, а qmake при этом не вызывал. Либо объявление класса и его реализацию поместил в один файл неподключив соответсявующий, автоматически создаваемый, файл (в твоем случае moc_expertsystem.cpp)
kalombo
Вклинюсь сюда тоже со своим вопросом, надеюсь никому не помешаю. Вопрос такой. Создал я значит свой класс производный от QWizard, для него сделал несколько страниц производных от класс QWizardPage. И вот на одной из страниц у меня есть QTableWIdget, как к нему обращаться с других страниц к примеру? В моем случае мне надо обращаться к этому виджету в методе класса QWizard::accept(), что позволило мне решить проблему следующим образом. Я создал для страницы на которой QTableWidget паблик метод, возвращающий ссылку на этот виджет и потом в классе QWizard вызываю этот метод. Такой способ решения мне кажется не очень красивым, а как с другой страницы получить доступ к этому виджету вообще непонятно.
SABROG
Полагаю, что одним из этих методов:

QTableWidget *tbw = wizard()->page(id)->getTableWidgetPointer();
QTableWidget *tbw = wizard()->page(id)->findChild<QTableWidget *>("mytablewidgetname");
QTableWidget *tbw = wizard()->page(id)->justPublicTableWidgetPointer;


Вообще в QWizardPage есть методы registerField() и field(). Это глобальные методы, если ты регистрируешь свое поле, то оно доступно через метод field() из любой страницы, загвоздка в том, что это работает только на следующие поля-классы:

Цитата
QAbstractButton
QAbstractSlider
QComboBox
QDateTimeEdit
QLineEdit
QListWidget
QSpinBox


Есть еще метод QWizard::setDefaultProperty(), который позволяет расширить список классов. Например:

    setDefaultProperty("QTableWidget", "currentItem", SIGNAL(currentItemChanged()));
    ...
    QTableWidgetItem *item = field("QTableWidget").value<QTableWidgetItem *>();


По идее любому своему объекту (QObject) можно добавлять динамические свойства и получать их из любой страницы. На самом деле это эквивалентно такому:

Wizard::Wizard(QWidget *parent) : public QWizard(parent)
{
    setProperty("pointerToMyTable", qVariantFromValue(tableWidgetPtr));
}

WizardPage1::WizardPage1(QWidget *parent) : public QWizardPage(parent)
{
    QTableWidget *table = parent()->property("pointerToMyTable").value<QTableWidget *>();
}


Но это в теории, сам я с этим классом никогда не работал.
FladeX
То есть для чекбоксов получается так:
    setDefaultProperty("QCheckBox", "currentItem", SIGNAL(currentItemChanged()));

    func01 = new QCheckBox(QObject::trUtf8("Чекбокс"));

    registerField("introfunc01", func01);

И потом обращаться как:
field(introfunc01)->isChecked(true)

Но не получается (
SABROG
Цитата(FladeX @ 25.3.2009, 13:07) *
field(introfunc01)->isChecked(true)


Че за бред :wacko:

field возвращает QVariant, а там уже может быть что-угодно, а не указатель на QCheckBox. Ты уж определись, что ты используешь registerField или setDefaultProperty. Эти функции делают одно и то же по сути.
FladeX
То есть получается что для чекбоксов registerField вообще не подходит?
А с setProperty так и не разобрался, как их использовать в случае чекбоксов...
FladeX
Подскажите что можно сделать с чекбоксами :)
На первой странице несколько чекбоксов, каждый из которых соответсвует одной странице. При checked страница будет доступна в визарде, при !checked не будет. >_<
Kagami
Что-то все коллективно тупят :)
Цитата
The QCheckBox widget provides a checkbox with a text label. More...

#include <QCheckBox>
Inherits QAbstractButton.
SABROG
Цитата(FladeX @ 14.5.2009, 12:07) *
Подскажите что можно сделать с чекбоксами :)
На первой странице несколько чекбоксов, каждый из которых соответсвует одной странице. При checked страница будет доступна в визарде, при !checked не будет. >_<

Я тебя правильно понимаю, проблема в том, что в "нелинейном" визарде переход на страницу либо осуществляется либо нет, но она доступна. Ты хочешь динамически генерить и удалять страницы в зависимости от выбора в чекбоксе?
FladeX
Kagami, и тем не менее, через registerFields у меня не получилось.
SABROG, генерировать и удалять не нужно. Есть конечный список предопределенных страниц, каждой из которых сопоставлен чекбокс. Если чекбокс отмечен, то эта страница будет отображаться в визарде по кнопке Next. Если чекбокс не отмечен, то страница эта не будет отображаться. Для такой реализации нужно просто перезадать nextId для каждой из страниц. Однако при этом я столкнулся с трудностью - область видимости переменных - чекбоксы-то только на первой странице, а nextId по одному на каждой (каждая страница - отдельный класс, унаследованный от QWizardPage).
Kagami
В конструкторе страницы делаем:
registerField("checkBox1", checkBox1);

В nextID():
if (field("checkBox1").toBool()) {
//Если выбрано
...
} else {
//Иначе
...
}

P.S. Если читать документацию внимательней, то необходимость в 80% темах отпадает :)
FladeX
Да, теперь все работает. Благодарю!

Еще хочу выводить в QLineEdit (на каждой странице свой) какой-нибудь текст, причем текст зависит от значений QComboBox и QCheckBox, расположенных на странице. Я все написал, но у меня теперь показывает лишь первое значение, которое характерно для дефолтного состояния QComboBox и QCheckBox, а при их изменении значение QLineEdit не изменяется, хотя должно. Подскажите, почему так?
Kagami
Немного подробностей реализации бы не помешало :)
FladeX
cpp
Func09Page::Func09Page(QWidget *parent)
    : QWizardPage(parent)
{
    setTitle(QObject::trUtf8("Заголовок"));
    setSubTitle(QObject::trUtf8("<br>"));
    setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo.png"));
    setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/func09.png"));

    check0901 = new QCheckBox(QObject::trUtf8("Текст"));
    label0901 = new QLabel(QObject::trUtf8("Текст"));
    combo0901 = new QComboBox;

    label0902 = new QLabel(QObject::trUtf8("Текст"));
    combo0902 = new QComboBox;

    check0903 = new QCheckBox(QObject::trUtf8("Текст"));
    label0903 = new QLabel(QObject::trUtf8("Текст"));
    combo0903 = new QComboBox;

    check0904 = new QCheckBox(QObject::trUtf8("Текст"));
    label0904 = new QLabel(QObject::trUtf8("Текст"));
    combo0904 = new QComboBox;

    summa09 = new QLineEdit;
    registerField("summafunc09", summa09);

    combo0901->setMaximumWidth(250);
    combo0902->setMaximumWidth(250);
    combo0903->setMaximumWidth(250);
    combo0904->setMaximumWidth(250);

    combo0901->insertItem(1, "10");
    //...
    combo0901->insertItem(50, "500");

    combo0902->insertItem(1, "1.5");
    //...
    combo0902->insertItem(14, "8.0");

    combo0903->insertItem(1, "10");
    //...
    combo0903->insertItem(50, "500");

    combo0904->insertItem(1, "10");
    //....
    combo0904->insertItem(50, "500");

    double h, s1, s2, s3, summa;
    QString hstring, s1string, s2string, s3string;
    hstring = combo0902->currentText();
    s1string = combo0901->currentText();
    s2string = combo0903->currentText();
    s3string = combo0904->currentText();
    h = hstring.toDouble();
    s1 = s1string.toDouble();
    s2 = s2string.toDouble();
    s3 = s3string.toDouble();
    summa = 0;
    if (check0901->isChecked())
    {
        if ((h>=1.5) && (h<2.0))
        {
            // сверхтонкая стяжка
            summa += 1578.1 * s1;
        }
        else if ((h>=2.0) && (h<3.5))
        {
            // тонкая стяжка
            summa += 1623.9 * s1;
        }
        else if ((h>=3.5) && (h<=8.0))
        {
            // нормальная стяжка
            summa += 2040.5 * s1;
        }
    }
    if (check0903->isChecked())
    {
        summa += 4 * sqrt(s2) * 273.0;
    }
    if (check0904->isChecked())
    {
        summa += 2040.5 * s3;
    }

    QString value = QString::number(summa);
    summa09->setText(value);

    QGridLayout *layout = new QGridLayout;
    layout->addWidget(check0901, 0, 0);
    layout->addWidget(label0901, 1, 0);
    layout->addWidget(combo0901, 2, 0);
    layout->addWidget(label0902, 3, 0);
    layout->addWidget(combo0902, 4, 0);
    layout->addWidget(check0903, 5, 0);
    layout->addWidget(label0903, 6, 0);
    layout->addWidget(combo0903, 7, 0);
    layout->addWidget(check0904, 0, 1);
    layout->addWidget(label0904, 1, 1);
    layout->addWidget(combo0904, 2, 1);
    layout->addWidget(summa09, 3, 1);
    setLayout(layout);
}

h
class Func09Page : public QWizardPage
{
    Q_OBJECT
public:
    Func09Page(QWidget *parent = 0);

private:
    QLabel *label0901;
    QLabel *label0902;
    QLabel *label0903;
    QLabel *label0904;
    QCheckBox *check0901;
    QCheckBox *check0903;
    QCheckBox *check0904;
    QComboBox *combo0901;
    QComboBox *combo0902;
    QComboBox *combo0903;
    QComboBox *combo0904;
    QLineEdit *summa09;
};

А использовать пытаюсь здесь:
cpp
OutroPage::OutroPage(QWidget *parent)
    : QWizardPage(parent)
{
    setTitle(QObject::trUtf8("Заголовок"));
    setSubTitle(QObject::trUtf8("Подзаголовок"));
    setPixmap(QWizard::LogoPixmap, QPixmap(":/images/logo.png"));
    setPixmap(QWizard::WatermarkPixmap, QPixmap(":/images/outro.png"));

    label9901 = new QLabel(QObject::trUtf8("Текст:"));
    line9901 = new QLineEdit;

    QString summa09 = field("summafunc09").toString();
    line9901->setText(summa09);

    QVBoxLayout *layout = new QVBoxLayout;
    layout->addWidget(label9901);
    layout->addWidget(line9901);
    setLayout(layout);
}
Kagami
Ну.. все очень просто. В данном случае надо подключать сигналы изменения чекбоксов и комбобоксов к своему слоту, который уже будет в зависимости от их состояния заполнять поле ввода. В твоей программе такой расчет происходит только один раз - при конструировании страницы.
В свой слот надо выносить вот этот кусок:
Раскрывающийся текст
    double h, s1, s2, s3, summa;
    QString hstring, s1string, s2string, s3string;
    hstring = combo0902->currentText();
    s1string = combo0901->currentText();
    s2string = combo0903->currentText();
    s3string = combo0904->currentText();
    h = hstring.toDouble();
    s1 = s1string.toDouble();
    s2 = s2string.toDouble();
    s3 = s3string.toDouble();
    summa = 0;
    if (check0901->isChecked())
    {
        if ((h>=1.5) && (h<2.0))
        {
            // сверхтонкая стяжка
            summa += 1578.1 * s1;
        }
        else if ((h>=2.0) && (h<3.5))
        {
            // тонкая стяжка
            summa += 1623.9 * s1;
        }
        else if ((h>=3.5) && (h<=8.0))
        {
            // нормальная стяжка
            summa += 2040.5 * s1;
        }
    }
    if (check0903->isChecked())
    {
        summa += 4 * sqrt(s2) * 273.0;
    }
    if (check0904->isChecked())
    {
        summa += 2040.5 * s3;
    }

    QString value = QString::number(summa);
    summa09->setText(value);
Гость
посмотрите пожалуйста мою тему, аналогичная ситуация, не получается выцепить значение с предыдущей страницы, хотя все как в примере делаю
http://www.forum.crossplatform.ru/index.php?showtopic=8974
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.