Initial commit
This commit is contained in:
commit
ff50ea6784
12 changed files with 509 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
__pycache__
|
||||||
8
config.py
Normal file
8
config.py
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
DB_HOST = "localhost"
|
||||||
|
DB_PORT = 5432
|
||||||
|
DB_NAME = "toy_store_a"
|
||||||
|
DB_USER = "postgres"
|
||||||
|
DB_PASSWORD = "1234"
|
||||||
|
|
||||||
|
DISCOUNT_COLOR = "#dbe68a"
|
||||||
|
OUT_OF_STOCK_COLOR = "#565750"
|
||||||
48
controllers/auth_controller.py
Normal file
48
controllers/auth_controller.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
from models.user_model import UserModel
|
||||||
|
from views.login_view import LoginView
|
||||||
|
from controllers.catalog_controller import CatalogController
|
||||||
|
|
||||||
|
|
||||||
|
class AuthController:
|
||||||
|
def __init__(self, database):
|
||||||
|
self.database = database
|
||||||
|
self.model = UserModel(database)
|
||||||
|
self.view = LoginView()
|
||||||
|
|
||||||
|
self.view.login_button.clicked.connect(
|
||||||
|
self.login
|
||||||
|
)
|
||||||
|
self.view.guest_button.clicked.connect(
|
||||||
|
self.login_as_guest
|
||||||
|
)
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
self.view.show()
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
login = self.view.login_input.text()
|
||||||
|
password = self.view.password_input.text()
|
||||||
|
user = self.model.authenticate(login, password)
|
||||||
|
|
||||||
|
if user:
|
||||||
|
self.open_catalog(
|
||||||
|
user["full_name"],
|
||||||
|
user["role_name"],
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.view.status_label.setText(
|
||||||
|
"Неверный логин или пароль"
|
||||||
|
)
|
||||||
|
|
||||||
|
def login_as_guest(self):
|
||||||
|
self.open_catalog("Гость", "Гость")
|
||||||
|
|
||||||
|
def open_catalog(self, full_name: str, role: str):
|
||||||
|
self.catalog = CatalogController(
|
||||||
|
self.database,
|
||||||
|
full_name,
|
||||||
|
role,
|
||||||
|
self,
|
||||||
|
)
|
||||||
|
self.catalog.show()
|
||||||
|
self.view.close()
|
||||||
38
controllers/catalog_controller.py
Normal file
38
controllers/catalog_controller.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
from models.toy_model import ToyModel
|
||||||
|
from views.catalog_view import CatalogView
|
||||||
|
|
||||||
|
|
||||||
|
class CatalogController:
|
||||||
|
def __init__(self, database, full_name, role, auth):
|
||||||
|
self.database = database
|
||||||
|
self.model = ToyModel(database)
|
||||||
|
self.view = CatalogView(full_name, role)
|
||||||
|
self.auth = auth
|
||||||
|
self.role = role
|
||||||
|
|
||||||
|
self.view.refresh_button.clicked.connect(
|
||||||
|
self.load_data
|
||||||
|
)
|
||||||
|
self.view.sort_button.clicked.connect(
|
||||||
|
self.sort_by_price
|
||||||
|
)
|
||||||
|
self.view.logout_button.clicked.connect(
|
||||||
|
self.logout
|
||||||
|
)
|
||||||
|
|
||||||
|
self.load_data()
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
self.view.show()
|
||||||
|
|
||||||
|
def load_data(self):
|
||||||
|
toys = self.model.get_all()
|
||||||
|
self.view.load_data(toys)
|
||||||
|
|
||||||
|
def sort_by_price(self):
|
||||||
|
toys = self.model.sort_by_price()
|
||||||
|
self.view.load_data(toys)
|
||||||
|
|
||||||
|
def logout(self):
|
||||||
|
self.view.close()
|
||||||
|
self.auth.show()
|
||||||
138
db.sql
Normal file
138
db.sql
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
CREATE TABLE roles (
|
||||||
|
role_id SERIAL PRIMARY KEY,
|
||||||
|
role_name VARCHAR(50) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE users (
|
||||||
|
user_id SERIAL PRIMARY KEY,
|
||||||
|
login VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
password VARCHAR(100) NOT NULL,
|
||||||
|
full_name VARCHAR(150) NOT NULL,
|
||||||
|
role_id INTEGER REFERENCES roles(role_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE categories (
|
||||||
|
category_id SERIAL PRIMARY KEY,
|
||||||
|
category_name VARCHAR(100) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE manufacturers (
|
||||||
|
manufacturer_id SERIAL PRIMARY KEY,
|
||||||
|
manufacturer_name VARCHAR(100) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE suppliers (
|
||||||
|
supplier_id SERIAL PRIMARY KEY,
|
||||||
|
supplier_name VARCHAR(100) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE age_groups (
|
||||||
|
age_group_id SERIAL PRIMARY KEY,
|
||||||
|
age_label VARCHAR(20) NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE toys (
|
||||||
|
toy_id SERIAL PRIMARY KEY,
|
||||||
|
toy_name VARCHAR(150) NOT NULL,
|
||||||
|
category_id INTEGER REFERENCES categories(category_id),
|
||||||
|
manufacturer_id INTEGER REFERENCES manufacturers(manufacturer_id),
|
||||||
|
price NUMERIC(10,2) NOT NULL,
|
||||||
|
discount INTEGER DEFAULT 0,
|
||||||
|
image VARCHAR(255)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE toy_age_groups (
|
||||||
|
toy_id INTEGER REFERENCES toys(toy_id),
|
||||||
|
age_group_id INTEGER REFERENCES age_groups(age_group_id),
|
||||||
|
PRIMARY KEY (toy_id, age_group_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE toy_suppliers (
|
||||||
|
toy_id INTEGER REFERENCES toys(toy_id),
|
||||||
|
supplier_id INTEGER REFERENCES suppliers(supplier_id),
|
||||||
|
PRIMARY KEY (toy_id, supplier_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE stock (
|
||||||
|
toy_id INTEGER PRIMARY KEY REFERENCES toys(toy_id),
|
||||||
|
quantity INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO roles (role_name) VALUES
|
||||||
|
('Гость'),
|
||||||
|
('Покупатель'),
|
||||||
|
('Сотрудник'),
|
||||||
|
('Администратор');
|
||||||
|
|
||||||
|
INSERT INTO users (login, password, full_name, role_id) VALUES
|
||||||
|
('guest','guest','Гость',1),
|
||||||
|
('anna','111','Иванова Анна Сергеевна',2),
|
||||||
|
('oleg','222','Кузнецов Олег Петрович',2),
|
||||||
|
('manager','333','Смирнова Мария Андреевна',3),
|
||||||
|
('admin','admin','Сидоров Максим Игоревич',4);
|
||||||
|
|
||||||
|
INSERT INTO categories (category_name) VALUES
|
||||||
|
('Мягкие игрушки'),
|
||||||
|
('Конструкторы'),
|
||||||
|
('Развивающие игрушки'),
|
||||||
|
('Настольные игры'),
|
||||||
|
('Роботы');
|
||||||
|
|
||||||
|
INSERT INTO manufacturers (manufacturer_name) VALUES
|
||||||
|
('Lego'),
|
||||||
|
('Hasbro'),
|
||||||
|
('Mattel'),
|
||||||
|
('PlaySmart'),
|
||||||
|
('Fisher Price');
|
||||||
|
|
||||||
|
INSERT INTO suppliers (supplier_name) VALUES
|
||||||
|
('ООО Радуга'),
|
||||||
|
('ИП Смайл'),('ToyImport'),
|
||||||
|
('KidsWorld');
|
||||||
|
|
||||||
|
INSERT INTO age_groups (age_label) VALUES
|
||||||
|
('0-1'),
|
||||||
|
('1-3'),
|
||||||
|
('3-5'),
|
||||||
|
('5-7'),
|
||||||
|
('7+');
|
||||||
|
|
||||||
|
INSERT INTO toys (toy_name, category_id, manufacturer_id, price, discount, image) VALUES
|
||||||
|
('Плюшевый мишка',1,4,1500,10,'bear.png'),
|
||||||
|
('Конструктор City',2,1,4200,25,'city.png'),
|
||||||
|
('Развивающий куб',3,5,2300,0,NULL),
|
||||||
|
('Робот трансформер',5,2,5200,30,'robot.png'),
|
||||||
|
('Настольная игра Лото',4,3,1800,5,NULL),
|
||||||
|
('Кукла классическая',1,3,2700,15,'doll.png'),
|
||||||
|
('Конструктор Junior',2,1,3100,0,NULL),
|
||||||
|
('Музыкальный телефон',3,5,2100,20,NULL),
|
||||||
|
('Робот на пульте',5,2,6400,35,'rc.png'),
|
||||||
|
('Игра Мемори',4,3,1600,0,NULL);
|
||||||
|
|
||||||
|
INSERT INTO toy_age_groups (toy_id, age_group_id) VALUES
|
||||||
|
(1,2),(1,3),
|
||||||
|
(2,4),(2,5),
|
||||||
|
(3,2),
|
||||||
|
(4,4),(4,5),
|
||||||
|
(5,3),(5,4),
|
||||||
|
(6,3),(6,4),
|
||||||
|
(7,2),(7,3),
|
||||||
|
(8,2),
|
||||||
|
(9,5),
|
||||||
|
(10,3),(10,4);
|
||||||
|
|
||||||
|
INSERT INTO toy_suppliers (toy_id, supplier_id) VALUES
|
||||||
|
(1,1),(1,2),
|
||||||
|
(2,3),
|
||||||
|
(3,1),(3,4),
|
||||||
|
(4,2),(4,3),
|
||||||
|
(5,1),
|
||||||
|
(6,4),
|
||||||
|
(7,3),
|
||||||
|
(8,2),(8,4),
|
||||||
|
(9,3),
|
||||||
|
(10,1),(10,2);
|
||||||
|
|
||||||
|
INSERT INTO stock (toy_id, quantity) VALUES
|
||||||
|
(1,12),(2,5),(3,0),(4,7),(5,10),
|
||||||
|
(6,4),(7,8),(8,0),(9,3),(10,15);
|
||||||
16
main.py
Normal file
16
main.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import sys
|
||||||
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
from models.database import Database
|
||||||
|
from controllers.auth_controller import AuthController
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
database = Database()
|
||||||
|
controller = AuthController(database)
|
||||||
|
controller.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
0
models/__init__.py
Normal file
0
models/__init__.py
Normal file
36
models/database.py
Normal file
36
models/database.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import psycopg2
|
||||||
|
from psycopg2.extras import RealDictCursor
|
||||||
|
from config import (
|
||||||
|
DB_HOST,
|
||||||
|
DB_PORT,
|
||||||
|
DB_NAME,
|
||||||
|
DB_USER,
|
||||||
|
DB_PASSWORD,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Database:
|
||||||
|
def __init__(self):
|
||||||
|
self.connection = psycopg2.connect(
|
||||||
|
host=DB_HOST,
|
||||||
|
port=DB_PORT,
|
||||||
|
dbname=DB_NAME,
|
||||||
|
user=DB_USER,
|
||||||
|
password=DB_PASSWORD,
|
||||||
|
cursor_factory=RealDictCursor,
|
||||||
|
)
|
||||||
|
|
||||||
|
def fetch_all(self, query: str, params: tuple = ()):
|
||||||
|
with self.connection.cursor() as cursor:
|
||||||
|
cursor.execute(query, params)
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
def fetch_one(self, query: str, params: tuple = ()):
|
||||||
|
with self.connection.cursor() as cursor:
|
||||||
|
cursor.execute(query, params)
|
||||||
|
return cursor.fetchone()
|
||||||
|
|
||||||
|
def execute(self, query: str, params: tuple = ()):
|
||||||
|
with self.connection.cursor() as cursor:
|
||||||
|
cursor.execute(query, params)
|
||||||
|
self.connection.commit()
|
||||||
87
models/toy_model.py
Normal file
87
models/toy_model.py
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
from models.database import Database
|
||||||
|
|
||||||
|
|
||||||
|
class ToyModel:
|
||||||
|
def __init__(self, database: Database):
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
def get_all(self):
|
||||||
|
query = """
|
||||||
|
SELECT t.toy_id,
|
||||||
|
t.toy_name,
|
||||||
|
c.category_name,
|
||||||
|
m.manufacturer_name,
|
||||||
|
t.price,
|
||||||
|
t.discount,
|
||||||
|
COALESCE(s.quantity, 0) AS quantity,
|
||||||
|
STRING_AGG(DISTINCT a.age_label, ', ') AS ages,
|
||||||
|
STRING_AGG(DISTINCT sup.supplier_name, ', ') AS suppliers
|
||||||
|
FROM toys t
|
||||||
|
JOIN categories c ON t.category_id = c.category_id
|
||||||
|
JOIN manufacturers m ON t.manufacturer_id = m.manufacturer_id
|
||||||
|
LEFT JOIN stock s ON t.toy_id = s.toy_id
|
||||||
|
LEFT JOIN toy_age_groups ta ON t.toy_id = ta.toy_id
|
||||||
|
LEFT JOIN age_groups a ON ta.age_group_id = a.age_group_id
|
||||||
|
LEFT JOIN toy_suppliers ts ON t.toy_id = ts.toy_id
|
||||||
|
LEFT JOIN suppliers sup ON ts.supplier_id = sup.supplier_id
|
||||||
|
GROUP BY t.toy_id, c.category_name,
|
||||||
|
m.manufacturer_name, s.quantity
|
||||||
|
ORDER BY t.toy_name
|
||||||
|
"""
|
||||||
|
return self.database.fetch_all(query)
|
||||||
|
|
||||||
|
def search_by_age(self, age: str):
|
||||||
|
query = """
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
SELECT t.toy_id,
|
||||||
|
t.toy_name,
|
||||||
|
c.category_name,
|
||||||
|
m.manufacturer_name,
|
||||||
|
t.price,
|
||||||
|
t.discount,
|
||||||
|
COALESCE(s.quantity, 0) AS quantity,
|
||||||
|
STRING_AGG(DISTINCT a.age_label, ', ') AS ages,
|
||||||
|
STRING_AGG(DISTINCT sup.supplier_name, ', ') AS suppliers
|
||||||
|
FROM toys t
|
||||||
|
JOIN categories c ON t.category_id = c.category_id
|
||||||
|
JOIN manufacturers m ON t.manufacturer_id = m.manufacturer_id
|
||||||
|
LEFT JOIN stock s ON t.toy_id = s.toy_id
|
||||||
|
LEFT JOIN toy_age_groups ta ON t.toy_id = ta.toy_id
|
||||||
|
LEFT JOIN age_groups a ON ta.age_group_id = a.age_group_id
|
||||||
|
LEFT JOIN toy_suppliers ts ON t.toy_id = ts.toy_id
|
||||||
|
LEFT JOIN suppliers sup ON ts.supplier_id = sup.supplier_id
|
||||||
|
GROUP BY t.toy_id, c.category_name,
|
||||||
|
m.manufacturer_name, s.quantity
|
||||||
|
) sub
|
||||||
|
WHERE ages ILIKE %s
|
||||||
|
"""
|
||||||
|
return self.database.fetch_all(query, (f"%{age}%",))
|
||||||
|
|
||||||
|
def sort_by_price(self):
|
||||||
|
query = """
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
SELECT t.toy_id,
|
||||||
|
t.toy_name,
|
||||||
|
c.category_name,
|
||||||
|
m.manufacturer_name,
|
||||||
|
t.price,
|
||||||
|
t.discount,
|
||||||
|
COALESCE(s.quantity, 0) AS quantity,
|
||||||
|
STRING_AGG(DISTINCT a.age_label, ', ') AS ages,
|
||||||
|
STRING_AGG(DISTINCT sup.supplier_name, ', ') AS suppliers
|
||||||
|
FROM toys t
|
||||||
|
JOIN categories c ON t.category_id = c.category_id
|
||||||
|
JOIN manufacturers m ON t.manufacturer_id = m.manufacturer_id
|
||||||
|
LEFT JOIN stock s ON t.toy_id = s.toy_id
|
||||||
|
LEFT JOIN toy_age_groups ta ON t.toy_id = ta.toy_id
|
||||||
|
LEFT JOIN age_groups a ON ta.age_group_id = a.age_group_id
|
||||||
|
LEFT JOIN toy_suppliers ts ON t.toy_id = ts.toy_id
|
||||||
|
LEFT JOIN suppliers sup ON ts.supplier_id = sup.supplier_id
|
||||||
|
GROUP BY t.toy_id, c.category_name,
|
||||||
|
m.manufacturer_name, s.quantity
|
||||||
|
) sub
|
||||||
|
ORDER BY price
|
||||||
|
"""
|
||||||
|
return self.database.fetch_all(query)
|
||||||
17
models/user_model.py
Normal file
17
models/user_model.py
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
from models.database import Database
|
||||||
|
|
||||||
|
|
||||||
|
class UserModel:
|
||||||
|
def __init__(self, database: Database):
|
||||||
|
self.database = database
|
||||||
|
|
||||||
|
def authenticate(self, login: str, password: str):
|
||||||
|
query = """
|
||||||
|
SELECT u.user_id,
|
||||||
|
u.full_name,
|
||||||
|
r.role_name
|
||||||
|
FROM users u
|
||||||
|
JOIN roles r ON u.role_id = r.role_id
|
||||||
|
WHERE u.login = %s AND u.password = %s
|
||||||
|
"""
|
||||||
|
return self.database.fetch_one(query, (login, password))
|
||||||
82
views/catalog_view.py
Normal file
82
views/catalog_view.py
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QWidget,
|
||||||
|
QVBoxLayout,
|
||||||
|
QPushButton,
|
||||||
|
QLabel,
|
||||||
|
QTableWidget,
|
||||||
|
QTableWidgetItem,
|
||||||
|
)
|
||||||
|
from PyQt6.QtGui import QColor
|
||||||
|
from config import DISCOUNT_COLOR, OUT_OF_STOCK_COLOR
|
||||||
|
|
||||||
|
|
||||||
|
class CatalogView(QWidget):
|
||||||
|
def __init__(self, full_name: str, role: str):
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Каталог игрушек")
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout()
|
||||||
|
|
||||||
|
self.user_label = QLabel(
|
||||||
|
f"{full_name} ({role})"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.refresh_button = QPushButton("Обновить")
|
||||||
|
self.sort_button = QPushButton("Сортировать по цене")
|
||||||
|
self.logout_button = QPushButton("Выйти")
|
||||||
|
|
||||||
|
self.table = QTableWidget()
|
||||||
|
|
||||||
|
self.layout.addWidget(self.user_label)
|
||||||
|
self.layout.addWidget(self.refresh_button)
|
||||||
|
self.layout.addWidget(self.sort_button)
|
||||||
|
self.layout.addWidget(self.table)
|
||||||
|
self.layout.addWidget(self.logout_button)
|
||||||
|
|
||||||
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
self.setFixedSize(860, 500)
|
||||||
|
|
||||||
|
def load_data(self, toys: list):
|
||||||
|
headers = [
|
||||||
|
"Название",
|
||||||
|
"Категория",
|
||||||
|
"Производитель",
|
||||||
|
"Возраст",
|
||||||
|
"Поставщик",
|
||||||
|
"Цена",
|
||||||
|
"Скидка",
|
||||||
|
"Остаток",
|
||||||
|
]
|
||||||
|
|
||||||
|
self.table.setColumnCount(len(headers))
|
||||||
|
self.table.setHorizontalHeaderLabels(headers)
|
||||||
|
self.table.setRowCount(len(toys))
|
||||||
|
|
||||||
|
for row, toy in enumerate(toys):
|
||||||
|
values = [
|
||||||
|
toy["toy_name"],
|
||||||
|
toy["category_name"],
|
||||||
|
toy["manufacturer_name"],
|
||||||
|
toy["ages"],
|
||||||
|
toy["suppliers"],
|
||||||
|
str(toy["price"]),
|
||||||
|
str(toy["discount"]),
|
||||||
|
str(toy["quantity"]),
|
||||||
|
]
|
||||||
|
|
||||||
|
for col, value in enumerate(values):
|
||||||
|
item = QTableWidgetItem(value)
|
||||||
|
self.table.setItem(row, col, item)
|
||||||
|
|
||||||
|
if toy["discount"] >= 25:
|
||||||
|
for col in range(len(headers)):
|
||||||
|
self.table.item(row, col).setBackground(
|
||||||
|
QColor(DISCOUNT_COLOR)
|
||||||
|
)
|
||||||
|
|
||||||
|
if toy["quantity"] == 0:
|
||||||
|
for col in range(len(headers)):
|
||||||
|
self.table.item(row, col).setBackground(
|
||||||
|
QColor(OUT_OF_STOCK_COLOR)
|
||||||
|
)
|
||||||
38
views/login_view.py
Normal file
38
views/login_view.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QWidget,
|
||||||
|
QVBoxLayout,
|
||||||
|
QLineEdit,
|
||||||
|
QPushButton,
|
||||||
|
QLabel,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LoginView(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Авторизация")
|
||||||
|
|
||||||
|
self.layout = QVBoxLayout()
|
||||||
|
|
||||||
|
self.login_input = QLineEdit()
|
||||||
|
self.login_input.setPlaceholderText("Логин")
|
||||||
|
|
||||||
|
self.password_input = QLineEdit()
|
||||||
|
self.password_input.setPlaceholderText("Пароль")
|
||||||
|
self.password_input.setEchoMode(
|
||||||
|
QLineEdit.EchoMode.Password
|
||||||
|
)
|
||||||
|
|
||||||
|
self.login_button = QPushButton("Войти")
|
||||||
|
self.guest_button = QPushButton("Войти как гость")
|
||||||
|
self.status_label = QLabel()
|
||||||
|
|
||||||
|
self.layout.addWidget(self.login_input)
|
||||||
|
self.layout.addWidget(self.password_input)
|
||||||
|
self.layout.addWidget(self.login_button)
|
||||||
|
self.layout.addWidget(self.guest_button)
|
||||||
|
self.layout.addWidget(self.status_label)
|
||||||
|
|
||||||
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
|
self.setFixedSize(240, 180)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue