Здравствуйте.
Листинг 6.7, в определении класса Calculator с помощью #include подключается QWidget, классы QLCDNumber и QPushButton просто объявляются. Но в реализации Calculator.cpp дополнительно подключается модуль QtWidgets, в который входят все вышеизложенные классы. Не логично ли было, подключить QtWidgets в Calculator.h? Или может я не правильно понимаю?
Артем, здравствуйте!
Чем меньше в заголовочном файле будет директив #include тем лучше, так как большое их количество может повлиять на время компиляции программ, потому что компилятору нужно будет просматривать содержимое каждого из этих фалов.
Модуль QtWidgets это целая серия #include файлов каждого класса модуля. Поэтому вместо #include или #include используется предварительное объявление класса QLCDNumber в целях облегчения работы C++ компилятора.
Но все же мы обязаны указать #include и #include так как наш класс Calculator наследуется от класса QWidget, а контейнер QStack используется по значению.
Надеюсь немного прояснил ситуацию.
Макс добрый день.
Нашел багу в работе калькулятора.
Если брать число А + операция + число Б+ операция + число С то к предыдущему результату будет прибавляться строчная сумма всех предыдущих чисел.
т.е. 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(); //так предупреждений нет.
Метод QBoxLayout::addStretch() управляет фактором растяжения между двумя виджетами. Это фактор, а не значение в пикселях (в книге я привожу сравнение с пружиной помещенной между виджетами). То есть задав значение 50 вы просто усилили этот фактор, и до тех пор пока впереди и/или в конце виджетов нет других факторов растяжения, никаких изменений заметно не будет. Попробуйте поставить перед строчкой pcbxLayout->addWidget(pcmdA) еще один фактор растяжения например pcbxLayout->addStretch(50).
Это в зависимости от собственных предпочтений или требований проекта. В Qt можно размещать и создавать виджеты как коде программы, так и визуальном редакторе Qt Designer. Визуальному размещению виджетов посвящена глава 44 “Qt Designer. Быстрая разработка прототипов”
Макс привет.
Нашол еще одну багу в калькуляторе.
Нет проверки на наличие двух(или более) точек в числе, тоесть можна ввести напрмер 23.1…2.
Исправить можно к примеру так:
…..
else if (str == “.”) {
if (!(m_strDisplay.contains(‘.’))) {
m_strDisplay+= str;
m_plcd->display(m_strDisplay);
}
}
Здравствуйте, Макс!
В листингах 6.8 и 6.9 на стр. 126-127 описывается код программы калькулятор. Меня интересует создание кнопок в циклах for. Там происходит вызов метода createButton(const QString &str), и в реализации этого метода создается указатель на объект QPushButton. Далее сигнал clicked() от этого объекта-кнопки (указатель pcmd) соединяется со слотом slotButtonClicked(). Не могу понять как идентифицировать каждую кнопку? Т.е., например, обратиться к какой-либо кнопке по указателю pcmd, если указатель на эти кнопки один и тот же? И как метод connect() понимает от какой кнопки калькулятора пришел сигнал? Немного путанно, но надеюсь Вы поняли.
Метод createButton(const QString&) при каждом вызове создает новый объект QPushButton, и возвращает указатель на этот объект. Сигналы clicked(), созданного объекта кнопки, в этом методе, соединяются со слотом slotButtonClicked(). Идентификация происходит в слоте slotButtonClicked(), вызовом метода sender(). Этот метод возвращает указатель на кнопку, из-за которой был вызван этот слот (т.е. на ту кнопку которая была нажата и выслала сигнал clicked()). Надеюсь немного прояснил.
В коде калькулятора есть три проблемы:
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 = “”;
}
}
}
// ……….
Выше в комментариях были приведены варианты решения двух проблем, нашел еще одну проблему (все три проблемы решил самостоятельно, решения вышли такими же как и у читателей ранее). Описал все три решения, чтобы систематизировать.
Добрый день. Мне чтобы работала приходится добавлять библиотеки QLCDNumber и QtWidgets, если просто объявить классы QLCDNumber и QPushButton компилятор выдает ошибку. Подскажите как исправить
Здравствуйте. Как вы определяете когда нужно создать обьект динамически, а когда статически? Вот на примере листинга 6.12:
QSplitter spl(Qt::Vertical); – тут статически
QTextEdit* ptx1 = new QTextEdit; – а тут уже динамически.
Но если открыть главу 2, стр. 52, там указано, что “Все обьекты должны создаваться в памяти динамически” (исключение – не имеющие предков). Но spl тут не имеет предков и все равно он создан статически.
Виталий, всем виджетам которые помещаются в лайаут, автоматически присваивается виджет предка. Статически можно создавать виджеты в основной программе main() без предков.
На странице 125 в листинге “Calculator.h” есть опечатка: указан include, но компилируется только с
Здравствуйте Михаил,
пожалуйста продолжите свою мысль, Вы имеете ввиду листинг 6.7? Там я опечатки не нашел.
Здравствуйте.
Листинг 6.7, в определении класса Calculator с помощью #include подключается QWidget, классы QLCDNumber и QPushButton просто объявляются. Но в реализации Calculator.cpp дополнительно подключается модуль QtWidgets, в который входят все вышеизложенные классы. Не логично ли было, подключить QtWidgets в Calculator.h? Или может я не правильно понимаю?
Артем, здравствуйте! или #include используется предварительное объявление класса QLCDNumber в целях облегчения работы C++ компилятора. и #include так как наш класс Calculator наследуется от класса QWidget, а контейнер QStack используется по значению.
Чем меньше в заголовочном файле будет директив #include тем лучше, так как большое их количество может повлиять на время компиляции программ, потому что компилятору нужно будет просматривать содержимое каждого из этих фалов.
Модуль QtWidgets это целая серия #include файлов каждого класса модуля. Поэтому вместо #include
Но все же мы обязаны указать #include
Надеюсь немного прояснил ситуацию.
Макс добрый день.
Нашел багу в работе калькулятора.
Если брать число А + операция + число Б+ операция + число С то к предыдущему результату будет прибавляться строчная сумма всех предыдущих чисел.
т.е. 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(); //так предупреждений нет.
Егор, большое Вам спасибо, за замечания и исправления обязательно учту их в следующем издании.
Листинг 6.2. Меняю значение параметра функции addStretch, например на 50, но при запуске ничего не меняется. Почему так?
Метод QBoxLayout::addStretch() управляет фактором растяжения между двумя виджетами. Это фактор, а не значение в пикселях (в книге я привожу сравнение с пружиной помещенной между виджетами). То есть задав значение 50 вы просто усилили этот фактор, и до тех пор пока впереди и/или в конце виджетов нет других факторов растяжения, никаких изменений заметно не будет. Попробуйте поставить перед строчкой pcbxLayout->addWidget(pcmdA) еще один фактор растяжения например pcbxLayout->addStretch(50).
Правильно ли я понимаю, что в Qt размещение элементов на форме чаще делают кодом с использованием менеджеров компоновки, а не в визуальном режиме?
Это в зависимости от собственных предпочтений или требований проекта. В Qt можно размещать и создавать виджеты как коде программы, так и визуальном редакторе Qt Designer. Визуальному размещению виджетов посвящена глава 44 “Qt Designer. Быстрая разработка прототипов”
Макс привет.
Нашол еще одну багу в калькуляторе.
Нет проверки на наличие двух(или более) точек в числе, тоесть можна ввести напрмер 23.1…2.
Исправить можно к примеру так:
…..
else if (str == “.”) {
if (!(m_strDisplay.contains(‘.’))) {
m_strDisplay+= str;
m_plcd->display(m_strDisplay);
}
}
Большое спасибо, постараюсь учесть в следующей версии калькулятора.
На стр. 124 первая строка снизу: “…задействованы классы стека QValueStack…”. Должно быть QStack, я думаю.
Спасибо Эльдар, да действительно “QValueStack” это “гость” из прошлых изданий, должно быть QStack.
Здравствуйте, Макс!
В листингах 6.8 и 6.9 на стр. 126-127 описывается код программы калькулятор. Меня интересует создание кнопок в циклах for. Там происходит вызов метода createButton(const QString &str), и в реализации этого метода создается указатель на объект QPushButton. Далее сигнал clicked() от этого объекта-кнопки (указатель pcmd) соединяется со слотом slotButtonClicked(). Не могу понять как идентифицировать каждую кнопку? Т.е., например, обратиться к какой-либо кнопке по указателю pcmd, если указатель на эти кнопки один и тот же? И как метод connect() понимает от какой кнопки калькулятора пришел сигнал? Немного путанно, но надеюсь Вы поняли.
Метод createButton(const QString&) при каждом вызове создает новый объект QPushButton, и возвращает указатель на этот объект. Сигналы clicked(), созданного объекта кнопки, в этом методе, соединяются со слотом slotButtonClicked(). Идентификация происходит в слоте slotButtonClicked(), вызовом метода sender(). Этот метод возвращает указатель на кнопку, из-за которой был вызван этот слот (т.е. на ту кнопку которая была нажата и выслала сигнал clicked()). Надеюсь немного прояснил.
В коде калькулятора есть три проблемы:
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 = “”;
}
}
}
// ……….
Выше в комментариях были приведены варианты решения двух проблем, нашел еще одну проблему (все три проблемы решил самостоятельно, решения вышли такими же как и у читателей ранее). Описал все три решения, чтобы систематизировать.
Ваши решения могут пригодится и оказаться полезными! Спасибо Вячеслав!
На стр. 130 небольшая опечатка: “В листинге 6.12 в конструктор класса QSlitter…”. Правильно QSplitter.
Это действительно опечатка, правильно будет QSplitter. Спасибо!
Добрый день. Мне чтобы работала приходится добавлять библиотеки QLCDNumber и QtWidgets, если просто объявить классы QLCDNumber и QPushButton компилятор выдает ошибку. Подскажите как исправить
Здравствуйте, Алексей!
скорее всего Вы забыли указать модуль QtWidgets в pro-файле.
Попробуйте добавить в pro-файл строчку QT += widgets
Здравствуйте. Как вы определяете когда нужно создать обьект динамически, а когда статически? Вот на примере листинга 6.12:
QSplitter spl(Qt::Vertical); – тут статически
QTextEdit* ptx1 = new QTextEdit; – а тут уже динамически.
Но если открыть главу 2, стр. 52, там указано, что “Все обьекты должны создаваться в памяти динамически” (исключение – не имеющие предков). Но spl тут не имеет предков и все равно он создан статически.
Виталий, всем виджетам которые помещаются в лайаут, автоматически присваивается виджет предка. Статически можно создавать виджеты в основной программе main() без предков.