Added missing files and removed unnessesary ones
This commit is contained in:
parent
c3fa5367c3
commit
199dd693e4
50
C++/.vscode/settings.json
vendored
50
C++/.vscode/settings.json
vendored
@ -1,50 +0,0 @@
|
|||||||
{
|
|
||||||
"files.associations": {
|
|
||||||
"algorithm": "cpp",
|
|
||||||
"iostream": "cpp",
|
|
||||||
"numeric": "cpp",
|
|
||||||
"array": "cpp",
|
|
||||||
"atomic": "cpp",
|
|
||||||
"bit": "cpp",
|
|
||||||
"*.tcc": "cpp",
|
|
||||||
"cctype": "cpp",
|
|
||||||
"clocale": "cpp",
|
|
||||||
"cmath": "cpp",
|
|
||||||
"compare": "cpp",
|
|
||||||
"concepts": "cpp",
|
|
||||||
"cstdarg": "cpp",
|
|
||||||
"cstddef": "cpp",
|
|
||||||
"cstdint": "cpp",
|
|
||||||
"cstdio": "cpp",
|
|
||||||
"cstdlib": "cpp",
|
|
||||||
"cwchar": "cpp",
|
|
||||||
"cwctype": "cpp",
|
|
||||||
"deque": "cpp",
|
|
||||||
"string": "cpp",
|
|
||||||
"unordered_map": "cpp",
|
|
||||||
"vector": "cpp",
|
|
||||||
"exception": "cpp",
|
|
||||||
"functional": "cpp",
|
|
||||||
"iterator": "cpp",
|
|
||||||
"memory": "cpp",
|
|
||||||
"memory_resource": "cpp",
|
|
||||||
"random": "cpp",
|
|
||||||
"string_view": "cpp",
|
|
||||||
"system_error": "cpp",
|
|
||||||
"tuple": "cpp",
|
|
||||||
"type_traits": "cpp",
|
|
||||||
"utility": "cpp",
|
|
||||||
"initializer_list": "cpp",
|
|
||||||
"iosfwd": "cpp",
|
|
||||||
"istream": "cpp",
|
|
||||||
"limits": "cpp",
|
|
||||||
"new": "cpp",
|
|
||||||
"numbers": "cpp",
|
|
||||||
"ostream": "cpp",
|
|
||||||
"stdexcept": "cpp",
|
|
||||||
"streambuf": "cpp",
|
|
||||||
"typeinfo": "cpp",
|
|
||||||
"ctime": "cpp",
|
|
||||||
"cstring": "cpp"
|
|
||||||
}
|
|
||||||
}
|
|
240
C++/C++.md
240
C++/C++.md
@ -545,3 +545,243 @@ void boo(int* ptr) {
|
|||||||
## Структуры
|
## Структуры
|
||||||
|
|
||||||
> Структура - тип данных, позоляющий объединить несколько переменных в одной еденице.
|
> Структура - тип данных, позоляющий объединить несколько переменных в одной еденице.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
struct Employee {
|
||||||
|
short id;
|
||||||
|
int age;
|
||||||
|
double salary;
|
||||||
|
};
|
||||||
|
|
||||||
|
Employee john = {5, 20, 30.0};
|
||||||
|
std::cout << john.id << ' ' << john.age << ' ' << john.salary << '\n';
|
||||||
|
```
|
||||||
|
|
||||||
|
## Перечисления
|
||||||
|
|
||||||
|
> Перечисление - это пользовательский тип данных, который представляет собой набор именованных констант, которым присваиваются целочисленные значения. Весит как *int*
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
enum Weekday {
|
||||||
|
Monday,
|
||||||
|
Tuesday,
|
||||||
|
Wednesday,
|
||||||
|
Thursday,
|
||||||
|
Friday,
|
||||||
|
Saturday,
|
||||||
|
Sunday,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Weekday2 {
|
||||||
|
Monday = 1,
|
||||||
|
Tuesday = 2,
|
||||||
|
Wednesday = 3,
|
||||||
|
Thursday = 4,
|
||||||
|
Friday = 5,
|
||||||
|
Saturday = 6,
|
||||||
|
Sunday = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
Weekday today = Saturday;
|
||||||
|
```
|
||||||
|
|
||||||
|
Weekday полностью аналогичен Weekday2
|
||||||
|
|
||||||
|
## Объединение
|
||||||
|
|
||||||
|
> Объединение - это пользовательский тип данных, позволяющий хранить различные типы данных в одной области памяти. Объединение занимает память, достаточную для хранения переменной имеющий самый большой размер.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
union MyUnion{
|
||||||
|
int intValue;
|
||||||
|
char charValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
MyUnion val = 65;
|
||||||
|
int a = val.intValue; // 65
|
||||||
|
char b = val.charValue; // 'A'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Передача значений в функцию (Подробнее)
|
||||||
|
|
||||||
|
* Передача по значению (создаётся копия, может быть медленно, используется для примитивов)
|
||||||
|
|
||||||
|
```C++
|
||||||
|
void increment(int a) {
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int a = 5;
|
||||||
|
increment(&a); // a остаётся 5
|
||||||
|
```
|
||||||
|
|
||||||
|
* Передача по ссылке (копия не создаётся, используется для больших значений / структур, аналогична передаче по значению, но синтаксис проще)
|
||||||
|
|
||||||
|
```C++
|
||||||
|
void increment(int& a) {
|
||||||
|
a++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int a = 5;
|
||||||
|
increment(a); // a становится 6
|
||||||
|
```
|
||||||
|
|
||||||
|
* Передача по указателю (копия не создаётся, используется в основном для массивов)
|
||||||
|
|
||||||
|
```C++
|
||||||
|
void increment(int* a) {
|
||||||
|
(*a)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int a = 5;
|
||||||
|
increment(&a); // a тоже становится 6
|
||||||
|
```
|
||||||
|
|
||||||
|
## Классы
|
||||||
|
|
||||||
|
> Классы - шаблон или описание, определяющее структуру поведения объектов.
|
||||||
|
> Объект - экземляр класса
|
||||||
|
|
||||||
|
```С++
|
||||||
|
class ClassName{
|
||||||
|
// Поля и методы класса
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
> Поля класса - переменные, котроые представляют состояие объетогв класса
|
||||||
|
> Методы класа - функции, которые определяют поведение объектов класса
|
||||||
|
|
||||||
|
```С++
|
||||||
|
ClassName objectName; // создание объекта класса просто
|
||||||
|
|
||||||
|
ClassName objectName = new ClassName(); //создание объекта класса сложно
|
||||||
|
delete objectName;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Пример
|
||||||
|
|
||||||
|
```С++
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Person{
|
||||||
|
public:
|
||||||
|
std::string name;
|
||||||
|
int age;
|
||||||
|
|
||||||
|
void displayInfo(){
|
||||||
|
std::count << "Name: " << name << ", Age: " << age << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(){
|
||||||
|
Person person1;
|
||||||
|
person1.name = "Alice";
|
||||||
|
person1.age = 25;
|
||||||
|
person1.displayInfo();
|
||||||
|
|
||||||
|
Person* person2 = new Person();
|
||||||
|
person2 -> name = "Bob";
|
||||||
|
person2 -> age = 30;
|
||||||
|
person2 -> displayInfo();
|
||||||
|
|
||||||
|
delete person2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> Пользовательский тип данных
|
||||||
|
|
||||||
|
### Модификаторы доступа
|
||||||
|
|
||||||
|
* public - доступно всем (по умолчанию в struct)
|
||||||
|
* private - доступно только внутри класса (по умолчанию в class)
|
||||||
|
* protected - достпуно внутри класса и наследникам
|
||||||
|
|
||||||
|
### Конструктор и деструктор
|
||||||
|
|
||||||
|
> Конструктор - функция, которая вызывается при инициализации класса (может быть несколько)
|
||||||
|
> Деструктор - функция, которая вызывается при уничтожении объекта
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class MyClass {
|
||||||
|
public:
|
||||||
|
MyClass() {
|
||||||
|
std::cout << "Constructed\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
MyClass(int val) {
|
||||||
|
std::cout << "Constucted" << val << '\n';f
|
||||||
|
}
|
||||||
|
|
||||||
|
~MyClass() {
|
||||||
|
std::cout << "Destroyed\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### this
|
||||||
|
|
||||||
|
> this - указатель на объект вызвовший метод
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Foo{
|
||||||
|
public:
|
||||||
|
Person(std::string val) {
|
||||||
|
this->name = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## ООП
|
||||||
|
|
||||||
|
> Инкапсуляция - данные класса скрыты от прямого доступа и манипулиций извне класса
|
||||||
|
> Наследование - создаёт классы-потомки
|
||||||
|
> Полимарфизм - разные классы используют один и тот же интерфейс
|
||||||
|
|
||||||
|
```C++
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class Figure {
|
||||||
|
public:
|
||||||
|
virtual void draw() {
|
||||||
|
std::cout << "Draw figure\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Circe: public Figure {
|
||||||
|
public:
|
||||||
|
void draw() override {
|
||||||
|
std::cout << "Draw circle\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Rectangle: public Figure {
|
||||||
|
public:
|
||||||
|
void draw() override {
|
||||||
|
std::cout << "Draw rectangle\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Figure* figure = new Figure();
|
||||||
|
Figure* circle = new Circle():
|
||||||
|
Figure* rectangle = new Rectangle();
|
||||||
|
|
||||||
|
figure->draw();
|
||||||
|
circle->draw();
|
||||||
|
rectangle->draw();
|
||||||
|
|
||||||
|
delete figure;
|
||||||
|
delete circle;
|
||||||
|
delete rectangle;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
16
C++/lesson6/task1.cpp
Normal file
16
C++/lesson6/task1.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Person {
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Person(const std::string& name) {
|
||||||
|
this->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printName() {
|
||||||
|
std::cout << this->name << '\n';
|
||||||
|
}
|
||||||
|
};
|
47
C++/lesson6/task2.cpp
Normal file
47
C++/lesson6/task2.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Student {
|
||||||
|
std::string name;
|
||||||
|
int age;
|
||||||
|
double average_grade;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Student(std::string name, int age, double average) {
|
||||||
|
this->name = name;
|
||||||
|
this->age = age;
|
||||||
|
this->average_grade = average;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& get_name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_age() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_average_grade() {
|
||||||
|
return average_grade;
|
||||||
|
}
|
||||||
|
|
||||||
|
void status() {
|
||||||
|
if (average_grade >= 4 && average_grade < 5) {
|
||||||
|
std::cout << "Student is хорошист" << '\n';
|
||||||
|
} else if (average_grade = 5) {
|
||||||
|
std::cout << "Student is отличник" << '\n';
|
||||||
|
} else if (average_grade < 3) {
|
||||||
|
std::cout << "Student is двоечник" << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Student student1("George", 19, 3.5);
|
||||||
|
Student student2("Paul", 14, 4.8);
|
||||||
|
Student student3("Vasyok", 17, 5);
|
||||||
|
|
||||||
|
student1.status();
|
||||||
|
student2.status();
|
||||||
|
student3.status();
|
||||||
|
}
|
40
C++/lesson6/task3.cpp
Normal file
40
C++/lesson6/task3.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
struct Account {
|
||||||
|
int number;
|
||||||
|
int money;
|
||||||
|
int percentage;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Account(int number, int money, int percentage) {
|
||||||
|
this->number = number;
|
||||||
|
this->money = money;
|
||||||
|
this->percentage = percentage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void refill(int amount) {
|
||||||
|
money += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void withdraw(int amount) {
|
||||||
|
money -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintInformation() {
|
||||||
|
std::cout << number << ' ' << money << ' ' << percentage << '\n';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
Account* account1 = new Account(21213, 500, 15);
|
||||||
|
account1->PrintInformation();
|
||||||
|
account1->refill(200);
|
||||||
|
account1->withdraw(50);
|
||||||
|
account1->PrintInformation();
|
||||||
|
|
||||||
|
Account* account2 = new Account(1934, 800, 10);
|
||||||
|
account2->PrintInformation();
|
||||||
|
account2->refill(150);
|
||||||
|
account2->withdraw(23);
|
||||||
|
account2->PrintInformation();
|
||||||
|
}
|
37
Python/clock/main.py
Executable file
37
Python/clock/main.py
Executable file
@ -0,0 +1,37 @@
|
|||||||
|
import sys
|
||||||
|
from time import strftime
|
||||||
|
|
||||||
|
from PyQt6.QtCore import QTimer
|
||||||
|
from PyQt6.QtWidgets import QApplication, QLCDNumber, QVBoxLayout, QWidget
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(100, 100, 800, 400)
|
||||||
|
self.setWindowTitle("Clock")
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.timeout.connect(self.update_clock)
|
||||||
|
self.timer.start(200)
|
||||||
|
|
||||||
|
self.lcd = QLCDNumber()
|
||||||
|
vbox.addWidget(self.lcd)
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
def update_clock(self) -> None:
|
||||||
|
time_ = strftime("%H:%M:%S")
|
||||||
|
self.lcd.setDigitCount(8)
|
||||||
|
self.lcd.display(time_)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
BIN
Python/pyqt6_4/cat1.jpg
Executable file
BIN
Python/pyqt6_4/cat1.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 347 KiB |
BIN
Python/pyqt6_4/cat2.jpg
Executable file
BIN
Python/pyqt6_4/cat2.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.5 MiB |
21
Python/pyqt6_4/snippets/1.py
Executable file
21
Python/pyqt6_4/snippets/1.py
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import QApplication, QWidget
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
61
Python/pyqt6_4/snippets/10.py
Executable file
61
Python/pyqt6_4/snippets/10.py
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QWidget,
|
||||||
|
QHBoxLayout,
|
||||||
|
QSpinBox,
|
||||||
|
QLabel,
|
||||||
|
QLineEdit,
|
||||||
|
)
|
||||||
|
from PyQt6.QtGui import QFont
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
self.price = 300
|
||||||
|
self.amount = 0
|
||||||
|
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
|
||||||
|
self.line_edit = QLineEdit(str(self.price))
|
||||||
|
self.line_edit.setFont(QFont("Times", 14))
|
||||||
|
|
||||||
|
self.spin_box = QSpinBox()
|
||||||
|
self.spin_box.valueChanged.connect(self.handle_spin_box)
|
||||||
|
self.result = QLabel(str(self.total))
|
||||||
|
|
||||||
|
hbox.addWidget(self.line_edit)
|
||||||
|
hbox.addWidget(self.spin_box)
|
||||||
|
hbox.addWidget(self.result)
|
||||||
|
|
||||||
|
self.setLayout(hbox)
|
||||||
|
|
||||||
|
def handle_spin_box(self) -> None:
|
||||||
|
try:
|
||||||
|
self.price = int(self.line_edit.text())
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
self.amount = self.spin_box.value()
|
||||||
|
self.result.setText(str(self.total))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total(self) -> int:
|
||||||
|
return self.amount * self.price
|
||||||
|
|
||||||
|
def handle_line_edit(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
31
Python/pyqt6_4/snippets/2.py
Executable file
31
Python/pyqt6_4/snippets/2.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import QApplication, QWidget, QLabel
|
||||||
|
from PyQt6.QtGui import QPixmap
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
|
||||||
|
label = QLabel(self)
|
||||||
|
label.setText("Текст")
|
||||||
|
label.move(300, 300)
|
||||||
|
|
||||||
|
pixmap = QPixmap()
|
||||||
|
lable_pic = QLabel(self)
|
||||||
|
lable_pic.setPicture(pixmap)
|
||||||
|
lable_pic.move(200, 200)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
31
Python/pyqt6_4/snippets/3.py
Executable file
31
Python/pyqt6_4/snippets/3.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton
|
||||||
|
from PyQt6.QtCore import QSize
|
||||||
|
from PyQt6.QtGui import QFont, QIcon
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
self.create_button()
|
||||||
|
|
||||||
|
def create_button(self) -> None:
|
||||||
|
btn = QPushButton("Click", self)
|
||||||
|
btn.setGeometry(*(100,) * 4)
|
||||||
|
btn.setFont(QFont("Times", 14, QFont.Weight.ExtraBold))
|
||||||
|
btn.setIcon(QIcon("cat1.jpg"))
|
||||||
|
btn.setIconSize(QSize(50, 50))
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
27
Python/pyqt6_4/snippets/4.py
Executable file
27
Python/pyqt6_4/snippets/4.py
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtGui import QFont
|
||||||
|
from PyQt6.QtWidgets import QApplication, QLineEdit, QWidget
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
|
||||||
|
line_edit = QLineEdit(self)
|
||||||
|
line_edit.setFont(QFont("Times", 14))
|
||||||
|
line_edit.setPlaceholderText("Enter your password")
|
||||||
|
line_edit.setEchoMode(QLineEdit.EchoMode.Password)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
32
Python/pyqt6_4/snippets/5.py
Executable file
32
Python/pyqt6_4/snippets/5.py
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QHBoxLayout
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
|
||||||
|
btn1 = QPushButton("One")
|
||||||
|
btn2 = QPushButton("Two")
|
||||||
|
btn3 = QPushButton("Three")
|
||||||
|
|
||||||
|
layout = QHBoxLayout()
|
||||||
|
layout.addWidget(btn1)
|
||||||
|
layout.addWidget(btn2)
|
||||||
|
layout.addWidget(btn3)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
32
Python/pyqt6_4/snippets/6.py
Executable file
32
Python/pyqt6_4/snippets/6.py
Executable file
@ -0,0 +1,32 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
|
||||||
|
btn1 = QPushButton("One")
|
||||||
|
btn2 = QPushButton("Two")
|
||||||
|
btn3 = QPushButton("Three")
|
||||||
|
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(btn1)
|
||||||
|
layout.addWidget(btn2)
|
||||||
|
layout.addWidget(btn3)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
63
Python/pyqt6_4/snippets/7.py
Executable file
63
Python/pyqt6_4/snippets/7.py
Executable file
@ -0,0 +1,63 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtCore import QSize
|
||||||
|
from PyQt6.QtGui import QIcon
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QRadioButton,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
ICON_SIZE = 100
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(200, 200, 400, 300)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
self.create_radio()
|
||||||
|
|
||||||
|
def create_radio(self) -> None:
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
|
||||||
|
rad1 = QRadioButton("Cat 1")
|
||||||
|
rad1.setIcon(QIcon("cat1.jpg"))
|
||||||
|
rad1.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
|
||||||
|
rad1.toggled.connect(self.radio_selected)
|
||||||
|
|
||||||
|
rad2 = QRadioButton("Cat 2")
|
||||||
|
rad2.setIcon(QIcon("cat2.jpg"))
|
||||||
|
rad2.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
|
||||||
|
rad2.toggled.connect(self.radio_selected)
|
||||||
|
|
||||||
|
hbox.addWidget(rad1)
|
||||||
|
hbox.addWidget(rad2)
|
||||||
|
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
|
||||||
|
self.label = QLabel("")
|
||||||
|
|
||||||
|
vbox.addWidget(self.label)
|
||||||
|
vbox.addLayout(hbox)
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
def radio_selected(self) -> None:
|
||||||
|
radio_btn = self.sender()
|
||||||
|
if radio_btn.isEnabled():
|
||||||
|
self.label.setText(f"You have chosen {radio_btn.text().lower()}")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
68
Python/pyqt6_4/snippets/8.py
Executable file
68
Python/pyqt6_4/snippets/8.py
Executable file
@ -0,0 +1,68 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from PyQt6.QtCore import QSize
|
||||||
|
from PyQt6.QtGui import QIcon
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QCheckBox,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
ICON_SIZE = 100
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(200, 200, 400, 300)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
self.create_radio()
|
||||||
|
|
||||||
|
def create_radio(self) -> None:
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
|
||||||
|
self.check1 = QCheckBox("Cat 1")
|
||||||
|
self.check1.setIcon(QIcon("cat1.jpg"))
|
||||||
|
self.check1.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
|
||||||
|
self.check1.toggled.connect(self.radio_selected)
|
||||||
|
|
||||||
|
self.check2 = QCheckBox("Cat 2")
|
||||||
|
self.check2.setIcon(QIcon("cat2.jpg"))
|
||||||
|
self.check2.setIconSize(QSize(ICON_SIZE, ICON_SIZE))
|
||||||
|
self.check2.toggled.connect(self.radio_selected)
|
||||||
|
|
||||||
|
hbox.addWidget(self.check1)
|
||||||
|
hbox.addWidget(self.check2)
|
||||||
|
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
|
||||||
|
self.label = QLabel("You haven't chosen anything")
|
||||||
|
|
||||||
|
vbox.addWidget(self.label)
|
||||||
|
vbox.addLayout(hbox)
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
def radio_selected(self) -> None:
|
||||||
|
text = "You have chosen "
|
||||||
|
if self.check1.isChecked():
|
||||||
|
text += self.check1.text().lower() + ", "
|
||||||
|
if self.check2.isChecked():
|
||||||
|
text += self.check2.text().lower()
|
||||||
|
if not any((self.check1.isChecked(), self.check2.isChecked())):
|
||||||
|
text = "You haven't chosen anything"
|
||||||
|
text = text.removesuffix(", ")
|
||||||
|
self.label.setText(text)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
70
Python/pyqt6_4/snippets/9.py
Executable file
70
Python/pyqt6_4/snippets/9.py
Executable file
@ -0,0 +1,70 @@
|
|||||||
|
import sys
|
||||||
|
from enum import StrEnum
|
||||||
|
|
||||||
|
from PyQt6.QtGui import QFont
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QComboBox,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CatType(StrEnum):
|
||||||
|
ORANGE = "one orange brain cell"
|
||||||
|
VOID = "void"
|
||||||
|
DUST = "dust kitty"
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(*(500,) * 4)
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
self.current_type = CatType.ORANGE
|
||||||
|
self.create_combo()
|
||||||
|
|
||||||
|
def create_combo(self) -> None:
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
|
||||||
|
label = QLabel("Select cat type:")
|
||||||
|
label.setFont(QFont("Times", 15))
|
||||||
|
|
||||||
|
self.combo = QComboBox(self)
|
||||||
|
for cat_type in CatType:
|
||||||
|
self.combo.addItem(cat_type.capitalize())
|
||||||
|
self.combo.currentTextChanged.connect(self.combo_changed)
|
||||||
|
|
||||||
|
hbox.addWidget(label)
|
||||||
|
hbox.addWidget(self.combo)
|
||||||
|
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
self.label_result = QLabel(
|
||||||
|
f"Current cat: {self.current_type.capitalize()}",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.label_result.setFont(QFont("Times", 15))
|
||||||
|
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
vbox.addWidget(self.label_result)
|
||||||
|
vbox.addLayout(hbox)
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
def combo_changed(self) -> None:
|
||||||
|
self.current_type = CatType(self.combo.currentText().lower())
|
||||||
|
self.label_result.setText(
|
||||||
|
f"Current cat: {self.current_type.capitalize()}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
0
Python/pyqt6_4/task1.py
Executable file
0
Python/pyqt6_4/task1.py
Executable file
0
Python/pyqt6_4/test.py
Executable file
0
Python/pyqt6_4/test.py
Executable file
BIN
Python/soper/flag.jpg
Executable file
BIN
Python/soper/flag.jpg
Executable file
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
207
Python/soper/soper.py
Executable file
207
Python/soper/soper.py
Executable file
@ -0,0 +1,207 @@
|
|||||||
|
import sys
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from enum import StrEnum, auto
|
||||||
|
from random import sample
|
||||||
|
from typing import Any, Callable, Iterator, Self
|
||||||
|
|
||||||
|
from PyQt6 import QtGui
|
||||||
|
from PyQt6.QtCore import QSize, Qt, QTimer
|
||||||
|
from PyQt6.QtGui import QIcon
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QLCDNumber,
|
||||||
|
QMessageBox,
|
||||||
|
QPushButton,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(slots=True, frozen=True)
|
||||||
|
class Cords:
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
|
||||||
|
|
||||||
|
class ButtonType(StrEnum):
|
||||||
|
EMPTY = auto()
|
||||||
|
BOMB = auto()
|
||||||
|
NUMBER = auto()
|
||||||
|
|
||||||
|
|
||||||
|
class Button(QPushButton):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
cords: Cords,
|
||||||
|
handler1: Callable[[Self, bool], Any],
|
||||||
|
handler2: Callable[[Self], Any],
|
||||||
|
) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setFixedSize(50, 50)
|
||||||
|
self.type = ButtonType.EMPTY
|
||||||
|
self.number = 0
|
||||||
|
self.cords = cords
|
||||||
|
self.marked: bool = False
|
||||||
|
self.revealed: bool = False
|
||||||
|
self.left_handler = handler1
|
||||||
|
self.right_handler = handler2
|
||||||
|
|
||||||
|
def reveal(self) -> Iterator[Cords]:
|
||||||
|
self.revealed = True
|
||||||
|
self.setStyleSheet("background-color: grey")
|
||||||
|
if self.type is ButtonType.NUMBER:
|
||||||
|
self.setText(str(self.number))
|
||||||
|
|
||||||
|
def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
|
||||||
|
if e.button() is Qt.MouseButton.LeftButton:
|
||||||
|
self.left_handler(self, True)
|
||||||
|
elif e.button() is Qt.MouseButton.RightButton:
|
||||||
|
self.right_handler(self)
|
||||||
|
|
||||||
|
def get_neighbors(self) -> Iterator[Cords]:
|
||||||
|
for x in range(self.cords.x - 1, self.cords.x + 2):
|
||||||
|
for y in range(self.cords.y - 1, self.cords.y + 2):
|
||||||
|
if x < 0 or x >= 10:
|
||||||
|
continue
|
||||||
|
if y < 0 or y >= 10:
|
||||||
|
continue
|
||||||
|
if Cords(x, y) == self.cords:
|
||||||
|
continue
|
||||||
|
yield Cords(x, y)
|
||||||
|
|
||||||
|
def update_texture(self) -> None:
|
||||||
|
if self.marked:
|
||||||
|
self.setIcon(QIcon("flag.jpg"))
|
||||||
|
self.setIconSize(QSize(50, 50))
|
||||||
|
else:
|
||||||
|
self.setIcon(QIcon())
|
||||||
|
# TODO: remove
|
||||||
|
if self.type is ButtonType.BOMB:
|
||||||
|
self.setStyleSheet("background-color: red")
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.setGeometry(0, 0, 500, 500)
|
||||||
|
self.seconds = 0
|
||||||
|
self.revealed_buttons: set[Cords] = set()
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.timeout.connect(self.show_time)
|
||||||
|
self.timer.setInterval(1000)
|
||||||
|
self.timer.start()
|
||||||
|
self.bomb_amount = 10
|
||||||
|
self.flags_amount = 0
|
||||||
|
self.setWindowTitle("Окно")
|
||||||
|
self.create_buttons()
|
||||||
|
self.select_bombs()
|
||||||
|
|
||||||
|
def create_buttons(self) -> None:
|
||||||
|
vbox = QVBoxLayout()
|
||||||
|
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
self.counter = QLabel(f"{self.flags_amount}/{self.bomb_amount}")
|
||||||
|
finish_button = QPushButton()
|
||||||
|
finish_button.setText("FINISH")
|
||||||
|
finish_button.clicked.connect(self.finish)
|
||||||
|
self.time = QLCDNumber()
|
||||||
|
self.time.setDigitCount(5)
|
||||||
|
self.time.display("00:00")
|
||||||
|
hbox.addWidget(self.counter)
|
||||||
|
hbox.addWidget(finish_button)
|
||||||
|
hbox.addWidget(self.time)
|
||||||
|
|
||||||
|
vbox.addLayout(hbox)
|
||||||
|
|
||||||
|
self.buttons: list[list[Button]] = []
|
||||||
|
for x in range(10):
|
||||||
|
hbox = QHBoxLayout()
|
||||||
|
row = []
|
||||||
|
|
||||||
|
for y in range(10):
|
||||||
|
button = Button(
|
||||||
|
Cords(x, y),
|
||||||
|
self.button_clicked,
|
||||||
|
self.set_flag,
|
||||||
|
)
|
||||||
|
row.append(button)
|
||||||
|
hbox.addWidget(button)
|
||||||
|
|
||||||
|
self.buttons.append(row)
|
||||||
|
vbox.addLayout(hbox)
|
||||||
|
self.setLayout(vbox)
|
||||||
|
|
||||||
|
def select_bombs(self) -> None:
|
||||||
|
buttons = [j for i in self.buttons for j in i]
|
||||||
|
bombs = sample(buttons, self.bomb_amount)
|
||||||
|
for bomb in bombs:
|
||||||
|
bomb.type = ButtonType.BOMB
|
||||||
|
# TODO: remove
|
||||||
|
bomb.setStyleSheet("background-color: red")
|
||||||
|
for bomb in bombs:
|
||||||
|
for cords in bomb.get_neighbors():
|
||||||
|
button = self.buttons[cords.x][cords.y]
|
||||||
|
if button.type is ButtonType.BOMB:
|
||||||
|
continue
|
||||||
|
button.type = ButtonType.NUMBER
|
||||||
|
button.number += 1
|
||||||
|
|
||||||
|
def button_clicked(self, button: Button, user: bool) -> None:
|
||||||
|
if button.cords in self.revealed_buttons:
|
||||||
|
return
|
||||||
|
self.revealed_buttons.add(button.cords)
|
||||||
|
if button.type is ButtonType.BOMB:
|
||||||
|
if user:
|
||||||
|
QMessageBox.warning(self, "You lost", "You lost")
|
||||||
|
self.close()
|
||||||
|
return
|
||||||
|
button.reveal()
|
||||||
|
if button.type is ButtonType.NUMBER:
|
||||||
|
return
|
||||||
|
for cords in button.get_neighbors():
|
||||||
|
neighbor = self.buttons[cords.x][cords.y]
|
||||||
|
self.button_clicked(neighbor, False)
|
||||||
|
|
||||||
|
def set_flag(self, button: Button) -> None:
|
||||||
|
if button.revealed:
|
||||||
|
return
|
||||||
|
was_marked = button.marked
|
||||||
|
button.marked = not was_marked
|
||||||
|
button.update_texture()
|
||||||
|
if was_marked:
|
||||||
|
self.flags_amount -= 1
|
||||||
|
else:
|
||||||
|
self.flags_amount += 1
|
||||||
|
self.counter.setText(f"{self.flags_amount}/{self.bomb_amount}")
|
||||||
|
|
||||||
|
def finish(self) -> None:
|
||||||
|
buttons = [j for i in self.buttons for j in i]
|
||||||
|
bomb = ButtonType.BOMB
|
||||||
|
if not all(button.marked for button in buttons if button.type is bomb):
|
||||||
|
QMessageBox.warning(self, "You lost", "You lost")
|
||||||
|
self.close()
|
||||||
|
return
|
||||||
|
QMessageBox.information(self, "You won", "You won")
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def show_time(self) -> None:
|
||||||
|
self.seconds += 1
|
||||||
|
minutes, seconds = divmod(self.seconds, 60)
|
||||||
|
self.time.display(f"{minutes:0>2}:{seconds:0>2}")
|
||||||
|
if minutes >= 5:
|
||||||
|
QMessageBox.warning(self, "You lost", "You lost")
|
||||||
|
self.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = Window()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
419
Python/sql/main.py
Executable file
419
Python/sql/main.py
Executable file
@ -0,0 +1,419 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
from psycopg2 import extensions
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QApplication,
|
||||||
|
QHBoxLayout,
|
||||||
|
QLabel,
|
||||||
|
QLineEdit,
|
||||||
|
QMessageBox,
|
||||||
|
QPushButton,
|
||||||
|
QTableWidget,
|
||||||
|
QTableWidgetItem,
|
||||||
|
QVBoxLayout,
|
||||||
|
QWidget,
|
||||||
|
)
|
||||||
|
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
|
||||||
|
from cryptography.exceptions import InvalidKey
|
||||||
|
|
||||||
|
|
||||||
|
def get_kdf(salt: bytes) -> Scrypt:
|
||||||
|
return Scrypt(salt, length=128, n=2**14, r=8, p=1)
|
||||||
|
|
||||||
|
|
||||||
|
def encrypt(password: str) -> bytes:
|
||||||
|
salt = os.urandom(64)
|
||||||
|
return (salt, get_kdf(salt).derive(password.encode("UTF-8")))
|
||||||
|
|
||||||
|
|
||||||
|
def check_password(password: str, salt: bytes, expected: bytes) -> bool:
|
||||||
|
try:
|
||||||
|
get_kdf(salt).verify(password.encode("UTF-8"), expected)
|
||||||
|
except InvalidKey:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
Student = tuple[int, str, str, str]
|
||||||
|
|
||||||
|
HOST = "127.0.0.1"
|
||||||
|
USER = "tester"
|
||||||
|
PASSWORD = "example123!"
|
||||||
|
PORT = 5432
|
||||||
|
DATABASE = "testing"
|
||||||
|
|
||||||
|
|
||||||
|
class Connection:
|
||||||
|
connection: Optional[extensions.connection] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get(cls) -> extensions.connection:
|
||||||
|
if cls.connection is not None:
|
||||||
|
return cls.connection
|
||||||
|
try:
|
||||||
|
cls.connection = psycopg2.connect(
|
||||||
|
host=HOST, user=USER, password=PASSWORD, database=DATABASE
|
||||||
|
)
|
||||||
|
cls.connection.autocommit = True
|
||||||
|
except Exception as e:
|
||||||
|
print(type(e))
|
||||||
|
raise
|
||||||
|
return cls.connection
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def close(cls) -> None:
|
||||||
|
if cls.connection is not None:
|
||||||
|
cls.connection.close()
|
||||||
|
cls.connection = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_all_data(cls) -> list[Student]:
|
||||||
|
with cls.get().cursor() as cursor:
|
||||||
|
cursor.execute("SELECT * FROM students ORDER BY id")
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_user(cls, login: str) -> Optional[tuple[bytes, bytes]]:
|
||||||
|
with cls.get().cursor() as cursor:
|
||||||
|
cursor.execute(
|
||||||
|
"SELECT salt, password, admin FROM users WHERE login = %s",
|
||||||
|
(login,),
|
||||||
|
)
|
||||||
|
result = cursor.fetchone()
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
return (bytes(result[0]), bytes(result[1]), result[2])
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_database() -> None:
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
cursor.execute("DROP TABLE IF EXISTS students")
|
||||||
|
cursor.execute(
|
||||||
|
"CREATE TABLE students("
|
||||||
|
"id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,"
|
||||||
|
"surname VARCHAR(255),"
|
||||||
|
"name VARCHAR(255),"
|
||||||
|
"group_ VARCHAR(255))"
|
||||||
|
)
|
||||||
|
cursor.execute("DROP TABLE IF EXISTS users")
|
||||||
|
cursor.execute(
|
||||||
|
"CREATE TABLE users("
|
||||||
|
"id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,"
|
||||||
|
"login VARCHAR(255),"
|
||||||
|
"salt BYTEA,"
|
||||||
|
"password BYTEA,"
|
||||||
|
"admin BOOLEAN)"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def add_test_data() -> None:
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO STUDENTS(name, surname, group_) VALUES "
|
||||||
|
"('Nick', 'Stepanov', 'programmer'),"
|
||||||
|
"('Maxim', 'Yes', 'programmer')"
|
||||||
|
)
|
||||||
|
admin_creds = encrypt("admin")
|
||||||
|
user_creds = encrypt("example123!")
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO users(login, salt, password, admin) VALUES "
|
||||||
|
"('admin', %s, %s, true),"
|
||||||
|
"('user', %s, %s, false)",
|
||||||
|
(*admin_creds, *user_creds),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Window(QWidget):
|
||||||
|
def __init__(self, is_admin: bool):
|
||||||
|
super().__init__()
|
||||||
|
self.is_admin = is_admin
|
||||||
|
self.setGeometry(200, 200, 700, 400)
|
||||||
|
self.setWindowTitle("SQL Test")
|
||||||
|
self.vbox = QVBoxLayout()
|
||||||
|
self.setLayout(self.vbox)
|
||||||
|
self.need_clean = []
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def update(self, data: Optional[list[Student]] = None):
|
||||||
|
self.clean_widgets()
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
data = Connection.get_all_data()
|
||||||
|
|
||||||
|
hbox_buttons = QHBoxLayout()
|
||||||
|
but1 = QPushButton("Create")
|
||||||
|
but1.clicked.connect(self.button_create_handler)
|
||||||
|
but2 = QPushButton("Edit")
|
||||||
|
but2.clicked.connect(self.button_edit_handler)
|
||||||
|
but3 = QPushButton("Remove")
|
||||||
|
but3.clicked.connect(self.button_remove_handler)
|
||||||
|
but4 = QPushButton("Find")
|
||||||
|
but4.clicked.connect(self.button_find_handler)
|
||||||
|
hbox_buttons.addWidget(but1)
|
||||||
|
hbox_buttons.addWidget(but2)
|
||||||
|
hbox_buttons.addWidget(but3)
|
||||||
|
hbox_buttons.addWidget(but4)
|
||||||
|
self.add_widget_to_need_clean(but1, but2, but3, but4)
|
||||||
|
|
||||||
|
hbox_id = QHBoxLayout()
|
||||||
|
label_id = QLabel("ID")
|
||||||
|
self.text_id = QLineEdit()
|
||||||
|
hbox_id.addWidget(label_id)
|
||||||
|
hbox_id.addWidget(self.text_id)
|
||||||
|
self.add_widget_to_need_clean(hbox_id, label_id, self.text_id)
|
||||||
|
|
||||||
|
hbox_surname = QHBoxLayout()
|
||||||
|
label_surname = QLabel("Surname")
|
||||||
|
self.text_surname = QLineEdit()
|
||||||
|
hbox_surname.addWidget(label_surname)
|
||||||
|
hbox_surname.addWidget(self.text_surname)
|
||||||
|
self.add_widget_to_need_clean(
|
||||||
|
hbox_surname,
|
||||||
|
label_surname,
|
||||||
|
self.text_surname,
|
||||||
|
)
|
||||||
|
|
||||||
|
hbox_name = QHBoxLayout()
|
||||||
|
label_name = QLabel("Name")
|
||||||
|
self.text_name = QLineEdit()
|
||||||
|
hbox_name.addWidget(label_name)
|
||||||
|
hbox_name.addWidget(self.text_name)
|
||||||
|
self.add_widget_to_need_clean(hbox_name, label_name, self.text_name)
|
||||||
|
|
||||||
|
hbox_group = QHBoxLayout()
|
||||||
|
label_group = QLabel("Group")
|
||||||
|
self.text_group = QLineEdit()
|
||||||
|
hbox_group.addWidget(label_group)
|
||||||
|
hbox_group.addWidget(self.text_group)
|
||||||
|
self.add_widget_to_need_clean(hbox_group, label_group, self.text_group)
|
||||||
|
|
||||||
|
hbox_table = QHBoxLayout()
|
||||||
|
table = self.form_table(data)
|
||||||
|
hbox_table.addWidget(table)
|
||||||
|
self.add_widget_to_need_clean(table)
|
||||||
|
|
||||||
|
self.vbox.addLayout(hbox_id)
|
||||||
|
self.vbox.addLayout(hbox_surname)
|
||||||
|
self.vbox.addLayout(hbox_name)
|
||||||
|
self.vbox.addLayout(hbox_group)
|
||||||
|
self.vbox.addLayout(hbox_buttons)
|
||||||
|
self.vbox.addLayout(hbox_table)
|
||||||
|
|
||||||
|
def add_widget_to_need_clean(self, *args):
|
||||||
|
for el in args:
|
||||||
|
self.need_clean.append(el)
|
||||||
|
|
||||||
|
def clean_widgets(self):
|
||||||
|
if self.need_clean:
|
||||||
|
for widget in self.need_clean:
|
||||||
|
widget.deleteLater()
|
||||||
|
self.need_clean.clear()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def form_table(data: list[Student]) -> QTableWidget:
|
||||||
|
table = QTableWidget()
|
||||||
|
table.setRowCount(10)
|
||||||
|
table.setColumnCount(4)
|
||||||
|
table.setHorizontalHeaderLabels(("ID", "Surname", "Name", "Group"))
|
||||||
|
for i, row in enumerate(data):
|
||||||
|
for j, column in enumerate(map(str, row)):
|
||||||
|
table.setItem(i, j, QTableWidgetItem(column))
|
||||||
|
return table
|
||||||
|
|
||||||
|
def button_edit_handler(self):
|
||||||
|
if not self.is_admin:
|
||||||
|
return QMessageBox().warning(
|
||||||
|
self, "Rights", "You have to be an admin to do that"
|
||||||
|
)
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
cursor.execute("SELECT * FROM students;")
|
||||||
|
students = cursor.fetchall()
|
||||||
|
indexes = []
|
||||||
|
for student in students:
|
||||||
|
indexes.append(str(student[0]))
|
||||||
|
if self.text_id.text() in indexes:
|
||||||
|
commands = []
|
||||||
|
if self.text_surname.text() != "":
|
||||||
|
commands.append(
|
||||||
|
"UPDATE students SET surname = '"
|
||||||
|
+ self.text_surname.text()
|
||||||
|
+ "' "
|
||||||
|
+ "WHERE id = "
|
||||||
|
+ self.text_id.text()
|
||||||
|
+ ";"
|
||||||
|
)
|
||||||
|
if self.text_name.text() != "":
|
||||||
|
commands.append(
|
||||||
|
"UPDATE students SET name = '"
|
||||||
|
+ self.text_name.text()
|
||||||
|
+ "' "
|
||||||
|
+ "WHERE id = "
|
||||||
|
+ self.text_id.text()
|
||||||
|
+ ";"
|
||||||
|
)
|
||||||
|
if self.text_group.text() != "":
|
||||||
|
commands.append(
|
||||||
|
"UPDATE students SET gr = '"
|
||||||
|
+ self.text_group.text()
|
||||||
|
+ "' "
|
||||||
|
+ "WHERE id = "
|
||||||
|
+ self.text_id.text()
|
||||||
|
+ ";"
|
||||||
|
)
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
for command in commands:
|
||||||
|
cursor.execute(command)
|
||||||
|
QMessageBox.information(self, "Info", "Data changed")
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(self, "Error", "Data not changed")
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def button_create_handler(self):
|
||||||
|
if not self.is_admin:
|
||||||
|
return QMessageBox().warning(
|
||||||
|
self, "Rights", "You have to be an admin to do that"
|
||||||
|
)
|
||||||
|
name = self.text_name.text()
|
||||||
|
surname = self.text_surname.text()
|
||||||
|
group = self.text_group.text()
|
||||||
|
if not all((surname, name, group)):
|
||||||
|
QMessageBox.warning(self, "Invalid id", "Invalid id")
|
||||||
|
return
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO students(name, surname, group_) VALUES (%s, %s, %s)", # noqa
|
||||||
|
(name, surname, group),
|
||||||
|
)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def button_remove_handler(self) -> None:
|
||||||
|
if not self.is_admin:
|
||||||
|
return QMessageBox().warning(
|
||||||
|
self, "Rights", "You have to be an admin to do that"
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
id = int(self.text_id.text())
|
||||||
|
except ValueError:
|
||||||
|
QMessageBox.warning(self, "Invalid ID", "Invalid ID")
|
||||||
|
return
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
cursor.execute("DELETE FROM students WHERE id = %s", (id,))
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def button_find_handler(self) -> None:
|
||||||
|
id = self.text_id.text()
|
||||||
|
name = self.text_name.text()
|
||||||
|
surname = self.text_surname.text()
|
||||||
|
group = self.text_group.text()
|
||||||
|
filters = []
|
||||||
|
params = []
|
||||||
|
if id:
|
||||||
|
if not id.isnumeric():
|
||||||
|
QMessageBox.warning(self, "Invalid id", "Invalid id")
|
||||||
|
return
|
||||||
|
filters.append("id = %s")
|
||||||
|
params.append(id)
|
||||||
|
if name:
|
||||||
|
filters.append("LOWER(name) ~ %s")
|
||||||
|
params.append(name.lower())
|
||||||
|
if surname:
|
||||||
|
filters.append("LOWER(surname) ~ %s")
|
||||||
|
params.append(surname.lower())
|
||||||
|
if group:
|
||||||
|
filters.append("LOWER(group_) ~ %s")
|
||||||
|
params.append(group.lower())
|
||||||
|
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
if not params:
|
||||||
|
filters = ""
|
||||||
|
else:
|
||||||
|
filters = f" WHERE {' AND '.join(filters)}"
|
||||||
|
query = f"SELECT * FROM students{filters} ORDER BY id"
|
||||||
|
cursor.execute(query, params)
|
||||||
|
data = cursor.fetchall()
|
||||||
|
self.update(data)
|
||||||
|
|
||||||
|
|
||||||
|
class WindowPW(QWidget):
|
||||||
|
def __init__(self) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self.loged_in = False
|
||||||
|
self.is_admin = False
|
||||||
|
self.setGeometry(200, 200, 250, 150)
|
||||||
|
self.setWindowTitle("Login")
|
||||||
|
label = QLabel("Name", self)
|
||||||
|
label.move(10, 10)
|
||||||
|
self.line_login = QLineEdit(self)
|
||||||
|
self.line_login.move(100, 10)
|
||||||
|
label_pw = QLabel("password", self)
|
||||||
|
label_pw.move(10, 50)
|
||||||
|
self.line_pw = QLineEdit(self)
|
||||||
|
self.line_pw.move(100, 50)
|
||||||
|
register_but = QPushButton("Register", self)
|
||||||
|
register_but.move(25, 100)
|
||||||
|
register_but.clicked.connect(self.register_handler)
|
||||||
|
but = QPushButton("OK", self)
|
||||||
|
but.clicked.connect(self.but_handler)
|
||||||
|
but.move(100, 100)
|
||||||
|
|
||||||
|
def but_handler(self) -> None:
|
||||||
|
login = self.line_login.text().strip()
|
||||||
|
password = self.line_pw.text().strip()
|
||||||
|
user = Connection.get_user(login)
|
||||||
|
if user is None:
|
||||||
|
self.close()
|
||||||
|
return QMessageBox.warning(self, "Bye!", "Wrong creds")
|
||||||
|
salt, expected, admin = Connection.get_user(login)
|
||||||
|
if check_password(password, salt, expected):
|
||||||
|
self.loged_in = True
|
||||||
|
self.is_admin = admin
|
||||||
|
else:
|
||||||
|
QMessageBox.warning(self, "Bye!", "Wrong creds")
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
def register_handler(self) -> None:
|
||||||
|
login = self.line_login.text().strip()
|
||||||
|
password = self.line_pw.text().strip()
|
||||||
|
if not (login and password):
|
||||||
|
return QMessageBox().warning(
|
||||||
|
self, "Wrong creds", "You must input both login and password"
|
||||||
|
)
|
||||||
|
with Connection.get().cursor() as cursor:
|
||||||
|
cursor.execute(
|
||||||
|
"SELECT true FROM users WHERE login = %s LIMIT 1",
|
||||||
|
(login,),
|
||||||
|
)
|
||||||
|
if cursor.fetchone() is not None:
|
||||||
|
return QMessageBox().warning(
|
||||||
|
self, "Wrong creds", "Login already exists"
|
||||||
|
)
|
||||||
|
cursor.execute(
|
||||||
|
"INSERT INTO users(login, salt, password) VALUES (%s, %s, %s)",
|
||||||
|
(login, *encrypt(password)),
|
||||||
|
)
|
||||||
|
self.loged_in = True
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
prepare_database()
|
||||||
|
add_test_data()
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = WindowPW()
|
||||||
|
window.show()
|
||||||
|
result = app.exec()
|
||||||
|
if not window.loged_in:
|
||||||
|
sys.exit(result)
|
||||||
|
window = Window(window.is_admin)
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Reference in New Issue
Block a user