Здравствуйте.
Листинг 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() без предков.
Здравствуйте!
Опечатка в листинге 6.4.
Вместо phbxLayout->setContensMargins(5, 5, 5, 5); следует читать phbxLayout->setContentsMargins(5, 5, 5, 5);
Пропущена буква t в имени функции.
This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish.AcceptRead More
Privacy & Cookies Policy
Privacy Overview
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
На странице 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() без предков.
Здравствуйте!
Опечатка в листинге 6.4.
Вместо phbxLayout->setContensMargins(5, 5, 5, 5); следует читать phbxLayout->setContentsMargins(5, 5, 5, 5);
Пропущена буква t в имени функции.