Guest User

Untitled

a guest
May 31st, 2018
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.68 KB | None | 0 0
  1. #!/usr/bin/env ipython
  2. # coding: utf-8
  3. from PyQt5 import QtCore, QtWidgets, QtGui
  4. import sys, math, os, time, re, sqlite3, hashlib
  5.  
  6.  
  7. class User:
  8.  
  9. def __init__(self, db, login: str):
  10. self.db = db
  11. self.login = login
  12. self.password = hashlib.md5().hexdigest()
  13. self.upload()
  14.  
  15. def setLogin(self, newLogin: str):
  16. self.login = newLogin
  17.  
  18. def setPassword(self, newPassword: str):
  19. self.password = str(newPassword)
  20.  
  21. def setAvatar(self, newAvatar: str) -> bool:
  22. try:
  23. self.avatarUrl = newAvatar
  24. pixAvatar = QtGui.QPixmap('Avatars/' + self.avatarUrl)
  25. self.avatar = QtGui.QIcon(pixAvatar)
  26. return True
  27. except:
  28. return False
  29.  
  30. def registerUser(self) -> int:
  31. self.userId = self.db.registerUser(self)
  32. return self.userId
  33.  
  34. def upload(self) -> bool:
  35. if self.db.userIsRegistered(self):
  36. try:
  37. self.db.cursor.execute("SELECT `user_id`, `user_password`, `user_avatar`, `user_progress` FROM `users` WHERE `user_login` = '{}'".format(self.login))
  38. row = self.db.cursor.fetchone()
  39. self.userId = row[0]
  40. self.password = row[1]
  41. self.setAvatar(row[2])
  42. self.progress = row[3]
  43. return True
  44. finally:
  45. pass
  46. return False
  47.  
  48. def deleteUser(self):
  49. self.db.deleteUser(self)
  50. self.__del__()
  51.  
  52.  
  53. class Database():
  54. users = list()
  55.  
  56. def __init__(self, statusBar: QtWidgets.QStatusBar, progressBar: QtWidgets.QProgressBar, enterWindow):
  57. self.statusBar = statusBar
  58. self.progressBar = progressBar
  59. self.enterWindow = enterWindow
  60.  
  61. self.progressBar.setValue(0)
  62. self.statusBar.showMessage("Подключение к базе данных...")
  63. self.connection = sqlite3.connect("nn.db")
  64. self.cursor = self.connection.cursor()
  65.  
  66. self.progressBar.setValue(self.progressBar.maximum() * (1 / 7))
  67.  
  68. self.statusBar.showMessage("Сканирование имеющихся таблиц...")
  69. self.cursor.execute("SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'")
  70. existingTables = tuple(map(lambda row: row[0], self.cursor.fetchall()))
  71. self.progressBar.setValue(self.progressBar.maximum() * (2 / 7))
  72. if "users" not in existingTables:
  73. self.statusBar.showMessage("Создание таблицы users...")
  74. self.cursor.execute("CREATE TABLE `users` ("
  75. "`user_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
  76. "`user_login` TEXT DEFAULT '' UNIQUE,"
  77. "`user_password` TEXT DEFAULT '" + hashlib.md5().hexdigest() + "',"
  78. "`user_avatar` TEXT DEFAULT '001-man-13.png',"
  79. "`user_progress` REAL DEFAULT 0.0"
  80. ")")
  81. self.progressBar.setValue(self.progressBar.maximum() * (3 / 7))
  82. if "saves" not in existingTables:
  83. self.statusBar.showMessage("Создание таблицы saves...")
  84. self.cursor.execute("CREATE TABLE `saves` ("
  85. "`user_id` INTEGER NOT NULL,"
  86. "`type` TEXT DEFAULT '',"
  87. "`data` TEXT DEFAULT '',"
  88. "`course_id` INTEGER NOT NULL,"
  89. "`exercise_id` INTEGER NULL,"
  90. "FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`) "
  91. "ON DELETE CASCADE "
  92. "ON UPDATE CASCADE"
  93. ")")
  94. self.progressBar.setValue(self.progressBar.maximum() * (4 / 7))
  95. if "courses" not in existingTables:
  96. self.statusBar.showMessage("Создание таблицы courses...")
  97. self.cursor.execute("CREATE TABLE `courses` ("
  98. "`course_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
  99. "`face` TEXT DEFAULT 'book.png',"
  100. "`author` TEXT DEFAULT 'Пользователь',"
  101. "`title` TEXT DEFAULT '',"
  102. "`description` TEXT DEFAULT ''"
  103. ")")
  104. self.progressBar.setValue(self.progressBar.maximum() * (5 / 7))
  105. if "pages" not in existingTables:
  106. self.statusBar.showMessage("Создание таблицы pages...")
  107. self.cursor.execute("CREATE TABLE `pages` ("
  108. "`course_id` INTEGER NOT NULL,"
  109. "`page` INTEGER DEFAULT 1,"
  110. "`group` INTEGER NOT NULL,"
  111. "`title` TEXT DEFAULT '',"
  112. "`data` TEXT DEFAULT '',"
  113. "FOREIGN KEY (`course_id`) REFERENCES `courses`(`course_id`) "
  114. "ON DELETE CASCADE "
  115. "ON UPDATE CASCADE"
  116. ")")
  117. self.progressBar.setValue(self.progressBar.maximum() * (6 / 7))
  118. if "exercises" not in existingTables:
  119. self.statusBar.showMessage("Создание таблицы exercises...")
  120. self.cursor.execute("CREATE TABLE `exercises` ("
  121. "`exercise_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
  122. "`course_id` INTEGER NOT NULL,"
  123. "`page` INTEGER NOT NULL,"
  124. "`group` INTEGER NOT NULL,"
  125. "`description` TEXT DEFAULT '',"
  126. "`type` TEXT DEFAULT '',"
  127. "`data` TEXT DEFAULT '',"
  128. "FOREIGN KEY (`course_id`) REFERENCES `courses`(`course_id`)"
  129. "ON DELETE CASCADE "
  130. "ON UPDATE CASCADE"
  131. ")")
  132. self.progressBar.setValue(self.progressBar.maximum())
  133. self.uploadExistsUsers()
  134.  
  135. def __del__(self):
  136. try:
  137. self.cursor.close()
  138. self.connection.close()
  139. except:
  140. pass
  141.  
  142. def offerToEnter(self):
  143. self.enterWindow.show()
  144.  
  145. def uploadExistsUsers(self):
  146. self.progressBar.setValue(0)
  147. self.statusBar.showMessage("Загрузка пользователей...")
  148. self.cursor.execute("SELECT `user_login` FROM `users`")
  149. rows = self.cursor.fetchall()
  150. l = len(rows)
  151. for i in range(l):
  152. foundedUser = User(self, rows[i][0])
  153. self.users.append(foundedUser)
  154. self.progressBar.setValue(self.progressBar.maximum() * (i + 1) / l)
  155. self.progressBar.setValue(self.progressBar.maximum())
  156.  
  157. def userIsRegistered(self, user: User) -> bool:
  158. self.cursor.execute("SELECT `user_login` FROM `users`")
  159. rows = self.cursor.fetchall()
  160. for row in rows:
  161. if row[0] == user.login:
  162. return True
  163. return False
  164.  
  165. def registerUser(self, user: User) -> int:
  166. try:
  167. if not self.userIsRegistered(user):
  168. self.users.append(user)
  169. self.cursor.execute("INSERT INTO `users` (`user_login`, `user_password`, `user_avatar`) VALUES ('{}', '{}', '{}')".format(user.login, user.password, user.avatarUrl))
  170. else:
  171. self.cursor.execute("UPDATE `users` SET `user_password` = '{}', `user_avatar` = '{}' WHERE `user_login` = '{}'".format(user.password, user.avatarUrl, user.login))
  172. self.connection.commit()
  173. user.upload()
  174. return user.userId
  175. finally:
  176. return -1
  177.  
  178. def deleteUser(self, user: User) -> bool:
  179. try:
  180. if self.userIsRegistered(user):
  181. self.users.remove(user)
  182. self.cursor.execute("DELETE FROM `users` WHERE `user_login` = '{}'".format(user.login))
  183. self.connection.commit()
  184. return True
  185. finally:
  186. return False
  187.  
  188.  
  189. loginRegExp = QtCore.QRegExp(r"[a-zA-Zа-яА-Я\_\$][a-zA-Zа-яА-Я\_\$\-0-9]*")
  190. currentUser = None
  191. mainFrame = None
  192.  
  193.  
  194. class StyledLabel(QtWidgets.QLabel):
  195.  
  196. def __init__(self, line: str="", parent=None):
  197. super().__init__(line, parent)
  198.  
  199.  
  200. class RegistrationWindow(QtWidgets.QWidget):
  201.  
  202. def __init__(self, enterWindow):
  203. super().__init__()
  204. self.setWindowTitle("Регистрация")
  205. self.enterWindow = enterWindow
  206. self.newLogin = enterWindow.loginEdit.text()
  207.  
  208. self.vbox = QtWidgets.QVBoxLayout(self)
  209. self.hbox1 = QtWidgets.QHBoxLayout()
  210. self.hbox2 = QtWidgets.QHBoxLayout()
  211. self.hbox3 = QtWidgets.QHBoxLayout()
  212. self.buttonGo = QtWidgets.QPushButton("Зарегистрироваться")
  213. self.buttonGo.clicked.connect(self.register)
  214. self.label1 = StyledLabel("Аватар:")
  215. self.label1.setFixedWidth(96)
  216. self.label1.setAlignment(QtCore.Qt.AlignRight)
  217. self.label2 = StyledLabel("Логин:")
  218. self.label2.setFixedWidth(96)
  219. self.label2.setAlignment(QtCore.Qt.AlignRight)
  220. self.label3 = StyledLabel("Пароль:")
  221. self.label3.setFixedWidth(96)
  222. self.label3.setAlignment(QtCore.Qt.AlignRight)
  223. self.lineEdit = QtWidgets.QLineEdit()
  224. self.lineEdit.setValidator(QtGui.QRegExpValidator(loginRegExp))
  225. self.lineEdit.setMaxLength(50)
  226. self.avatarsBox = QtWidgets.QComboBox()
  227. self.avatarsBox.setIconSize(QtCore.QSize(48, 48))
  228. pixList = os.listdir("Avatars")
  229. pixList.sort()
  230. for pixName in pixList:
  231. self.avatarsBox.addItem(QtGui.QIcon("Avatars/" + pixName), pixName)
  232. self.pwdEdit = QtWidgets.QLineEdit()
  233. self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)
  234. self.pwdEdit.setMaxLength(32)
  235. self.buttonShowPassword = QtWidgets.QCheckBox()
  236. self.buttonShowPassword.stateChanged.connect(self.checked)
  237.  
  238. self.hbox1.addWidget(self.label1)
  239. self.hbox1.addWidget(self.avatarsBox)
  240. self.hbox2.addWidget(self.label2)
  241. self.hbox2.addWidget(self.lineEdit)
  242. self.hbox3.addWidget(self.label3)
  243. self.hbox3.addWidget(self.pwdEdit)
  244. self.hbox3.addWidget(self.buttonShowPassword)
  245. self.vbox.addLayout(self.hbox1)
  246. self.vbox.addLayout(self.hbox2)
  247. self.vbox.addLayout(self.hbox3)
  248. self.vbox.addWidget(self.buttonGo)
  249.  
  250. def checked(self, newState):
  251. if newState == QtCore.Qt.Checked:
  252. self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Normal)
  253. else:
  254. self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)
  255.  
  256. def showEvent(self, event):
  257. global db
  258. db.statusBar.showMessage("Регистрация пользователя...")
  259. self.desktop = QtWidgets.QApplication.desktop()
  260. x = (self.desktop.width() - self.width()) // 2
  261. y = (self.desktop.height() - self.height()) // 2
  262. self.move(x, y)
  263.  
  264. def register(self):
  265. global db
  266. newUser = User(db, self.lineEdit.text())
  267. newUser.setAvatar(self.avatarsBox.currentText())
  268. newUser.setPassword(hashlib.md5(self.pwdEdit.text().encode()).hexdigest())
  269. db.registerUser(newUser)
  270. self.hide()
  271. self.enterWindow.uploadUsers()
  272. self.enterWindow.show()
  273.  
  274.  
  275. class UsersListItem(QtWidgets.QListWidgetItem):
  276.  
  277. def __init__(self, user: User, parent=None):
  278. super().__init__(parent)
  279. self.user = user
  280. self.setSizeHint(QtCore.QSize(0, 64))
  281.  
  282. def updateItem(self):
  283. self.user.upload()
  284. self.setIcon(self.user.avatar)
  285. self.setText("{0}\nПрогресс: {1: >5.1f}%\n{2:\u25CB<10}".format(self.user.login, int(self.user.progress * 10) / 10.0, "\u25CF" * int(self.user.progress // 10)))
  286.  
  287. def updateUser(self, newUser: User):
  288. self.user = newUser
  289. self.updateItem()
  290.  
  291.  
  292. class UsersList(QtWidgets.QListWidget):
  293. selectedItem = None
  294. autoSelect = False
  295.  
  296. def __init__(self, enterWindow=None):
  297. super().__init__(enterWindow)
  298. self.enterWindow = enterWindow
  299. self.setSortingEnabled(True)
  300. self.setAlternatingRowColors(True)
  301. self.setIconSize(QtCore.QSize(48, 48))
  302. self.itemSelectionChanged.connect(self.itemIsSelected)
  303. self.itemClicked.connect(self.itemIsClicked)
  304.  
  305. def updateList(self, enteredLogin: str=""):
  306. global db
  307. self.clear()
  308. if enteredLogin == "":
  309. for user in db.users:
  310. item = UsersListItem(user)
  311. item.updateItem()
  312. self.addItem(item)
  313. else:
  314. enteredLogin = enteredLogin.lower()
  315. for user in db.users:
  316. if user.login.lower().find(enteredLogin) != -1:
  317. item = UsersListItem(user)
  318. item.updateItem()
  319. self.addItem(item)
  320. if user is db.users[0]:
  321. self.autoSelect = True
  322. item.setSelected(True)
  323. self.autoSelect = False
  324.  
  325. def itemIsSelected(self):
  326. if len(self.selectedItems()) > 0:
  327. self.selectedItem = self.selectedItems()[0]
  328. if not self.autoSelect:
  329. self.enterWindow.loginEdit.setText(self.selectedItem.user.login)
  330. self.enterWindow.loginEdit.setFocus(True)
  331.  
  332. def itemIsClicked(self, clickedItem):
  333. if len(self.selectedItems()) > 0:
  334. self.selectedItem = self.selectedItems()[0]
  335. self.enterWindow.loginEdit.setText(self.selectedItem.user.login)
  336. self.enterWindow.loginEdit.setFocus(True)
  337.  
  338. def deleteItem(self, item: UsersListItem):
  339. try:
  340. self.removeItemWidget(item)
  341. item.user.deleteUser()
  342. finally:
  343. return
  344.  
  345.  
  346.  
  347. class EnterWindow(QtWidgets.QWidget):
  348.  
  349. def __init__(self):
  350. super().__init__()
  351. self.setWindowTitle("Вход")
  352.  
  353. self.vbox = QtWidgets.QVBoxLayout(self)
  354. self.loginEdit = QtWidgets.QLineEdit()
  355. self.loginEdit.setObjectName("loginEdit")
  356. self.loginEdit.setPlaceholderText("Введите логин")
  357. self.loginEdit.setValidator(QtGui.QRegExpValidator(loginRegExp))
  358. self.loginEdit.textChanged.connect(self.loginChanged)
  359. self.vbox.addWidget(self.loginEdit)
  360.  
  361. self.usersList = UsersList(self)
  362. self.vbox.addWidget(self.usersList)
  363.  
  364. self.hbox = QtWidgets.QHBoxLayout()
  365. self.pwdEdit = QtWidgets.QLineEdit()
  366. self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)
  367. self.pwdEdit.setMaxLength(32)
  368. self.pwdEdit.setPlaceholderText("Введите пароль")
  369. self.hbox.addWidget(self.pwdEdit)
  370. self.buttonShowPassword = QtWidgets.QCheckBox()
  371. self.buttonShowPassword.stateChanged.connect(self.checked)
  372. self.hbox.addWidget(self.buttonShowPassword)
  373. self.vbox.addLayout(self.hbox)
  374.  
  375. self.buttonGo = QtWidgets.QPushButton("Войти")
  376. self.buttonGo.clicked.connect(self.enterUser)
  377. self.vbox.addWidget(self.buttonGo)
  378.  
  379. self.buttonNew = QtWidgets.QPushButton("Новый пользователь")
  380. self.buttonNew.clicked.connect(self.createUser)
  381. self.vbox.addWidget(self.buttonNew)
  382.  
  383. self.buttonDelete = QtWidgets.QPushButton("Удалить пользователя")
  384. self.buttonDelete.clicked.connect(self.deleteUser)
  385. self.vbox.addWidget(self.buttonDelete)
  386.  
  387. def checked(self, newState):
  388. if newState == QtCore.Qt.Checked:
  389. self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Normal)
  390. else:
  391. self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)
  392.  
  393. def showEvent(self, event):
  394. global db
  395. db.statusBar.showMessage("Выбор пользователя...")
  396. self.desktop = QtWidgets.QApplication.desktop()
  397. x = (self.desktop.width() - self.width()) // 2
  398. y = (self.desktop.height() - self.height()) // 2
  399. self.move(x, y)
  400.  
  401. def uploadUsers(self):
  402. self.usersList.updateList()
  403.  
  404. def loginChanged(self, enteredLogin):
  405. self.usersList.updateList(enteredLogin)
  406. if self.usersList.count() > 0 and len(enteredLogin) > 0:
  407. self.usersList.autoSelect = True
  408. self.usersList.item(0).setSelected(True)
  409. self.usersList.autoSelect = False
  410.  
  411. def enterUser(self):
  412. if self.usersList.selectedItem is None:
  413. QtWidgets.QMessageBox.warning(self, "Ошибка", "Выберите пользователя.")
  414. else:
  415. pwd = hashlib.md5(self.pwdEdit.text().encode()).hexdigest()
  416. if pwd == self.usersList.selectedItem.user.password:
  417. global db, currentUser, mainFrame
  418. currentUser = self.usersList.selectedItem.user
  419. self.hide()
  420. mainFrame.menuBar.setEnabled(True)
  421. db.statusBar.showMessage("Добро пожаловать, {0:s}!".format(currentUser.login))
  422. mainFrame.reloadChoiceList()
  423. mainFrame.reloadUser()
  424. else:
  425. QtWidgets.QMessageBox.warning(self, "Ошибка", "Вы ввели неверный пароль пользователя.")
  426.  
  427. def closeEvent(self, event):
  428. global currentUser
  429. if currentUser is None:
  430. QtWidgets.QApplication.quit()
  431. else:
  432. event.accept()
  433.  
  434. def createUser(self):
  435. self.hide()
  436. self.registrationWindow = RegistrationWindow(self)
  437. self.registrationWindow.show()
  438.  
  439. def deleteUser(self):
  440. try:
  441. global db
  442. user = self.usersList.selectedItem.user
  443. if db.userIsRegistered(user):
  444. self.usersList.deleteItem(self.usersList.selectedItem)
  445. self.usersList.updateList()
  446. self.loginEdit.setText("")
  447. finally:
  448. return
  449.  
  450.  
  451. class ProgressBar(QtWidgets.QProgressBar):
  452. progressBarBrightText = False
  453.  
  454. def __init__(self, parent=None):
  455. super().__init__(parent)
  456. self.valueChanged.connect(self.loadingUpdate)
  457.  
  458. def loadingUpdate(self, value):
  459. self.setFormat("{0:d}%".format(int(self.value() * 100 / self.maximum())))
  460. if value * 2 < self.maximum() + self.fontMetrics().width(self.format()) and self.progressBarBrightText:
  461. self.setStyleSheet("color: rgb(32, 32, 32);")
  462. self.progressBarBrightText = False
  463. elif value * 2 >= self.maximum() + self.fontMetrics().width(self.format()) and not self.progressBarBrightText:
  464. self.setStyleSheet("color: white;")
  465. self.progressBarBrightText = True
  466.  
  467.  
  468. class ProgressBarF(QtWidgets.QProgressBar):
  469. progressBarBrightText = False
  470.  
  471. def __init__(self, parent=None):
  472. super().__init__(parent)
  473. self.valueChanged.connect(self.loadingUpdate)
  474.  
  475. def loadingUpdate(self, value):
  476. self.setFormat("{0:.2f}%".format(self.value() * 100 / self.maximum()))
  477. if value * 2 < self.maximum() + self.fontMetrics().width(self.format()) and self.progressBarBrightText:
  478. self.setStyleSheet("color: rgb(32, 32, 32);")
  479. self.progressBarBrightText = False
  480. elif value * 2 >= self.maximum() + self.fontMetrics().width(self.format()) and not self.progressBarBrightText:
  481. self.setStyleSheet("color: white;")
  482. self.progressBarBrightText = True
  483.  
  484.  
  485. class CourseLabel(QtWidgets.QLabel):
  486. mouse = 0 # leaveEvent ~ 0, enterEvent ~ 1, mousePressEvent ~ 2
  487.  
  488. def __init__(self, course_id: int):
  489. super().__init__()
  490. global db
  491. db.cursor.execute('SELECT face, author, title, description FROM courses WHERE course_id = {}'.format(course_id))
  492. row = db.cursor.fetchone()
  493. self.course_id, self.face, self.author, self.title, self.description = course_id, *row
  494. self.pixmap = QtGui.QPixmap('Images/' + self.face).scaledToHeight(240)
  495. self.setFixedHeight(256)
  496.  
  497. def paintEvent(self, event):
  498. painter = QtGui.QPainter(self)
  499. painter.setBackgroundMode(QtCore.Qt.TransparentMode)
  500. painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
  501. if self.mouse == 0:
  502. painter.setOpacity(0.125 if self.course_id & 0x01 else 0.0625)
  503. elif self.mouse == 1:
  504. painter.setOpacity(0.1875)
  505. else:
  506. painter.setOpacity(0)
  507. painter.fillRect(0, 0, self.width() - 1, self.height() - 1, QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))
  508. painter.setOpacity(1.0)
  509. painter.drawPixmap(8, 8, self.pixmap.width(), self.pixmap.height(), self.pixmap)
  510. painter.setFont(QtGui.QFont('Monaco', 10, QtGui.QFont.Bold))
  511. painter.setPen(QtGui.QPen(QtCore.Qt.white, 1))
  512. painter.drawText(
  513. QtCore.QRect(self.pixmap.width() + 16, 8, self.width() - self.pixmap.width() - 24, 240),
  514. QtCore.Qt.AlignLeft | QtCore.Qt.TextWordWrap,
  515. 'Автор: {}\nНазвание: {}'.format(self.author, self.title)
  516. )
  517.  
  518. def showEvent(self, event):
  519. self.update()
  520.  
  521. def resizeEvent(self, event):
  522. self.update()
  523.  
  524. def enterEvent(self, event):
  525. self.mouse = 1
  526. self.update()
  527. self.setCursor(QtCore.Qt.PointingHandCursor)
  528.  
  529. def leaveEvent(self, event):
  530. self.mouse = 0
  531. self.update()
  532. self.setCursor(QtCore.Qt.ArrowCursor)
  533.  
  534. def mousePressEvent(self, event):
  535. self.mouse = 2
  536. self.update()
  537. self.setCursor(QtCore.Qt.ArrowCursor)
  538. """global mainFrame
  539. mainFrame.openCourse(self)"""
  540.  
  541.  
  542. """def CourseFrame(QtWidgets.QLabel):
  543.  
  544. pass"""
  545.  
  546.  
  547. class MainArea(QtWidgets.QScrollArea):
  548.  
  549. def __init__(self, mainFrame = None):
  550. super().__init__(mainFrame)
  551.  
  552. def resizeEvent(self, event):
  553. self.mainPanel.setFixedWidth(self.width() - 21)
  554. if self.courses:
  555. for courseLabel in self.courses:
  556. courseLabel.setFixedWidth(self.width() - 23)
  557.  
  558.  
  559. class MainFrame(QtWidgets.QWidget):
  560.  
  561. def __init__(self, mainWindow=None):
  562. super().__init__(mainWindow)
  563. self.mainWindow = mainWindow
  564. global mainFrame
  565. mainFrame = self
  566.  
  567. self.vbox = QtWidgets.QVBoxLayout(self)
  568. self.vbox.setContentsMargins(0, 0, 0, 0)
  569. self.vbox.setSpacing(0)
  570.  
  571. # Нижняя строка состояния
  572. self.statusBar = QtWidgets.QStatusBar(self)
  573. self.statusBar.setObjectName("mainStatusBar")
  574. self.statusBar.setFixedHeight(32)
  575. self.statusBar.setSizeGripEnabled(False)
  576. self.statusBar.setContentsMargins(0, 0, 3, 0)
  577.  
  578. # Индикатор хода прогресса
  579. self.progressBar = ProgressBar(self.statusBar)
  580. self.progressBar.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
  581. self.progressBar.setFixedWidth(160)
  582. self.progressBar.setRange(0, 160)
  583. self.statusBar.addPermanentWidget(self.progressBar)
  584.  
  585. self.userLabel = QtWidgets.QLabel()
  586. self.userLabel.setObjectName("userLabel")
  587. self.userLabel.setFixedHeight(100)
  588. self.userLabel.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
  589. self.userLabel.setContentsMargins(4, 8, 4, 4)
  590. self.choiceList = QtWidgets.QTreeWidget()
  591. self.choiceList.setObjectName("choiceList")
  592. self.choiceList.setHeaderHidden(True)
  593. self.choiceList.setAnimated(True)
  594. header = self.choiceList.header()
  595. header.setStretchLastSection(False)
  596. header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)
  597. self.choiceList.setHeader(header)
  598. self.mainPanel = QtWidgets.QLabel()
  599. self.mainPanel.setObjectName('mainPanel')
  600. self.mainBox = QtWidgets.QVBoxLayout(self.mainPanel)
  601. self.mainBox.setContentsMargins(0, 0, 0, 0)
  602. self.mainBox.setSpacing(0)
  603. self.mainBox.setAlignment(QtCore.Qt.AlignHCenter)
  604. self.leftPanel = QtWidgets.QLabel()
  605. self.leftBox = QtWidgets.QVBoxLayout()
  606. self.leftBox.setContentsMargins(0, 0, 0, 0)
  607. self.leftBox.setSpacing(0)
  608. self.leftPanel.setLayout(self.leftBox)
  609. self.leftBox.addWidget(self.userLabel)
  610. self.leftBox.addWidget(self.choiceList)
  611.  
  612. self.itemCourses = QtWidgets.QTreeWidgetItem(self.choiceList)
  613. self.itemCourses.setText(0, "Курсы")
  614. self.itemActiveCourses = QtWidgets.QTreeWidgetItem(self.itemCourses)
  615. self.itemActiveCourses.setText(0, "Активные курсы")
  616. self.itemNonactiveCourses = QtWidgets.QTreeWidgetItem(self.itemCourses)
  617. self.itemNonactiveCourses.setText(0, "Закрытые курсы")
  618. self.itemPrograms = QtWidgets.QTreeWidgetItem(self.choiceList)
  619. self.itemPrograms.setText(0, "Python-программы")
  620.  
  621. # Режим пользователя
  622. self.splitter = QtWidgets.QSplitter()
  623. self.splitter.setOrientation(QtCore.Qt.Horizontal)
  624. self.splitter.addWidget(self.leftPanel)
  625.  
  626. # Верхнее меню
  627. self.menuBar = QtWidgets.QMenuBar()
  628. self.menuBar.setFixedHeight(26)
  629.  
  630. self.developerMenu = QtWidgets.QMenu("&Разработка")
  631. self.developerMenu.setLayoutDirection(QtCore.Qt.LeftToRight)
  632. self.modeGroup = QtWidgets.QActionGroup(self.developerMenu)
  633. self.modeGroup.setExclusive(True)
  634. self.menuBar.addMenu(self.developerMenu)
  635. self.userMode = QtWidgets.QAction("Режим пользователя", self.modeGroup)
  636. self.userMode.setCheckable(True)
  637. self.developerMode = QtWidgets.QAction("Режим разработчика", self.modeGroup)
  638. self.developerMode.setCheckable(True)
  639. self.developerMenu.addAction(self.userMode)
  640. self.developerMenu.addAction(self.developerMode)
  641. self.userMode.setChecked(True)
  642. self.menuBar.setDisabled(True)
  643. self.modeGroup.triggered.connect(self.modeToggled)
  644. self.vbox.addWidget(self.menuBar)
  645. self.vbox.addWidget(self.splitter)
  646. self.vbox.addWidget(self.statusBar)
  647.  
  648. # Режим разработчика
  649. self.developerWidget = QtWidgets.QWidget()
  650. self.developerLayout = QtWidgets.QVBoxLayout(self.developerWidget)
  651. self.developerLayout.setSpacing(0)
  652. self.developerLayout.setContentsMargins(0, 0, 0, 0)
  653.  
  654. self.buttonsArea = QtWidgets.QScrollArea()
  655. self.buttonsArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
  656. self.buttonsArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
  657. self.buttonsLabel = QtWidgets.QLabel()
  658. self.buttonsArea.setWidget(self.buttonsLabel)
  659. self.buttonsBox = QtWidgets.QHBoxLayout(self.buttonsLabel)
  660. self.buttonsBox.setContentsMargins(2, 2, 2, 2)
  661. self.buttonsBox.setSpacing(2)
  662. self.buttonExec = QtWidgets.QPushButton("Выполнить запрос (F5)")
  663. self.buttonExec.setShortcut(QtCore.Qt.Key_F5)
  664. self.buttonExec.setIcon(QtGui.QIcon("Images/exec.png"))
  665. self.buttonExec.setFixedWidth(210)
  666. self.buttonExec.clicked.connect(self.execCommand)
  667. self.buttonsBox.addWidget(self.buttonExec)
  668. self.buttonCommit = QtWidgets.QPushButton("Совершить транзакцию (F6)")
  669. self.buttonCommit.setShortcut(QtCore.Qt.Key_F6)
  670. self.buttonCommit.setIcon(QtGui.QIcon("Images/commit.png"))
  671. self.buttonCommit.setFixedWidth(240)
  672. self.buttonCommit.clicked.connect(self.commitCommand)
  673. self.buttonsBox.addWidget(self.buttonCommit)
  674. self.buttonClear = QtWidgets.QPushButton("Очистить консоль (Ctrl+R)")
  675. self.buttonClear.setShortcut(QtCore.Qt.ControlModifier | QtCore.Qt.Key_R)
  676. self.buttonClear.setIcon(QtGui.QIcon("Images/clear.png"))
  677. self.buttonClear.setFixedWidth(230)
  678. self.buttonClear.clicked.connect(self.clearCommand)
  679. self.buttonsBox.addWidget(self.buttonClear)
  680. self.buttonSave = QtWidgets.QPushButton("Сохранить SQL (Ctrl+S)")
  681. self.buttonSave.setShortcut(QtCore.Qt.ControlModifier | QtCore.Qt.Key_S)
  682. self.buttonSave.setIcon(QtGui.QIcon("Images/save.png"))
  683. self.buttonSave.setFixedWidth(220)
  684. self.buttonSave.clicked.connect(self.saveCommand)
  685. self.buttonsBox.addWidget(self.buttonSave)
  686. self.buttonsArea.setFixedHeight(30)
  687. self.buttonsLabel.setFixedSize(QtCore.QSize(self.buttonExec.width() + self.buttonCommit.width() + self.buttonClear.width() + self.buttonSave.width() + 10, 28))
  688. self.developerLayout.addWidget(self.buttonsArea)
  689.  
  690. self.devSplitter = QtWidgets.QSplitter()
  691. self.devSplitter.setOrientation(QtCore.Qt.Vertical)
  692. self.devSplitter.setHandleWidth(4)
  693. self.developerLayout.addWidget(self.devSplitter)
  694.  
  695. self.developerTextEdit = QtWidgets.QTextEdit()
  696. self.developerTextEdit.setObjectName("developerTextEdit")
  697. self.developerTextEdit.setWordWrapMode(False)
  698. self.devSplitter.addWidget(self.developerTextEdit)
  699.  
  700. self.consoleTextEdit = QtWidgets.QTextEdit()
  701. self.consoleTextEdit.setObjectName("consoleTextEdit")
  702. self.consoleTextEdit.setReadOnly(True)
  703. self.consoleTextEdit.setWordWrapMode(False)
  704. self.devSplitter.addWidget(self.consoleTextEdit)
  705.  
  706. def showEvent(self, event):
  707. self.update()
  708.  
  709. def loadDatabase(self):
  710. global db
  711. db = Database(self.statusBar, self.progressBar, self.enterWindow)
  712.  
  713. # Главная панель
  714. self.mainArea = MainArea()
  715. self.mainArea.setObjectName("mainArea")
  716. self.mainArea.mainBox = self.mainBox
  717. self.mainArea.mainPanel = self.mainPanel
  718. self.mainArea.courses = []
  719. self.mainArea.setWidget(self.mainPanel)
  720. db.cursor.execute('SELECT course_id FROM courses')
  721. self.course_ids = [row[0] for row in db.cursor.fetchall()]
  722. self.courses = []
  723. height = 0
  724. for course_id in self.course_ids:
  725. course = CourseLabel(course_id)
  726. self.courses.append(course)
  727. self.mainBox.addWidget(course)
  728. height += course.height()
  729.  
  730. # Режим пользователя
  731. self.splitter.addWidget(self.mainArea)
  732. self.splitter.setSizes((320, self.mainArea.width()))
  733. self.mainPanel.setFixedWidth(self.mainArea.width() - 21)
  734. self.mainPanel.setFixedHeight(height)
  735. for course in self.courses:
  736. course.setFixedWidth(self.mainArea.width() - 23)
  737. self.splitter.setHandleWidth(4)
  738.  
  739. """def openCourse(self, courseLabel: CourseLabel):
  740. self.currentCourseLabel = courseLabel
  741. self.hideListOfCourses()
  742.  
  743. def hideListOfCourses(self):
  744. self.opacity1 = QtWidgets.QGraphicsOpacityEffect()
  745. self.mainArea.setGraphicsEffect(self.opacity1)
  746. self.anim1 = QtCore.QPropertyAnimation(self.opacity1, b"opacity")
  747. self.anim1.setDuration(250)
  748. self.anim1.setStartValue(1.0)
  749. self.anim1.setEndValue(0.0)
  750. self.anim1.start()
  751. self.anim1.finished.connect(self.showCourse)
  752.  
  753. def showCourse(self):
  754. self.mainArea.hide()
  755. self.opacity2 = QtWidgets.QGraphicsOpacityEffect()
  756.  
  757. # Открываем выбранный курс
  758. self.courseFrame =
  759.  
  760. self.mainFrame.setGraphicsEffect(self.opacity2)
  761. self.mainFrame.setWindowOpacity(0.0)
  762. self.mainFrame.show()
  763. self.anim2 = QtCore.QPropertyAnimation(self.opacity2, b"opacity")
  764. self.anim2.setDuration(250)
  765. self.anim2.setStartValue(0.0)
  766. self.anim2.setEndValue(1.0)
  767. self.anim2.start()
  768. self.anim2.finished.connect(self.mainFrameIsVisible)"""
  769.  
  770. def offerToEnter(self):
  771. global db
  772. db.offerToEnter()
  773.  
  774. def modeToggled(self, action: QtWidgets.QAction):
  775. if self.userMode.isChecked():
  776. self.statusBar.showMessage("Режим пользователя.")
  777. self.vbox.replaceWidget(self.developerWidget, self.splitter)
  778. self.developerWidget.setVisible(False)
  779. self.reloadUser()
  780. self.reloadChoiceList()
  781. self.splitter.setVisible(True)
  782. if self.developerMode.isChecked():
  783. self.statusBar.showMessage("Режим разработчика.")
  784. self.vbox.replaceWidget(self.splitter, self.developerWidget)
  785. self.splitter.setVisible(False)
  786. self.developerWidget.setVisible(True)
  787.  
  788. def reloadUser(self):
  789. self.userLabel.setText('<img src="Avatars/{}" width="64" height="64" align="left" /><span style="color: khaki; font-weight: bold">&nbsp;{}</span><br><br>&nbsp;Прогресс: {:.1f}'.format(currentUser.avatarUrl, currentUser.login, currentUser.progress))
  790.  
  791. def reloadChoiceList(self):
  792. for child in self.itemActiveCourses.takeChildren():
  793. self.itemActiveCourses.removeChild(child)
  794. for child in self.itemNonactiveCourses.takeChildren():
  795. self.itemActiveCourses.removeChild(child)
  796. global currentUser
  797. if currentUser:
  798. global db
  799. db.cursor.execute('SELECT course_id, face, title, description FROM courses')
  800. rows = db.cursor.fetchall()
  801. db.cursor.execute("SELECT course_id FROM saves WHERE user_id = {} AND type = 'isActive' AND data = 'True'".format(currentUser.userId))
  802. activeCourses = [r[0] for r in db.cursor.fetchall()]
  803. for row in rows:
  804. course_id, face, title, description = row
  805. newItem = QtWidgets.QTreeWidgetItem(self.itemActiveCourses if (course_id in activeCourses) else self.itemNonactiveCourses)
  806. newItem.setText(0, title)
  807.  
  808. def execCommand(self, event):
  809. textCursor = QtGui.QTextCursor(self.developerTextEdit.textCursor())
  810. text = textCursor.selectedText()
  811. if text == "":
  812. text = self.developerTextEdit.toPlainText()
  813.  
  814. self.statusBar.showMessage("Выполнение запроса...")
  815. self.progressBar.setValue(0)
  816. self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)
  817. self.consoleTextEdit.insertHtml("<span style='font-weight: bold; color: lightgray;'>{0:s}</span><br>".format(time.asctime()))
  818.  
  819. queries = [q.replace("\\n", "<br>") for q in re.findall(r"\s*((?:(?:\'[^\']*?\')|(?:\"[^\"]*?\")|[^\"\';\\]|(?:\\(?:[^;]|\s)))+)\s*\\?;", text.replace("\\\n", "").replace("\n", " "))]
  820. global db
  821. timeSum, timeBegin, timeEnd = 0, 0, 0
  822. db.progressBar.setValue(0)
  823. try:
  824. qlen = len(queries)
  825. for i in range(qlen):
  826. timeBegin = time.time()
  827. self.consoleTextEdit.setTextColor(QtGui.QColor('gold'))
  828. self.consoleTextEdit.insertPlainText(queries[i] + ';\n')
  829. self.consoleTextEdit.setTextColor(QtGui.QColor('#336699'))
  830. db.cursor.execute(queries[i])
  831. timeEnd = time.time()
  832. self.consoleTextEdit.insertHtml("<span style='color: green;'>Запрос выполнен за {0:.3f} секунд.</span><br>".format(timeEnd - timeBegin))
  833. timeSum += timeEnd - timeBegin
  834. db.progressBar.setValue(db.progressBar.maximum() * (i + 1) / qlen)
  835. rows = list(db.cursor.fetchall())
  836. desc = False
  837. if db.cursor.description:
  838. rows.insert(0, [f[0] for f in db.cursor.description])
  839. desc = True
  840. if rows:
  841. rlen = len(rows)
  842. wcount = len(rows[0])
  843. wmaxlen = [0] * wcount
  844. for x in range(wcount):
  845. wlen = 0
  846. for y in range(rlen):
  847. wyxlen = len(str(rows[y][x]))
  848. if wyxlen > wlen:
  849. wlen = wyxlen
  850. wmaxlen[x] = wlen
  851. self.consoleTextEdit.insertPlainText("+")
  852. for x in range(wcount):
  853. self.consoleTextEdit.insertPlainText("-" * (wmaxlen[x] + 2) + ("+" if x < (wcount - 1) else "+\n"))
  854. if desc:
  855. for x in range(wcount):
  856. self.consoleTextEdit.insertPlainText("|" + str(rows[0][x]).center(wmaxlen[x] + 2, " "))
  857. self.consoleTextEdit.insertPlainText("|\n+")
  858. for x in range(wcount):
  859. self.consoleTextEdit.insertPlainText("-" * (wmaxlen[x] + 2) + ("+" if x < (wcount - 1) else "+\n"))
  860. for y in range(1, rlen):
  861. for x in range(wcount):
  862. self.consoleTextEdit.insertPlainText("| " + str(rows[y][x]).ljust(wmaxlen[x] + 1, " "))
  863. self.consoleTextEdit.insertPlainText("|\n")
  864. self.consoleTextEdit.insertPlainText("+")
  865. for x in range(wcount):
  866. self.consoleTextEdit.insertPlainText("-" * (wmaxlen[x] + 2) + ("+" if x < (wcount - 1) else "+\n"))
  867. self.progressBar.setValue(self.progressBar.maximum() / qlen * (i + 1))
  868. self.statusBar.showMessage("Запросы выполнены за {0:.3f} секунд.".format(timeSum))
  869. self.consoleTextEdit.insertHtml("<span style='color: green;'>Запросы выполнены за {0:.3f} секунд.</span><br><br>".format(timeSum))
  870. except (sqlite3.Error, sqlite3.Warning) as e:
  871. self.statusBar.showMessage("Режим разработчика.")
  872. self.consoleTextEdit.insertHtml("<span style='color: red;'>Ошибка: {}<br><br>".format(e.args[0].replace("<", "<").replace(">", ">")))
  873. db.progressBar.setValue(db.progressBar.maximum())
  874.  
  875. self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)
  876. self.progressBar.setValue(self.progressBar.maximum())
  877.  
  878. def commitCommand(self, event):
  879. self.statusBar.showMessage("Выполнение транзакции...")
  880. self.progressBar.setValue(0)
  881. self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)
  882. self.consoleTextEdit.insertHtml("<span style='font-weight: bold; color: lightgray;'>{0:s}</span><br>".format(time.asctime()))
  883.  
  884. global db
  885. timeDelta, timeBegin, timeEnd = 0, 0, 0
  886. db.progressBar.setValue(0)
  887. try:
  888. timeBegin = time.time()
  889. db.connection.commit()
  890. timeEnd = time.time()
  891. timeDelta = timeEnd - timeBegin
  892.  
  893. self.statusBar.showMessage("Транзакция выполнена за {0:.3f} секунд.".format(timeDelta))
  894. self.consoleTextEdit.insertHtml("<span style='color: green;'>Транзакция выполнена за {0:.3f} секунд.</span><br><br>".format(timeDelta))
  895. except:
  896. self.statusBar.showMessage("Режим разработчика.")
  897. self.consoleTextEdit.insertHtml("<span style='color: red;'>Ошибка: не удалось совершить транзакцию.</span><br><br>")
  898. db.progressBar.setValue(db.progressBar.maximum())
  899.  
  900. self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)
  901. self.progressBar.setValue(self.progressBar.maximum())
  902.  
  903. def clearCommand(self):
  904. self.consoleTextEdit.clear()
  905. self.statusBar.showMessage("Консоль очищена...")
  906.  
  907. def saveCommand(self):
  908. try:
  909. path = QtWidgets.QFileDialog.getSaveFileName(
  910. self,
  911. caption="Сохранить SQL-код",
  912. directory="./",
  913. filter="SQL (*.sql);; TXT (*.txt);; Все файлы (*)",
  914. initialFilter= "SQL (*.sql)")[0]
  915. file = open(path, "w")
  916. file.write(self.developerTextEdit.toPlainText())
  917. file.close()
  918. pathConsole = re.search(r"^(.+?)(?:\.[^.]+)?$", path).group(1) + ".txt"
  919. fileHtml = open(pathConsole, "w")
  920. fileHtml.write(self.consoleTextEdit.toPlainText())
  921. fileHtml.close()
  922. self.statusBar.showMessage("SQL-код сохранён в файле \"{0:s}\", а данные консоли - в файле \"{1:s}\".".format(path, pathConsole))
  923. except:
  924. self.statusBar.showMessage("Произошла ошибка при сохранении SQL-кода и данных консоли.")
  925.  
  926.  
  927. class GoLink(QtWidgets.QLabel):
  928.  
  929. def __init__(self, text: str="", presentationWindow=None, mainFrame=None):
  930. super().__init__(presentationWindow)
  931. self.presentationWindow = presentationWindow
  932. self.mainFrame = mainFrame
  933.  
  934. self.setAlignment(QtCore.Qt.AlignCenter)
  935. self.setText(text)
  936.  
  937. def enterEvent(self, event):
  938. self.setCursor(QtCore.Qt.PointingHandCursor)
  939.  
  940. def mousePressEvent(self, event):
  941. self.opacity1 = QtWidgets.QGraphicsOpacityEffect()
  942. self.presentationWindow.setGraphicsEffect(self.opacity1)
  943. self.anim1 = QtCore.QPropertyAnimation(self.opacity1, b"opacity")
  944. self.anim1.setDuration(250)
  945. self.anim1.setStartValue(1.0)
  946. self.anim1.setEndValue(0.0)
  947. self.anim1.start()
  948. self.anim1.finished.connect(self.presentationWindowIsInvisible)
  949.  
  950. def presentationWindowIsInvisible(self):
  951. self.presentationWindow.hide()
  952. self.opacity2 = QtWidgets.QGraphicsOpacityEffect()
  953. self.mainFrame.setGraphicsEffect(self.opacity2)
  954. self.mainFrame.setWindowOpacity(0.0)
  955. self.mainFrame.show()
  956. self.anim2 = QtCore.QPropertyAnimation(self.opacity2, b"opacity")
  957. self.anim2.setDuration(250)
  958. self.anim2.setStartValue(0.0)
  959. self.anim2.setEndValue(1.0)
  960. self.anim2.start()
  961. self.anim2.finished.connect(self.mainFrameIsVisible)
  962.  
  963. def mainFrameIsVisible(self):
  964. self.mainFrame.enterWindow = EnterWindow()
  965. self.mainFrame.loadDatabase()
  966. self.mainFrame.enterWindow.uploadUsers()
  967. self.mainFrame.offerToEnter()
  968.  
  969.  
  970. class PresentationWindow(QtWidgets.QLabel):
  971. slideWidth = 1138 # Ширина одного слайда
  972. slideHeight = 500 # Высота одного слайда
  973. slidesCount = 3 # Количество слайдов
  974. movingTime = 750 # Скорость прокрутки слайдов в миллисекундах
  975.  
  976. def __init__(self, mainWindow=None, mainFrame=None):
  977. super().__init__(mainWindow) # Экземпляр класса PresentationWindow будет дочерним относительно родителя mainWindow
  978. self.mainFrame = mainFrame
  979.  
  980. self.setFixedSize(1200, 640) # Задаем фиксированный размер для презентации
  981. self.setAlignment(QtCore.Qt.AlignCenter) # Устанавливаем его в центр окна
  982.  
  983. self.content = QtWidgets.QVBoxLayout(self) # Задаем вертикальный макет для содержания презентации
  984. self.scrollArea = QtWidgets.QScrollArea() # Область с прокруткой для перелистывания слайдов
  985. self.slides = [QtWidgets.QLabel() for i in range(self.slidesCount)] # Сами слайды (имеют тип QLabel)
  986. self.slidesPacket = QtWidgets.QLabel()
  987. self.slidesLayout = QtWidgets.QHBoxLayout(self.slidesPacket) # Горизонтальный макет для слайдов
  988. self.buttonHBox = QtWidgets.QHBoxLayout() # Горизонтальный макет для radio-кнопок
  989.  
  990. for i in range(self.slidesCount):
  991. # Позволим пользователю выделять текст:
  992. slide = self.slides[i]
  993. # Пишем текст в i-ый слайд:
  994. if i == 0:
  995. slide.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextSelectableByKeyboard)
  996. slide.setText("<img src='Images/icon.png' /><br><br>Добро пожаловать в программу <b>NeuralNetworks</b>, которая<br>научит вас программировать искусственные нейросети на языке Python!")
  997. elif i == 1:
  998. slide.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextSelectableByKeyboard)
  999. slide.setText("<b>NeuralNetworks</b> содержит в себе видео-уроки, теорию, тесты<br>и интерпретатор языка программирования <b>Python</b> для написания собственных программ!<br>Результаты заданий буду сохраняться в одну локальную базу данных формата <b>SQLite</b>, которая будет<br>хранить в себе <b>весь прогресс</b> и <b>весь код ваших программ</b>.")
  1000. else:
  1001. self.goBox = QtWidgets.QVBoxLayout(slide)
  1002. self.goLink = GoLink("<b>Давайте приступим...</b>", self, self.mainFrame)
  1003. self.goBox.addStretch(1)
  1004. self.goBox.addWidget(self.goLink)
  1005. self.goBox.addStretch(1)
  1006. slide.setAlignment(QtCore.Qt.AlignCenter) # Устанавливаем текст слайда по центру
  1007. slide.setFixedWidth(self.slideWidth) # Задаем ширину для слайда
  1008. slide.setObjectName("slide")
  1009. self.slidesLayout.addWidget(slide) # Добавляем данный слайд в макет
  1010. # Устанавливаем размер пакета со всеми слайдами:
  1011. self.slidesPacket.setFixedSize(self.slideWidth * self.slidesCount, self.slideHeight)
  1012. self.slidesPacket.setObjectName("slidesPacket")
  1013.  
  1014. self.scrollArea.setObjectName("slides")
  1015. self.scrollArea.setWidget(self.slidesPacket) # Задаем виджет (QLabel)slidesPacket для области прокрутки
  1016. self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # Скрываем полосу прокрутки
  1017. self.scrollArea.horizontalScrollBar().valueChanged.connect(self.scrollAreaWheelEvent)
  1018.  
  1019. self.buttonHBox.addStretch(1) # Мы добавим отступы в начале и в конце для кнопок, чтобы они были по середине
  1020. self.buttons = [QtWidgets.QRadioButton(self) for i in range(self.slidesCount)]
  1021. self.buttons[0].setChecked(True) # Первый слайд будет виден сначала
  1022. for button in self.buttons:
  1023. button.clicked.connect(self.slideToggle)
  1024. self.buttonHBox.addWidget(button)
  1025. self.buttonHBox.addStretch(1)
  1026.  
  1027. # Заполняем содержимое:
  1028. self.content.addWidget(self.scrollArea)
  1029. self.content.addLayout(self.buttonHBox)
  1030.  
  1031. def slideToggle(self, isChecked):
  1032. if isChecked:
  1033. # Анимируем горизонтальную прокрутку:
  1034. self.anim = QtCore.QPropertyAnimation(self.scrollArea.horizontalScrollBar(), b"value")
  1035. self.anim.setDuration(self.movingTime)
  1036. self.anim.setEasingCurve(QtCore.QEasingCurve.InOutExpo)
  1037. i = 0
  1038. for i in range(self.slidesCount):
  1039. if self.buttons[i].isChecked():
  1040. break
  1041. self.anim.setEndValue(self.scrollArea.horizontalScrollBar().pageStep() * i)
  1042. self.anim.start()
  1043.  
  1044. def scrollAreaWheelEvent(self, value):
  1045. k = value / (self.scrollArea.horizontalScrollBar().pageStep() * self.slidesCount)
  1046. i = 0
  1047. for i in range(self.slidesCount):
  1048. if self.buttons[i].isChecked():
  1049. break
  1050. j = int(math.ceil(k * self.slidesCount - 0.5))
  1051. if j != i:
  1052. self.buttons[j].setChecked(True)
  1053.  
  1054.  
  1055. class MainWindow(QtWidgets.QWidget):
  1056. sourceSize = QtCore.QSize(1280, 768)
  1057.  
  1058. def __init__(self):
  1059. super().__init__()
  1060.  
  1061. # Создаем произвольное окно с задним фоном:
  1062. self.setWindowTitle("NeuralNetworks")
  1063. self.icon = QtGui.QIcon("Images/icon.png")
  1064. self.setWindowIcon(self.icon)
  1065. self.resize(self.sourceSize)
  1066. # Центруем окно по экрану:
  1067. self.desktop = QtWidgets.QApplication.desktop()
  1068. x = (self.desktop.width() - self.width()) // 2
  1069. y = (self.desktop.height() - self.height()) // 2
  1070. self.move(x, y)
  1071.  
  1072. self.hbox = QtWidgets.QHBoxLayout(self)
  1073. self.hbox.setContentsMargins(0, 0, 0, 0)
  1074. self.mainFrame = MainFrame(self)
  1075. self.mainFrame.resize(self.sourceSize)
  1076. self.mainFrame.hide()
  1077. self.hbox.addWidget(self.mainFrame)
  1078.  
  1079. self.presentationWindow = PresentationWindow(self, self.mainFrame)
  1080. self.hbox.addWidget(self.presentationWindow)
  1081.  
  1082. self.keyEsc = QtWidgets.QShortcut(QtCore.Qt.Key_Escape, self)
  1083. self.keyEsc.activated.connect(self.pressedKeyEsc)
  1084.  
  1085. self.keyF11 = QtWidgets.QShortcut(QtCore.Qt.Key_F11, self)
  1086. self.keyF11.activated.connect(self.pressedKeyF11)
  1087.  
  1088. def resizeEvent(self, event):
  1089. self.mainFrame.resize(self.size())
  1090.  
  1091. def paintEvent(self, event):
  1092. painter = QtGui.QPainter(self)
  1093. painter.drawPixmap(0, 0, self.width(), self.height(), QtGui.QPixmap("Images/background.jpg"))
  1094.  
  1095. def closeEvent(self, event):
  1096. if currentUser is not None:
  1097. msgBox = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Question,
  1098. "Закрыть программу",
  1099. "Вы действительно хотите выйти из программы? Все данные будут сохранены.",
  1100. QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
  1101. msgBox.setDefaultButton(QtWidgets.QMessageBox.No)
  1102. if msgBox.exec() == QtWidgets.QMessageBox.Yes:
  1103. QtWidgets.QApplication.closeAllWindows()
  1104. event.accept()
  1105. else:
  1106. event.ignore()
  1107. else:
  1108. QtWidgets.QApplication.quit()
  1109.  
  1110. def pressedKeyEsc(self):
  1111. self.close()
  1112.  
  1113. def pressedKeyF11(self):
  1114. if self.isFullScreen():
  1115. self.showNormal()
  1116. else:
  1117. self.showFullScreen()
  1118.  
  1119.  
  1120. app = QtWidgets.QApplication(sys.argv)
  1121.  
  1122. qss = open("stylesheet.css")
  1123. app.setStyleSheet(qss.read())
  1124. qss.close()
  1125.  
  1126. mainWindow = MainWindow()
  1127. mainWindow.show()
  1128.  
  1129. code = app.exec_()
  1130. sys.exit(code)
Add Comment
Please, Sign In to add comment