Когда мне в школе мне задали сделать итоговый проект для допуска к ОГЭ. Я долго думал над темой проекта, и решил совместить две вещи в которых я хорошо разбираюсь, Квадратные уравнения и мой любимый язык программирования Python.
На этапе идеи я сразу понял с помощью чего именно я сделаю свой проект. Изначально у меня получилось разработать консольное приложение, состоящее из бесконечного цикла цикла и простого алгоритма который спрашивает тип уравнения: Полное квадратное/неполное квадратное, и после выбора мы могли вводить a, b и c/a и b.
Эту версию проекта я "накидал" за один вечер, когда я показал результат учителю, он порекомендовал мне сделать графический интерфейс, я моментально вспомнил Python библиотеку Tkinter для создания графического интерфейса.
Тут уже пришлось покумекать как именно это сделать, ведь на практике я еще на тот момент не сталкивался с этим фреймворком. В ходе поиска документации по данному фреймворку я столкнулся с тем что все материала были содержали слишком много "воды". На тот момент нейросети были чем то новым и неизведанным, как раз так совпало что в том промежутке времени появилась первая публичная модель ChatGPT, с помощью которой я нашел нужный материал, сделал техническую документацию и даже подредактировал саму программу.
Приступаем к работе
Для работы с графическим интерфейсом нам понадобится сама библиотека tkinter, а также отдельный модуль из неё что бы выводить результат решения, messagebox.
import tkinter as tk # с помощью as tk мы присваиваем псевдоним tk, для сокращения from tkinter import messagebox # из tkinter достаем метод, который нам позволит выводить результаты в окошке import math # библиотека которая нам позволит делать математические вычисления
Далее нам нужно создать функцию которая будет принимать 3 числа, в нашем случает это a, b, c.
Назовём функцию solve_quadratic_equation(): и внутри неё мы осуществим ввод данных. В Tkinter все поля ввода(Entry) хранят информацию в виде строк. Что бы получить то, что ввёл пользователь, используя метод .get():
def solve_quadratic_equation(): # ввод даннных(квадратные уравнения) a = float(entry_a.get()) b = float(entry_b.get()) c = float(entry_c.get()) discriminant = b**2 - 4*a*c # формула дискриминанта
entry_a.get()- берёт текст из поля entry_a и возвращает его в виде строки.
Например: пользователь ввёл2.5, тоentry_a.get()вернёт"2.5".float()- преобразует полученную строку в число с плавающей запятой (типfloat)Результат сохраняется в переменную
a,bилиc, с которой мы уже может производить математические расчёты.
Далее нам нужно проверить полученный из формулы discriminant = b**2 - 4ac дискриминант на:
Больше нуля
Равен нулю
Меньше нуля
Если переменная discriminant больше нуля, то мы производим расчёты для двух действительных корней:
# если дискриминант больше нуля if discriminant > 0: x1 = (-b + math.sqrt(discriminant)) / (2*a) x2 = (-b - math.sqrt(discriminant)) / (2*a) result = f"Корни уравнения: x1 = {x1}, x2 = {x2}"
Если вышеупомянутая переменная равна нулю, то мы производим расчёты для одного действительного корня:
# если дискриминант равен нулю elif discriminant == 0: x = -b / (2*a) result = f"Уравнение имеет единственный корень: x = {x}"
И так как других исходов кроме как дискриминант меньше нуля, быть не может, мы используем оператор сравнения else:
# если дискриминант меньше нуля else: result = "Уравнение не имеет действительных корней"
Теперь с помощью модуля messagebox, который мы импортировали в самом начале, выводим результат решения полного квадратного уравнения.
# вывод результата messagebox.showinfo("Результат", result)
Далее нам нужно реализовать функцию для решения неполного квадратного уравнения. Создадим и назовем функциюsolve_incomplete_quadratic_equation():. И как в прошлой функции мы осуществим ввод уже двух чисел, a и b, тем же способом, сделаем расчеты корня уравнения и выведем их во всплывающем окне.
# создание функции для не полного квадратного уравнения def solve_incomplete_quadratic_equation(): # ввод данных a_2 = float(entry_incomplete_a.get()) b_2 = float(entry_incomplete_b.get()) x = -(b / a) result = f"Корень уравнения: x = {x}" # вывод результата messagebox.showinfo("Результат", result)
И так, мы с вами закончили прописывать логику программы, сейчас нам нужно создать само окно, и внутри него сделать поля ввода a, b, c / a, b
Для начала создадим окно:
window = tk.Tk()
Дадим ему название:
window.title("Калькулятор квадратных уравнений")
А также зададим ему геометрию, ширину и высоту окна, у нас оно будет 500 на 500:
window.geometry("500x500")
Далее нам нужно создать виджеты:
Надпись "Квадратные уравнения"
Поля ввода для
a,bиcКнопка "Решить"
label_title = tk.Label(window, text="Квадратные уравнения") label_a = tk.Label(window, text="Введите a:") entry_a = tk.Entry(window) label_b = tk.Label(window, text="Введите b:") entry_b = tk.Entry(window) label_c = tk.Label(window, text="Введите c:") entry_c = tk.Entry(window)
label_title = tk.Label(window, text="Квадратные уравнения")
Эта строка создаёт надпись на экране.
tk.Label(...)- отвечает за создание текста в окне.window- указывает, в каком окне будет находиться эта надпись.text="Квадратные уравнения"- текст, который мы хотим показать пользователю.label_title- имя переменной, в который мы сохраняем созданную метку, что бы потом её можно было разместить на экране с помощью.pack()
Сейчас нам надо вспомнить момент с вводом данных. Там к a, b и c мы присваивали entry_a, entry_b, entry_c. Сейчас нам нужно введённые данные сохранить в entry_a, entry_b, entry_c после нажатия на кнопку "Решить".
Как происходит получение из поля ввода или же присваивание?
entry_a.get()спрашивает у меняentry_a: "Что сейчас находится внутри тебя?"Метод
.get()возвращает текст, который ввёл пользователь. Например:"-5".float(...)превращает эту строку в настоящее число (типfloat)."-5"в5.0a = ...сохраняет это число в переменнуюa, что бы потом использовать в формуле дискриминанта.
Далее нам надо создать кнопку "Решить", по нажатию которой у нас вызовется функция solve_quadratic_equation() которая получит введённые пользователем числа и выведет окошко с результатом.
button_solve_quadratic = tk.Button(window, text="Решить", command=solve_quadratic_equation)
tk.Button(...)- отвечает за создание кнопки в окне.window- указывает, в каком окне будет находиться эта надпись.text="Решить"- текст, который мы хотим показать пользователю.command=solve_quadratic_equation- что происходит при нажатии на кнопку
Сейчас нам остаётся отрисовать все виджеты которые мы создали. С помощью метода .pack() мы сможем разместить созданные виджеты внутри окна.
label_title.pack() label_a.pack() entry_a.pack() label_b.pack() entry_b.pack() label_c.pack() entry_c.pack() button_solve_quadratic.pack()
Продублируем все действия для неполных квадратных уравнений
# Создание виджетов для квадратных неполных уравнений label_incomplete_title = tk.Label(window, text="Квадратные неполные уравнения") label_incomplete_a = tk.Label(window, text="Введите a:") entry_incomplete_a = tk.Entry(window) label_incomplete_b = tk.Label(window, text="Введите b:") entry_incomplete_b = tk.Entry(window) button_solve_incomplete = tk.Button(window, text="Решить", command=solve_incomplete_quadratic_equation) label_incomplete_title.pack() label_incomplete_a.pack() entry_incomplete_a.pack() label_incomplete_b.pack() entry_incomplete_b.pack() button_solve_incomplete.pack()
И что бы у нас всё появилось нам нужна эта строчка:
window.mainloop()
Она необходима для работы любого приложения на Tkinter.
Что происходит?
mainloop() запускает бесконечный цикл приложения.
Итоги
Мы сделали простое приложение которое считает корни полного/неполного квадратного уравнения и всё это в обёртке Tkinter.



Полный код приложения
import tkinter as tk from tkinter import messagebox import math # создание функции для квадратного уравнения def solve_quadratic_equation(): # ввод даннных(квадратные уравнения) a = float(entry_a.get()) b = float(entry_b.get()) c = float(entry_c.get()) discriminant = b**2 - 4*a*c # формула дискриминанта # если дискриминант больше нуля if discriminant > 0: x1 = (-b + math.sqrt(discriminant)) / (2*a) x2 = (-b - math.sqrt(discriminant)) / (2*a) result = f"Корни уравнения: x1 = {x1}, x2 = {x2}" # если дискриминант равен нулю elif discriminant == 0: x = -b / (2*a) result = f"Уравнение имеет единственный корень: x = {x}" # если дискриминант меньше нуля else: result = "Уравнение не имеет действительных корней" # вывод результата messagebox.showinfo("Результат", result) # создание функции для не полного квадратного уравнения def solve_incomplete_quadratic_equation(): # ввод данных a_2 = float(entry_incomplete_a.get()) b_2 = float(entry_incomplete_b.get()) x = -(b_2 / a_2) result = f"Корень уравнения: x = {x}" # вывод результата messagebox.showinfo("Результат", result) # Создание главного окна window = tk.Tk() window.title("Калькулятор квадратных уравнений") window.geometry("500x500") # Создание виджетов label_title = tk.Label(window, text="Квадратные уравнения") label_a = tk.Label(window, text="Введите a:") entry_a = tk.Entry(window) label_b = tk.Label(window, text="Введите b:") entry_b = tk.Entry(window) label_c = tk.Label(window, text="Введите c:") entry_c = tk.Entry(window) button_solve_quadratic = tk.Button(window, text="Решить", command=solve_quadratic_equation) label_title.pack() label_a.pack() entry_a.pack() label_b.pack() entry_b.pack() label_c.pack() entry_c.pack() button_solve_quadratic.pack() # Создание виджетов для квадратных неполных уравнений label_incomplete_title = tk.Label(window, text="Квадратные неполные уравнения") label_incomplete_a = tk.Label(window, text="Введите a:") entry_incomplete_a = tk.Entry(window) label_incomplete_b = tk.Label(window, text="Введите b:") entry_incomplete_b = tk.Entry(window) button_solve_incomplete = tk.Button(window, text="Решить", command=solve_incomplete_quadratic_equation) label_incomplete_title.pack() label_incomplete_a.pack() entry_incomplete_a.pack() label_incomplete_b.pack() entry_incomplete_b.pack() button_solve_incomplete.pack() # Запуск главного цикла окна window.mainloop()
Комментарии (20)

HemulGM
04.05.2026 17:27Хорошо, вот на Delphi:
procedure TFormMain.ButtonCalcClick(Sender: TObject); begin var A := EditA.Text.ToDouble; var B := EditB.Text.ToDouble; var C := EditC.Text.ToDouble; var Discriminant := Power(B, 2) - 4 * A * C; if Discriminant > 0 then begin var X1 := (-B + Sqrt(Discriminant)) / (2 * A); var X2 := (-B - Sqrt(Discriminant)) / (2 * A); MemoResult.Text := Format('x1 = %f'#13#10'x2 = %f', [X1, X2]); end else MemoResult.Text := 'Уравнение не имеет действительных корней'; end; procedure TFormMain.ButtonCalcIncompClick(Sender: TObject); begin var A := EditIncompA.Text.ToDouble; var B := EditIncompB.Text.ToDouble; var X := -(B / A); MemoResultIncomp.Text := Format('x = %f', [X]); end;
Это весь код, что я написал. На Андроид, Мак, Линукс и Иос тоже запустится

red_dragon
04.05.2026 17:27А ты тоже школьник? Dephi с торрентов? На всех, тобой перечисленных OS, тестил? Где у тебя файл с описанием GUI? Сколько "весит" бинарник этого твоего "на Deplhi"?

HemulGM
04.05.2026 17:27Не школьник.
Delphi имеет бесплатную Community версию. У меня вообще платная.
На всех указанных OS это будет работать.
Собрать могу хоть сейчас на все платформы на одной машине.
Файл с описанием GUI трогать не надо, это всегда автогенерация. Его пишет сама среда разработки. Ты визуально конструируешь UI.
Ехе весит около 15мб. Не имея никаких зависимостей. На других платформах - также (но Линукс требует gtk).

red_dragon
04.05.2026 17:27Упрощу вопрос. Зачем ты привёл своё решение на Delphi? Что хотел показать этим?

bear11
04.05.2026 17:27Интересно, как такой “графический hello world” сейчас, на текущее время
можно реализовать на разных языках, что получается,
какие возможности кроссплатформенности
как выглядит исходный текст
насколько быстро это можно реализовать
какие другие проблемы возникают То есть тема вполне для обсуждения на habr.

K0Jlya9
04.05.2026 17:2715мб хелоуворлд бгг. 1кб это должно весить, и работать на любой платформе начиная как минимум с винХП.

<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Калькулятор квадратных уравнений</title> <style> * { box-sizing: border-box; font-family: "Segoe UI", sans-serif; } body { margin: 0; min-height: 100vh; display: flex; justify-content: center; align-items: center; background: #1e1e1e; color: white; } .window { width: 900px; background: #252525; border-radius: 12px; padding: 18px; box-shadow: 0 0 25px rgba(0,0,0,0.4); } .title { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; font-size: 20px; font-weight: 600; } .logo { width: 28px; height: 28px; border-radius: 50%; background: #b32025; display: flex; align-items: center; justify-content: center; font-weight: bold; } .content { display: flex; gap: 20px; } .card { flex: 1; background: #2c2c2c; border-radius: 12px; padding: 18px; } .card h2 { margin-top: 0; margin-bottom: 18px; font-size: 22px; font-weight: 500; } .input-group { position: relative; margin-bottom: 14px; } .input-group input { width: 100%; padding: 14px 45px 14px 14px; border: 1px solid #555; border-radius: 6px; background: #3a3a3a; color: white; font-size: 18px; outline: none; } .input-group span { position: absolute; right: 14px; top: 50%; transform: translateY(-50%); color: #bdbdbd; font-size: 18px; } button { width: 100%; padding: 14px; border: none; border-radius: 6px; background: #59c6f4; color: black; font-size: 18px; cursor: pointer; transition: 0.2s; margin-bottom: 16px; } button:hover { background: #71d3fb; } .result { min-height: 90px; background: #3a3a3a; border: 1px solid #555; border-radius: 6px; padding: 14px; font-size: 20px; line-height: 1.6; white-space: pre-line; } </style> </head> <body> <div class="window"> <div class="title"> <div class="logo">D</div> Калькулятор квадратных уравнений </div> <div class="content"> <!-- Полное квадратное --> <div class="card"> <h2>Квадратные уравнения</h2> <div class="input-group"> <input type="number" id="a" value="-4"> <span>A</span> </div> <div class="input-group"> <input type="number" id="b" value="5"> <span>B</span> </div> <div class="input-group"> <input type="number" id="c" value="6"> <span>C</span> </div> <button onclick="solveQuadratic()">Решить</button> <div class="result" id="quadraticResult"></div> </div> <!-- Неполное --> <div class="card"> <h2>Квадратные неполные уравнения</h2> <div class="input-group"> <input type="number" id="na" value="-1"> <span>A</span> </div> <div class="input-group"> <input type="number" id="nb" value="5"> <span>B</span> </div> <button onclick="solveSimple()">Решить</button> <div class="result" id="simpleResult"></div> </div> </div> </div> <script> function solveQuadratic() { let a = parseFloat(document.getElementById('a').value); let b = parseFloat(document.getElementById('b').value); let c = parseFloat(document.getElementById('c').value); let d = b * b - 4 * a * c; let result = ''; if (d < 0) { result = 'Нет действительных корней'; } else if (d === 0) { let x = (-b / (2 * a)).toFixed(2); result = `x = ${x}`; } else { let x1 = ((-b - Math.sqrt(d)) / (2 * a)).toFixed(2); let x2 = ((-b + Math.sqrt(d)) / (2 * a)).toFixed(2); result = `x1 = ${x1}\nx2 = ${x2}`; } document.getElementById('quadraticResult').innerText = result; } function solveSimple() { let a = parseFloat(document.getElementById('na').value); let b = parseFloat(document.getElementById('nb').value); if (a === 0) { document.getElementById('simpleResult').innerText = 'A не может быть 0'; return; } let x = Math.sqrt(-b / a); if (isNaN(x)) { document.getElementById('simpleResult').innerText = 'Нет решения'; } else { document.getElementById('simpleResult').innerText = `x = ${x.toFixed(2)}`; } } solveQuadratic(); solveSimple(); </script> </body> </html>
HemulGM
04.05.2026 17:27У тебя это просто текст и он не запустится нигде без специальной программы. Вообще нигде и никогда.

HemulGM
04.05.2026 17:27Другие ОС

Android 
Linux (Ubuntu) Среда. Дизайнер (код окна трогать не надо)


red_dragon
04.05.2026 17:27Я знаю, что такое Delphi. C четвёртой по седьмую версию пользовался довольно активно и даже деньги зарабатывал этим. Но раз уж ты осилил скриншоты, дай ссылку на .apk и бинарник для Linux. Сильно интересно стало, насколько это действительно кросплатформенно.

HemulGM
04.05.2026 17:27Насколько "кроссплатформенно" можешь посмотреть здесь:
https://github.com/HemulGM/ChatGPT
Это куда более крупный проект. С доступными бинарниками

Metotron0
04.05.2026 17:27Вообще не уровень хабра. Да и цель статьи не понятна. Если хотели научить аудиторию использовать tkinter, то зачем описывать, как в питоне импортируются пакеты, и что означает else? Если хотели обучить синтаксису питона, то этого явно мало, да и пример для обучения выбран не самый показательный.

morginalium8
04.05.2026 17:27автору 15-16 лет. и он уже имеет грамотную речь, умение описывать свои идеи, доводить их до реализации и описывать результат.
я технические знания придут

morginalium8
04.05.2026 17:27Можешь глянуть, я тут что-то похожее делал - только там вообще все решить можно

eulampius
04.05.2026 17:27А что за дичь с "неполными" квадратными уравнениями? Это же просто частные случаи, когда один или несколько коэффициентов равны нулю. Вот только, если a == 0,то уравнение перестаёт быть квадратным, а если a == b == 0, то оно перестаёт быть уравнением и становится равенством, только в одном случае истинным, а в остальных ложным. И все это можно запрограммировать без лишних полей ввода. Просто не вводим коэффициенты, если их нет. Корни, кстати, тоже можно представить не в виде одной-двух переменных, а иначе, более универсально.

D7ILeucoH
04.05.2026 17:27Я понял. Теперь дети пишут свои потуги в виде статей на Хабре. Вот это уровень, вот это мы приехали.
То моё беспокойство что я не написал ни одного поста - было нивелировано тем, что смысл постов просто обесценился.
Наличие научных публикаций в дипломе, на которое так пытались дрочить научруки, и чего я не стал делать - очевидно что полная хуйня. Круто что не вляпался в это ЧСВшное дерьмо... Просто делаешь что хочешь, для себя, и как сам это видишь. Всё. Объяснять кому-то очевидные с одной стороны, и агностические с другой стороны темы - бред. Главное - результат. А он есть.
Блин, смысл статьи то в чём? Я однажды смог ускорить обучение нейронки в 10к раз, что шло вразрез с подобием доки (на тот момент их не было), и просто рассказал об этом ребятам в команде, и всё. Похоже в этом было бы гораздо больше смысла, чем в этой статье.
Да и в целом алгоритм туповатый. Как и UX. Суть программы это упростить что-то, а не усложнить, задавая очевидные и ненужные вопросы. Задача - либо ввод уравнения целиком (с парсингом), либо коэффициентов, и всё. Ввод коэффициента A,B,C - тоже звучит тупо, потому что не понятно к какой степени они относятся. Эти цифры в принципе не были нужны. Очевидно что нужно было вместо них писать неизвестную с показателем. А сейчас программа зачем? Половина это копипаста, перегруженный интерфейс, так ещё и непонятный.

K0Jlya9
04.05.2026 17:27В соседней "статье" вполне себе великовозрастный чувак просто спросил у роботов какая книга-игра-фильм им нравится в каком то аспекте и тупо заполнил всю статью копипастой ответов. Хорошо что теперь на хабре есть кнопка для игнора авторов, плохо что нельзя игнорить сразу целые сообщества паразитов.


ArtyomOchkin
04.05.2026 17:27Неплохо для первого проекта. Я так баловался с реализацией алгоритма дисперсии, это поинтереснее будет.
Можете ознакомиться с ttk.button() или, лучше, с более совершенными формами tkinter вроде customtkinter. Тогда можно сделать близкое к WinUI стилю, более современно выглядящее приложение, а не просто WinForms, примерно такое, как товарищ выше в комментах прислал. Это возможно и c Python.
Если интересно, потом покажу свой старый эксперимент "DisperiaPro", на котором я разбирался с компиляцией бинарников на Python и реализовал подсчёт среднеквадратичного отклонения, дисперсии и др.

ysrgsyn
04.05.2026 17:27Ну чего вы негативите так народ?
Ну да, тема не хабровская совсем, просто школьник написал код и показал это миру.
В целом, он не виноват что его пост одобрили и опубликовали)
Раз есть что есть, лучше поддержим его как старшие коллегия))
А негативить идём под посты типа "я X и за 30 секунд сделал свое приложение через ИИ, так что эти ваши прахрамисты никому не нужны"

Metotron0
04.05.2026 17:27https://habr.com/ru/articles/1031410/
Дык, это, там +51А-а, там шутка юмора. Не выкупил при беглом осмотре.
bear11
а теперь перепишите это на фреймворке Kivy - и программа у вас превратится в жар птицу (по красоте) и ее даже можно будет без особых переделок запускать на Android.