Added missing files and removed unnessesary ones
This commit is contained in:
1 parent
c3fa5367c3
commit
199dd693e4
41 files changed
+1442
-50
No files matched your search
Executable
+37
@@ -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()
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 347 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
Executable
+21
@@ -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()
|
||||
Executable
+61
@@ -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()
|
||||
Executable
+31
@@ -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()
|
||||
Executable
+31
@@ -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()
|
||||
Executable
+27
@@ -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()
|
||||
Executable
+32
@@ -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()
|
||||
Executable
+32
@@ -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()
|
||||
Executable
+63
@@ -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()
|
||||
Executable
+68
@@ -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()
|
||||
Executable
+70
@@ -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()
|
||||
Executable
Whitespace-only changes.
Executable
Whitespace-only changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Executable
+207
@@ -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()
|
||||
Executable
+419
@@ -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