https://flask.palletsprojects.com/en/2.2.x/installation/
Create an environment
C:\flask_dev>py -3 -m venv venv
Activate the environment
C:\flask_dev>venv\Scripts\activate
Install Flask
venv C:\flask_dev>pip install Flask
#C:\flask_dev\flasktoexe\app.py from flask import Flask,render_template import webview app = Flask(__name__, static_folder='./static', template_folder='./templates') @app.route('/') def home(): return render_template("index.html",name='cairocoders Home page') @app.route('/page2') def page2(): return render_template("page2.html",name='cairocoders page 2') webview.create_window('Flask to exe', app) if __name__ == '__main__': #app.run(debug=True) webview.start()install pywebview
pywebview is a lightweight cross-platform wrapper around a webview component that allows to display HTML content in its own native GUI window.
https://pypi.org/project/pywebview/
C:\flask_dev>pip install pywebview
templates/index.html
//templates/index.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>Calculator</title> <link href="{{ url_for('static',filename='style.css') }}" rel="stylesheet"> <script src="{{ url_for('static',filename='script.js') }}" defer></script> </head> <body> <div class="calculator-grid"> <div class="output"> <div data-previous-operand class="previous-operand"></div> <div data-current-operand class="current-operand"></div> </div> <button data-all-clear class="span-two">AC</button> <button data-delete class="operation">DEL</button> <button data-operation class="operation">÷</button> <button data-number>1</button> <button data-number>2</button> <button data-number>3</button> <button data-operation class="operation">*</button> <button data-number>4</button> <button data-number>5</button> <button data-number>6</button> <button data-operation class="operation">+</button> <button data-number>7</button> <button data-number>8</button> <button data-number>9</button> <button data-operation class="operation">-</button> <button data-number>.</button> <button data-number>0</button> <button data-equals class="span-two">=</button> </div> <a href="/page2">Page 2</a> </body> </html>templates/page2.html
//templates/page2.html <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>Page 2</title> </head> <body> <h1>Page2</h1> <a href="/">Home</a> </body> </html>static/style.html
//static/style.html *, *::before, *::after { box-sizing: border-box; font-family: Gotham Rounded, sans-serif; font-weight: normal; } body { margin: 0; padding: 0; background: linear-gradient(to right, #0187d0, #a5c2c8); } .calculator-grid { display: grid; justify-content: center; align-content: center; min-height: 100vh; grid-template-columns: repeat(4, 100px); grid-template-rows: minmax(120px, auto) repeat(5, 100px); } .calculator-grid > button { cursor: pointer; font-size: 2rem; border: 1px, solid #FFFFFF; outline: none; } .calculator-grid > button:hover { background-color: #a5a5a5; } .span-two { grid-column: span 2; color: #adf802; background-color: #fd9502; } .operation { color: #ffffff; background-color: #fd9502; } .output{ grid-column: 1 / -1; background-color: rgba(0, 0, 0, 0.75); display: flex; align-items: flex-end; justify-content: space-around; flex-direction: column; padding: 10px; word-wrap: break-word; word-break: break-all; } .output .previous-operand{ color: rgba(255,255, 255, 0.75); font-size: 1.5rem; } .output .current-operand{ color: white; font-size: 2.5rem; }static/script.js
//static/script.js class Calculator { constructor(previousOperandTextElement, currentOperandTextElement) { this.previousOperandTextElement = previousOperandTextElement this.currentOperandTextElement = currentOperandTextElement this.clear() } clear() { this.currentOperand = '' this.previousOperand = '' this.operation = undefined } delete() { this.currentOperand = this.currentOperand.toString().slice(0, -1) } appendNumber(number) { if (number === '.' && this.currentOperand.includes('.')) return this.currentOperand = this.currentOperand.toString() + number.toString() } chooseOperation(operation) { if (this.currentOperand === '') return if (this.previousOperand !== '') { this.compute() } this.operation = operation this.previousOperand = this.currentOperand this.currentOperand = '' } compute() { let computation const prev = parseFloat(this.previousOperand) const current = parseFloat(this.currentOperand) if (isNaN(prev) || isNaN(current)) return switch (this.operation) { case '+': computation = prev + current break case '-': computation = prev - current break case '*': computation = prev * current break case '÷': computation = prev / current break default: return } this.currentOperand = computation this.operation = undefined this.previousOperand = '' } getDisplayNumber(number) { const stringNumber = number.toString() const integerDigits = parseFloat(stringNumber.split('.')[0]) const decimalDigits = stringNumber.split('.')[1] let integerDisplay if (isNaN(integerDigits)) { integerDisplay = '' } else { integerDisplay = integerDigits.toLocaleString('en', { maximumFractionDigits: 0 }) } if (decimalDigits != null) { return `${integerDisplay}.${decimalDigits}` } else { return integerDisplay } } updateDisplay() { this.currentOperandTextElement.innerText = this.getDisplayNumber(this.currentOperand) if (this.operation != null) { this.previousOperandTextElement.innerText = `${this.getDisplayNumber(this.previousOperand)} ${this.operation}` } else { this.previousOperandTextElement.innerText = '' } } } const numberButtons = document.querySelectorAll('[data-number]') const operationButtons = document.querySelectorAll('[data-operation]') const equalsButton = document.querySelector('[data-equals]') const deleteButton = document.querySelector('[data-delete]') const allClearButton = document.querySelector('[data-all-clear]') const previousOperandTextElement = document.querySelector('[data-previous-operand]') const currentOperandTextElement = document.querySelector('[data-current-operand]') const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement) numberButtons.forEach(button => { button.addEventListener('click', () => { calculator.appendNumber(button.innerText) calculator.updateDisplay() }) }) operationButtons.forEach(button => { button.addEventListener('click', () => { calculator.chooseOperation(button.innerText) calculator.updateDisplay() }) }) equalsButton.addEventListener('click', button => { calculator.compute() calculator.updateDisplay() }) allClearButton.addEventListener('click', button => { calculator.clear() calculator.updateDisplay() }) deleteButton.addEventListener('click', button => { calculator.delete() calculator.updateDisplay() }) document.addEventListener('keydown', function (event) { let patternForNumbers = /[0-9]/g; let patternForOperators = /[+\-*\/]/g if (event.key.match(patternForNumbers)) { event.preventDefault(); calculator.appendNumber(event.key) calculator.updateDisplay() } if (event.key === '.') { event.preventDefault(); calculator.appendNumber(event.key) calculator.updateDisplay() } if (event.key.match(patternForOperators)) { event.preventDefault(); calculator.chooseOperation(event.key) calculator.updateDisplay() } if (event.key === 'Enter' || event.key === '=') { event.preventDefault(); calculator.compute() calculator.updateDisplay() } if (event.key === "Backspace") { event.preventDefault(); calculator.delete() calculator.updateDisplay() } if (event.key == 'Delete') { event.preventDefault(); calculator.clear() calculator.updateDisplay() } });run (venv) C:\flask_dev\flasktoexe>flask run
convert to exe file
install Auto PY to EXE
Converts .py to .exe using a simple graphical interface.
https://pypi.org/project/auto-py-to-exe/
C:\>pip install auto-py-to-exe
execute terminal:
C:\>auto-py-to-exe