Глава 6 – Управление автоматическим размещением элементов

Управление автоматическим размещением элементов

Приобрести книгу можно на сайте ozon.ru и в электронном виде на Google Play:
Приобрести книгу о Qt и C++ на Ozon.ru Купить книгу о Qt и C++ на Goole Play

20 thoughts on “Глава 6 – Управление автоматическим размещением элементов

    1. Здравствуйте Михаил,
      пожалуйста продолжите свою мысль, Вы имеете ввиду листинг 6.7? Там я опечатки не нашел.

  1. Здравствуйте.
    Листинг 6.7, в определении класса Calculator с помощью #include подключается QWidget, классы QLCDNumber и QPushButton просто объявляются. Но в реализации Calculator.cpp дополнительно подключается модуль QtWidgets, в который входят все вышеизложенные классы. Не логично ли было, подключить QtWidgets в Calculator.h? Или может я не правильно понимаю?

    1. Артем, здравствуйте!
      Чем меньше в заголовочном файле будет директив #include тем лучше, так как большое их количество может повлиять на время компиляции программ, потому что компилятору нужно будет просматривать содержимое каждого из этих фалов.
      Модуль QtWidgets это целая серия #include файлов каждого класса модуля. Поэтому вместо #include или #include используется предварительное объявление класса QLCDNumber в целях облегчения работы C++ компилятора.
      Но все же мы обязаны указать #include и #include так как наш класс Calculator наследуется от класса QWidget, а контейнер QStack используется по значению.
      Надеюсь немного прояснил ситуацию.

  2. Макс добрый день.
    Нашел багу в работе калькулятора.
    Если брать число А + операция + число Б+ операция + число С то к предыдущему результату будет прибавляться строчная сумма всех предыдущих чисел.
    т.е. 5+6+9=80
    потому что 5+6+ (выводит 11) но далее нажимая 9 мы видим 69, нажимаем + или = получаем результат 80, если нажимали + и получив 80 нажмем на 3 то прибавляться к 80 будет 693, и так далее.
    т.е после нажатия кнопки операция, необходимо обнулять m_strDisplay.
    Вот так вот выглядит исправленный участок реализации слота slotButtonClicked:
    if (m_stk.count() >= 2)
    {
    m_stk.push(QString().setNum(m_plcd->value()));
    calculate();
    m_stk.clear();
    m_stk.push(QString().setNum(m_plcd->value()));
    if (str != “=”) m_stk.push(str);
    m_strDisplay = “”; //добавлено обнуление что бы исключить не корректное поведение
    }

    Так же следующего вида присваивание выдает предупреждение:
    qreal fOperand1 = m_stk.pop().toFloat(); //выдает предупреждения т.к. qreal является double
    исправлено так:
    qreal fOperand1 = m_stk.pop().toDouble(); //так предупреждений нет.

  3. Листинг 6.2. Меняю значение параметра функции addStretch, например на 50, но при запуске ничего не меняется. Почему так?

    1. Метод QBoxLayout::addStretch() управляет фактором растяжения между двумя виджетами. Это фактор, а не значение в пикселях (в книге я привожу сравнение с пружиной помещенной между виджетами). То есть задав значение 50 вы просто усилили этот фактор, и до тех пор пока впереди и/или в конце виджетов нет других факторов растяжения, никаких изменений заметно не будет. Попробуйте поставить перед строчкой pcbxLayout->addWidget(pcmdA) еще один фактор растяжения например pcbxLayout->addStretch(50).

  4. Правильно ли я понимаю, что в Qt размещение элементов на форме чаще делают кодом с использованием менеджеров компоновки, а не в визуальном режиме?

    1. Это в зависимости от собственных предпочтений или требований проекта. В Qt можно размещать и создавать виджеты как коде программы, так и визуальном редакторе Qt Designer. Визуальному размещению виджетов посвящена глава 44 “Qt Designer. Быстрая разработка прототипов”

  5. Макс привет.
    Нашол еще одну багу в калькуляторе.
    Нет проверки на наличие двух(или более) точек в числе, тоесть можна ввести напрмер 23.1…2.
    Исправить можно к примеру так:
    …..
    else if (str == “.”) {
    if (!(m_strDisplay.contains(‘.’))) {
    m_strDisplay+= str;
    m_plcd->display(m_strDisplay);
    }
    }

  6. Здравствуйте, Макс!
    В листингах 6.8 и 6.9 на стр. 126-127 описывается код программы калькулятор. Меня интересует создание кнопок в циклах for. Там происходит вызов метода createButton(const QString &str), и в реализации этого метода создается указатель на объект QPushButton. Далее сигнал clicked() от этого объекта-кнопки (указатель pcmd) соединяется со слотом slotButtonClicked(). Не могу понять как идентифицировать каждую кнопку? Т.е., например, обратиться к какой-либо кнопке по указателю pcmd, если указатель на эти кнопки один и тот же? И как метод connect() понимает от какой кнопки калькулятора пришел сигнал? Немного путанно, но надеюсь Вы поняли.

    1. Метод createButton(const QString&) при каждом вызове создает новый объект QPushButton, и возвращает указатель на этот объект. Сигналы clicked(), созданного объекта кнопки, в этом методе, соединяются со слотом slotButtonClicked(). Идентификация происходит в слоте slotButtonClicked(), вызовом метода sender(). Этот метод возвращает указатель на кнопку, из-за которой был вызван этот слот (т.е. на ту кнопку которая была нажата и выслала сигнал clicked()). Надеюсь немного прояснил.

  7. В коде калькулятора есть три проблемы:
    1) При нажатии на кнопку с символом десятичного разделителя “.” он всегда вводится и может при вводе получится число вида “2.563..4”;
    2) При нажатии подряд кнопки с символом “=” обнуляется выведенный в поле m_plcd калькулятора результат, но в стек введенное число заносится;
    3) При нажатии после вычисления какого-либо выражения знака какой-либо операции и ввода цифр новая цифра дописывается к предыдущей и выводится на дисплей калькулятора, т.е. при вычислении подряд нескольких выражений без нажатия знака “=” программа ведет себя некорректно. Вот способы решения данных проблем (может кому-нибудь пригодится):
    // ……….
    if (str == “CE”) {
    // код из книги
    // ……….
    }
    if (str.contains(QRegExp(“[0-9]”))) {
    // код из книги
    // ……….
    }
    else if (str == “.”) {
    // 1) Добавляем условие, для решения проблемы с “.”
    if(!m_strDisplay.contains(“.”)) {
    m_strDisplay += str;
    m_plcd->display(m_strDisplay);
    }
    }
    else {
    if (m_stk.count() >= 2) {
    m_stk.push(QString().setNum(m_plcd->value()));
    calculate();
    m_stk.clear();
    m_stk.push(QString().setNum(m_plcd->value()));
    if (str != “=”) {
    m_stk.push(str);
    m_strDisplay = “”; // 3) “Обнуляем” переменную m_strDisplay, для решения проблемы операций подряд
    }
    }
    else {
    // 2) Модифицируем код для проблемы с “=”
    m_stk.clear();
    m_stk.push(QString().setNum(m_plcd->value()));
    if(str != “=”) {
    m_stk.push(str);
    m_strDisplay = “”;
    }
    }
    }
    // ……….

    Выше в комментариях были приведены варианты решения двух проблем, нашел еще одну проблему (все три проблемы решил самостоятельно, решения вышли такими же как и у читателей ранее). Описал все три решения, чтобы систематизировать.

  8. На стр. 130 небольшая опечатка: “В листинге 6.12 в конструктор класса QSlitter…”. Правильно QSplitter.

Добавить комментарий для Mikhail Отменить ответ