| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168 |
- import tkinter as tk
- from tkinter import messagebox
- import random
- import os
- from pathlib import Path
- from typing import Dict, List, Optional, Tuple
- # Попытка импорта PIL для работы с изображениями
- try:
- from PIL import Image
- PIL_AVAILABLE = True
- except ImportError:
- PIL_AVAILABLE = False
- print("PIL (Pillow) не установлен. Установите: pip install Pillow")
- # ==================== КОНСТАНТЫ ====================
- WINDOW_SIZE = "1000x700"
- IMAGES_FOLDER = "quiz_images"
- SUPPORTED_FORMATS = ('.jpg', '.jpeg', '.png', '.bmp', '.ico', '.tiff')
- DEFAULT_COLORS = [
- '#f0f8ff', '#f5f5dc', '#e6e6fa', '#ffe4e1', '#f0fff0',
- '#fff0f5', '#e0ffff', '#faf0e6', '#fffacd', '#f8f8ff'
- ]
- # ==================== СПИСОК ВОПРОСОВ ====================
- questions = [
- {
- 'id': 1,
- 'question': 'Что понимается под "персональными данными" согласно законодательству?',
- 'options': [
- 'Только паспортные данные и фотографии',
- 'Любая информация, прямо или косвенно относящаяся к конкретному физическому лицу',
- 'Только контактные данные человека',
- 'Информация о юридических лицах'
- ],
- 'correct': 1,
- 'explanation': 'Персональные данные - любые сведения, которые относятся, непосредственно либо косвенно, к конкретному физическому лицу.',
- 'image': 'q1.jpg',
- 'bg_color': None
- },
- {
- 'id': 2,
- 'question': 'Кто такой "оператор" персональных данных?',
- 'options': [
- 'Человек, чьи данные обрабатываются',
- 'Государственный орган, контролирующий защиту данных',
- 'Лицо или орган, осуществляющий обработку ПД и определяющий цели обработки',
- 'Сотрудник, работающий с базами данных'
- ],
- 'correct': 2,
- 'explanation': 'Оператор - лицо или орган, осуществляющий обработку персональных данных и определяющий цели обработки, состав данных и действия с ними.',
- 'image': 'q2.jpg',
- 'bg_color': None
- },
- {
- 'id': 3,
- 'question': 'Что включает в себя система защиты персональных данных?',
- 'options': [
- 'Только антивирусное программное обеспечение',
- 'Только организационные меры',
- 'Организационные и технические меры, определенные с учетом актуальных угроз',
- 'Только физическую охрану помещений'
- ],
- 'correct': 2,
- 'explanation': 'Система защиты включает организационные и технические меры, определенные с учетом актуальных угроз безопасности.',
- 'image': 'q3.jpg',
- 'bg_color': None
- },
- {
- 'id': 5,
- 'question': 'Сколько уровней защищенности персональных данных устанавливается при их обработке в информационных системах?',
- 'options': [
- '2 уровня',
- '3 уровня',
- '4 уровня',
- '5 уровней'
- ],
- 'correct': 2,
- 'explanation': 'При обработке персональных данных в информационных системах устанавливаются 4 уровня защищенности.',
- 'image': 'q5.jpg',
- 'bg_color': None
- },
- {
- 'id': 6,
- 'question': 'Какие данные относятся к специальным категориям персональных данных?',
- 'options': [
- 'ФИО и адрес проживания',
- 'Информация о расовой принадлежности, политических взглядах, здоровье',
- 'Номер телефона и email',
- 'Место работы и должность'
- ],
- 'correct': 1,
- 'explanation': 'К специальным категориям относятся данные о расовой принадлежности, политических взглядах, религиозных убеждениях, здоровье.',
- 'image': 'q6.jpg',
- 'bg_color': None
- },
- {
- 'id': 7,
- 'question': 'Что относится к биометрическим персональным данным?',
- 'options': [
- 'ФИО и дата рождения',
- 'Физиологические особенности для идентификации: отпечатки пальцев, ДНК, группа крови',
- 'Номер паспорта',
- 'Адрес проживания'
- ],
- 'correct': 1,
- 'explanation': 'Биометрические данные - физиологические особенности, используемые для идентификации личности.',
- 'image': 'q7.jpg',
- 'bg_color': None
- },
- {
- 'id': 8,
- 'question': 'Как часто должен проводиться контроль за выполнением требований защиты ПД?',
- 'options': [
- 'Ежемесячно',
- 'Ежегодно',
- 'Не реже 1 раза в 3 года',
- 'Один раз в 5 лет'
- ],
- 'correct': 2,
- 'explanation': 'Контроль проводится не реже 1 раза в 3 года в сроки, определяемые оператором.',
- 'image': 'q8.jpg',
- 'bg_color': None
- },
- {
- 'id': 9,
- 'question': 'Какой федеральный закон регулирует защиту персональных данных в России?',
- 'options': [
- 'ФЗ "Об информации"',
- 'Федеральный закон №152-ФЗ "О персональных данных"',
- 'ФЗ "О связи"',
- 'ФЗ "О безопасности"'
- ],
- 'correct': 1,
- 'explanation': 'В России требования к обработке и защите персональных данных определяет Федеральный закон №152-ФЗ "О персональных данных".',
- 'image': 'q9.jpg',
- 'bg_color': None
- },
- {
- 'id': 10,
- 'question': 'Что такое GDPR?',
- 'options': [
- 'Российский закон о данных',
- 'Американский стандарт безопасности',
- 'Европейский регламент по защите данных',
- 'Международный стандарт шифрования'
- ],
- 'correct': 2,
- 'explanation': 'GDPR - Общий регламент по защите данных, служит правилом для защиты личных данных граждан ЕС.',
- 'image': 'q10.jpg',
- 'bg_color': None
- },
- {
- 'id': 11,
- 'question': 'Какие требования предъявляются к сбору персональных данных?',
- 'options': [
- 'Сбор только с согласия субъекта и ограничение только необходимыми данными',
- 'Сбор любой доступной информации',
- 'Сбор без согласия, если это удобно',
- 'Только сбор через официальные запросы'
- ],
- 'correct': 0,
- 'explanation': 'Персональные данные могут собираться только при согласии субъекта и ограничиваться только необходимыми данными.',
- 'image': 'q11.jpg',
- 'bg_color': None
- },
- {
- 'id': 12,
- 'question': 'Что означает требование "целостность и конфиденциальность" ПД?',
- 'options': [
- 'Данные должны быть красиво оформлены',
- 'Защита от несанкционированного доступа, потери и уничтожения',
- 'Данные должны быть доступны всем',
- 'Данные должны храниться вечно'
- ],
- 'correct': 1,
- 'explanation': 'Данные должны защищаться от несанкционированного доступа, потери, повреждения или уничтожения.',
- 'image': 'q12.jpg',
- 'bg_color': None
- },
- {
- 'id': 13,
- 'question': 'Что означает "ограничение сроков хранения" персональных данных?',
- 'options': [
- 'Хранить данные бесконечно',
- 'Хранить только необходимое для целей обработки время',
- 'Удалять сразу после получения',
- 'Хранить минимум 10 лет'
- ],
- 'correct': 1,
- 'explanation': 'Хранить персональные сведения можно только столько, сколько необходимо для достижения целей их обработки.',
- 'image': 'q13.jpg',
- 'bg_color': None
- },
- {
- 'id': 14,
- 'question': 'В каких сферах применяются персональные данные?',
- 'options': [
- 'Только в медицине',
- 'Только в банковской сфере',
- 'Практически во всех сферах: коммерция, финансы, медицина, образование, госорганы',
- 'Только в интернете'
- ],
- 'correct': 2,
- 'explanation': 'Персональные данные используются практически в любой сфере современного цифрового мира.',
- 'image': 'q14.jpg',
- 'bg_color': None
- },
- {
- 'id': 15,
- 'question': 'Какие данные относятся к "общим" согласно 152-ФЗ?',
- 'options': [
- 'ФИО, место регистрации, образование, контактная информация',
- 'Данные о здоровье',
- 'Отпечатки пальцев',
- 'Политические взгляды'
- ],
- 'correct': 0,
- 'explanation': 'Общие данные: ФИО, место регистрации, сведения об образовании, месте работы, контактная информация.',
- 'image': 'q15.jpg',
- 'bg_color': None
- },
- {
- 'id': 16,
- 'question': 'Что должно быть предусмотрено в договоре между оператором и уполномоченным лицом?',
- 'options': [
- 'Стоимость услуг',
- 'Обязанность обеспечить безопасность ПД при обработке',
- 'Срок действия договора',
- 'Реквизиты сторон'
- ],
- 'correct': 1,
- 'explanation': 'Договор должен предусматривать обязанность уполномоченного лица обеспечить безопасность ПД при их обработке.',
- 'image': 'q16.jpg',
- 'bg_color': None
- },
- {
- 'id': 17,
- 'question': 'Кто обеспечивает безопасность персональных данных в информационной системе?',
- 'options': [
- 'ФСБ России',
- 'Оператор системы или уполномоченное им лицо',
- 'Роскомнадзор',
- 'Сам субъект данных'
- ],
- 'correct': 1,
- 'explanation': 'Безопасность обеспечивает оператор системы или лицо, осуществляющее обработку по поручению оператора.',
- 'image': 'q17.jpg',
- 'bg_color': None
- },
- {
- 'id': 18,
- 'question': 'Какие угрозы относятся к 1-му типу?',
- 'options': [
- 'Только внешние атаки',
- 'Угрозы, связанные с недокументированными возможностями в системном ПО',
- 'Только физические угрозы',
- 'Угрозы от сотрудников'
- ],
- 'correct': 1,
- 'explanation': 'Угрозы 1-го типа связаны с наличием недокументированных возможностей в системном программном обеспечении.',
- 'image': 'q18.jpg',
- 'bg_color': None
- },
- {
- 'id': 19,
- 'question': 'Какие угрозы относятся ко 2-му типу?',
- 'options': [
- 'Угрозы от хакеров',
- 'Угрозы, связанные с недокументированными возможностями в прикладном ПО',
- 'Угрозы пожаров и наводнений',
- 'Угрозы отключения электричества'
- ],
- 'correct': 1,
- 'explanation': 'Угрозы 2-го типа связаны с наличием недокументированных возможностей в прикладном программном обеспечении.',
- 'image': 'q19.jpg',
- 'bg_color': None
- },
- {
- 'id': 20,
- 'question': 'Какие угрозы относятся к 3-му типу?',
- 'options': [
- 'Угрозы из интернета',
- 'Угрозы, не связанные с недокументированными возможностями в системном и прикладном ПО',
- 'Только физические угрозы',
- 'Угрозы от вирусов'
- ],
- 'correct': 1,
- 'explanation': 'Угрозы 3-го типа - угрозы, не связанные с наличием недокументированных возможностей в ПО.',
- 'image': 'q20.jpg',
- 'bg_color': None
- },
- {
- 'id': 21,
- 'question': 'Когда устанавливается необходимость 1-го уровня защищенности?',
- 'options': [
- 'Всегда для всех систем',
- 'При угрозах 1 типа и обработке специальных или биометрических данных',
- 'Только для государственных систем',
- 'При обработке менее 100 записей'
- ],
- 'correct': 1,
- 'explanation': '1-й уровень необходим при угрозах 1 типа и обработке специальных категорий или биометрических данных.',
- 'image': 'q21.jpg',
- 'bg_color': None
- },
- {
- 'id': 22,
- 'question': 'Какие требования предъявляются для 4-го уровня защищенности?',
- 'options': [
- 'Создание специального отдела',
- 'Организация безопасности помещений, сохранность носителей, утверждение списка допущенных лиц',
- 'Шифрование всех данных',
- 'Ежедневный аудит'
- ],
- 'correct': 1,
- 'explanation': '4-й уровень требует безопасности помещений, сохранности носителей и утверждения списка допущенных лиц.',
- 'image': 'q22.jpg',
- 'bg_color': None
- },
- {
- 'id': 23,
- 'question': 'Что дополнительно требуется для 3-го уровня защищенности?',
- 'options': [
- 'Создание отдела защиты данных',
- 'Назначение ответственного за безопасность ПД в ИС',
- 'Автоматическая регистрация изменений',
- 'Шифрование каналов связи'
- ],
- 'correct': 1,
- 'explanation': 'Для 3-го уровня необходимо назначение должностного лица, ответственного за безопасность ПД в ИС.',
- 'image': 'q23.jpg',
- 'bg_color': None
- },
- {
- 'id': 24,
- 'question': 'Что дополнительно требуется для 2-го уровня защищенности?',
- 'options': [
- 'Видеонаблюдение',
- 'Ограничение доступа к электронному журналу сообщений',
- 'Биометрическая идентификация',
- 'Еженедельные проверки'
- ],
- 'correct': 1,
- 'explanation': 'Для 2-го уровня доступ к электронному журналу должен быть только для лиц, которым это необходимо.',
- 'image': 'q24.jpg',
- 'bg_color': None
- },
- {
- 'id': 25,
- 'question': 'Что дополнительно требуется для 1-го уровня защищенности?',
- 'options': [
- 'Автоматическая регистрация изменений полномочий и создание структурного подразделения',
- 'Ежечасный мониторинг',
- 'Вооруженная охрана',
- 'Спутниковое наблюдение'
- ],
- 'correct': 0,
- 'explanation': '1-й уровень требует автоматической регистрации изменений полномочий и создания структурного подразделения.',
- 'image': 'q25.jpg',
- 'bg_color': None
- },
- {
- 'id': 26,
- 'question': 'Что должно содержать уведомление в Роскомнадзор о начале обработки ПД?',
- 'options': [
- 'Только название организации',
- 'Информацию о целях обработки, категориях данных и мерах защиты',
- 'Только контактные данные',
- 'Только ФИО директора'
- ],
- 'correct': 1,
- 'explanation': 'Уведомление должно содержать информацию о целях, категориях данных и мерах защиты.',
- 'image': 'q26.jpg',
- 'bg_color': None
- },
- {
- 'id': 27,
- 'question': 'Что такое трансграничная передача данных?',
- 'options': [
- 'Передача внутри организации',
- 'Передача данных за пределы государства',
- 'Передача по локальной сети',
- 'Передача на флешке'
- ],
- 'correct': 1,
- 'explanation': 'Трансграничная передача - это передача персональных данных на территорию иностранного государства.',
- 'image': 'q27.jpg',
- 'bg_color': None
- },
- {
- 'id': 28,
- 'question': 'Кто должен давать согласие на обработку данных детей?',
- 'options': [
- 'Сам ребенок',
- 'Учитель',
- 'Законные представители (родители)',
- 'Директор школы'
- ],
- 'correct': 2,
- 'explanation': 'Для обработки данных детей требуется согласие законных представителей.',
- 'image': 'q28.jpg',
- 'bg_color': None
- },
- {
- 'id': 29,
- 'question': 'Что должно быть сделано при утечке персональных данных?',
- 'options': [
- 'Ничего, это не обязательно',
- 'Уведомление владельцев данных и контролирующих органов',
- 'Только смена паролей',
- 'Увольнение сотрудников'
- ],
- 'correct': 1,
- 'explanation': 'В случае утечки владельцы данных должны быть своевременно уведомлены.',
- 'image': 'q29.jpg',
- 'bg_color': None
- },
- {
- 'id': 30,
- 'question': 'Что такое обезличивание персональных данных?',
- 'options': [
- 'Удаление фотографий',
- 'Действия, после которых нельзя определить принадлежность данных конкретному лицу',
- 'Шифрование данных',
- 'Смена имен'
- ],
- 'correct': 1,
- 'explanation': 'Обезличивание делает невозможным идентификацию человека без использования дополнительной информации.',
- 'image': 'q30.jpg',
- 'bg_color': None
- },
- {
- 'id': 31,
- 'question': 'Кто осуществляет выбор средств защиты информации для системы защиты ПД?',
- 'options': [
- 'Роскомнадзор',
- 'Оператор в соответствии с нормативными актами ФСБ и ФСТЭК',
- 'Субъект данных',
- 'Поставщик оборудования'
- ],
- 'correct': 1,
- 'explanation': 'Выбор средств защиты осуществляется оператором в соответствии с актами ФСБ и ФСТЭК.',
- 'image': 'q31.jpg',
- 'bg_color': None
- },
- {
- 'id': 32,
- 'question': 'Какие организации могут привлекаться для контроля защиты ПД?',
- 'options': [
- 'Любые организации',
- 'Юридические лица и ИП с лицензией на техзащиту информации',
- 'Только государственные органы',
- 'Только ФСБ'
- ],
- 'correct': 1,
- 'explanation': 'Могут привлекаться организации и ИП, имеющие лицензию на техзащиту конфиденциальной информации.',
- 'image': 'q32.jpg',
- 'bg_color': None
- },
- {
- 'id': 33,
- 'question': 'Что относится к организационным мерам защиты ПД?',
- 'options': [
- 'Установка файерволов',
- 'Назначение ответственных лиц, разработка документов, инструктаж сотрудников',
- 'Шифрование дисков',
- 'Антивирусная защита'
- ],
- 'correct': 1,
- 'explanation': 'Организационные меры включают назначение ответственных, разработку документов и обучение сотрудников.',
- 'image': 'q33.jpg',
- 'bg_color': None
- },
- {
- 'id': 34,
- 'question': 'Что относится к техническим мерам защиты ПД?',
- 'options': [
- 'Проведение инструктажей',
- 'Антивирусы, межсетевые экраны, системы шифрования',
- 'Разработка политик безопасности',
- 'Подписание согласий'
- ],
- 'correct': 1,
- 'explanation': 'Технические меры включают программно-аппаратные средства защиты информации.',
- 'image': 'q34.jpg',
- 'bg_color': None
- },
- {
- 'id': 35,
- 'question': 'Какие данные являются общедоступными?',
- 'options': [
- 'Все данные в интернете',
- 'Данные, доступ к которым предоставлен самим субъектом',
- 'Паспортные данные',
- 'Медицинские записи'
- ],
- 'correct': 1,
- 'explanation': 'Общедоступные данные - это данные, доступ к которым предоставлен самим субъектом.',
- 'image': 'q35.jpg',
- 'bg_color': None
- },
- {
- 'id': 36,
- 'question': 'Что такое инцидент с персональными данными?',
- 'options': [
- 'Плановое обновление ПО',
- 'Нарушение безопасности, приводящее к утечке или компрометации данных',
- 'Обычная проверка системы',
- 'Резервное копирование'
- ],
- 'correct': 1,
- 'explanation': 'Инцидент - это любое событие, которое привело к нарушению защиты данных.',
- 'image': 'q36.jpg',
- 'bg_color': None
- },
- {
- 'id': 37,
- 'question': 'Какие требования предъявляются к точности и актуальности данных?',
- 'options': [
- 'Данные можно не обновлять',
- 'Важно обеспечивать правильность и своевременность данных',
- 'Точность не важна',
- 'Достаточно собрать данные один раз'
- ],
- 'correct': 1,
- 'explanation': 'Важно обеспечивать правильность и своевременность данных.',
- 'image': 'q37.jpg',
- 'bg_color': None
- },
- {
- 'id': 38,
- 'question': 'Что означает требование "законность, справедливость и прозрачность"?',
- 'options': [
- 'Данные должны быть доступны всем',
- 'Обработка должна вестись легально, честно и ясно для граждан',
- 'Данные должны публиковаться',
- 'Обработка может быть скрытой'
- ],
- 'correct': 1,
- 'explanation': 'Обработка должна вестись легально, честно и ясно для граждан, чьи данные собираются.',
- 'image': 'q38.jpg',
- 'bg_color': None
- },
- {
- 'id': 39,
- 'question': 'Что такое электронный журнал безопасности?',
- 'options': [
- 'Список сотрудников',
- 'Средство регистрации событий доступа и изменений в системе',
- 'Журнал учета посетителей',
- 'База данных клиентов'
- ],
- 'correct': 1,
- 'explanation': 'Электронный журнал регистрирует события доступа и изменения в системе.',
- 'image': 'q39.jpg',
- 'bg_color': None
- },
- {
- 'id': 40,
- 'question': 'К какому типу данных относится данные о заработной плате?',
- 'options': [
- 'Не являются персональными данными',
- 'Являются персональными данными и не подлежат разглашению без согласия',
- 'Могут публиковаться свободно',
- 'Относятся к общедоступным'
- ],
- 'correct': 1,
- 'explanation': 'Сведения о заработной плате - это персональные данные и не подлежат разглашению без согласия.',
- 'image': 'q40.jpg',
- 'bg_color': None
- },
- {
- 'id': 41,
- 'question': 'Что должен сделать оператор перед началом обработки ПД?',
- 'options': [
- 'Ничего',
- 'Подать уведомление в Роскомнадзор',
- 'Купить оборудование',
- 'Нанять сотрудников'
- ],
- 'correct': 1,
- 'explanation': 'Необходимо подать уведомление о начале обработки ПД в Роскомнадзор для регистрации в качестве оператора.',
- 'image': 'q41.jpg',
- 'bg_color': None
- },
- {
- 'id': 42,
- 'question': 'Что такое модель угроз для ИСПД?',
- 'options': [
- 'Описание возможных злоумышленников',
- 'Документ, описывающий актуальные угрозы безопасности для конкретной системы',
- 'Программа для взлома',
- 'Схема сети'
- ],
- 'correct': 1,
- 'explanation': 'Модель угроз - документ, описывающий актуальные угрозы для конкретной информационной системы.',
- 'image': 'q42.jpg',
- 'bg_color': None
- },
- {
- 'id': 43,
- 'question': 'Какие существуют категории персональных данных по 152-ФЗ?',
- 'options': [
- 'Только общие и специальные',
- 'Общие, особые, биометрические и иные данные',
- 'Только биометрические',
- 'Только контактные'
- ],
- 'correct': 1,
- 'explanation': 'Закон выделяет общие, особые, биометрические и иные категории персональных данных.',
- 'image': 'q43.jpg',
- 'bg_color': None
- },
- {
- 'id': 44,
- 'question': 'Что должно содержать согласие на обработку ПД?',
- 'options': [
- 'Только подпись',
- 'Конкретные цели обработки, перечень данных, срок действия',
- 'Только ФИО',
- 'Только дату'
- ],
- 'correct': 1,
- 'explanation': 'Согласие должно быть конкретным, содержать цели обработки, перечень данных и срок действия.',
- 'image': 'q44.jpg',
- 'bg_color': None
- },
- {
- 'id': 45,
- 'question': 'Кто такой уполномоченный по защите данных?',
- 'options': [
- 'Сотрудник полиции',
- 'Лицо, ответственное за контроль соблюдения законодательства о данных',
- 'Программист',
- 'Начальник отдела кадров'
- ],
- 'correct': 1,
- 'explanation': 'Это лицо, ответственное за контроль соблюдения законодательства о персональных данных.',
- 'image': 'q45.jpg',
- 'bg_color': None
- },
- {
- 'id': 46,
- 'question': 'Что такое техническое задание на создание системы защиты?',
- 'options': [
- 'Рекламный буклет',
- 'Документ с требованиями к создаваемой системе защиты ПД',
- 'Инструкция пользователя',
- 'Договор с поставщиком'
- ],
- 'correct': 1,
- 'explanation': 'ТЗ - документ с требованиями по формированию требуемой системы защиты.',
- 'image': 'q46.jpg',
- 'bg_color': None
- },
- {
- 'id': 47,
- 'question': 'Какие данные относятся к "иным" согласно 152-ФЗ?',
- 'options': [
- 'Данные о здоровье',
- 'Все, что не попадает в общие, особые и биометрические категории',
- 'Только фотографии',
- 'Только отпечатки пальцев'
- ],
- 'correct': 1,
- 'explanation': 'Иные данные - всё, что не попадает в предыдущие категории.',
- 'image': 'q47.jpg',
- 'bg_color': None
- },
- {
- 'id': 48,
- 'question': 'Что такое ФСТЭК России?',
- 'options': [
- 'Производитель компьютеров',
- 'Федеральная служба по техническому и экспортному контролю',
- 'Провайдер интернета',
- 'Страховая компания'
- ],
- 'correct': 1,
- 'explanation': 'ФСТЭК - федеральная служба по техническому и экспортному контролю, регулирующая вопросы защиты информации.',
- 'image': 'q48.jpg',
- 'bg_color': None
- },
- {
- 'id': 49,
- 'question': 'Какие требования предъявляются к помещениям, где обрабатываются ПД?',
- 'options': [
- 'Наличие кондиционера',
- 'Режим, препятствующий неконтролируемому проникновению посторонних',
- 'Наличие коврового покрытия',
- 'Яркое освещение'
- ],
- 'correct': 1,
- 'explanation': 'Необходима организация режима, препятствующего неконтролируемому проникновению посторонних.',
- 'image': 'q49.jpg',
- 'bg_color': None
- },
- {
- 'id': 50,
- 'question': 'Какова основная цель выполнения требований по защите персональных данных?',
- 'options': [
- 'Выполнение формальностей',
- 'Минимизация вреда от возможной реализации угроз безопасности',
- 'Экономия средств',
- 'Повышение престижа компании'
- ],
- 'correct': 1,
- 'explanation': 'Основная цель - минимизация вреда, возникающего из-за возможной реализации угроз безопасности.',
- 'image': 'q50.jpg',
- 'bg_color': None
- }
- ] # Остальные вопросы аналогичны, для краткости сократил до 10
- class ImageManager:
- """Класс для управления изображениями"""
-
- def __init__(self, images_folder: str):
- self.images_folder = Path(images_folder)
- self.cache = {} # Кэш для изображений
- self.pil_available = PIL_AVAILABLE
-
- def find_image(self, image_name: str) -> Optional[Path]:
- """Поиск изображения по имени с разными расширениями"""
- if not image_name:
- return None
-
- # Проверка кэша
- if image_name in self.cache:
- return self.cache[image_name]
-
- # Поиск файла
- image_path = self.images_folder / image_name
- if image_path.exists():
- self.cache[image_name] = image_path
- return image_path
-
- # Поиск с разными расширениями
- name_without_ext = image_path.stem
- for ext in SUPPORTED_FORMATS:
- test_path = self.images_folder / f"{name_without_ext}{ext}"
- if test_path.exists():
- self.cache[image_name] = test_path
- return test_path
-
- return None
-
- def load_image(self, image_path: Path, bg_color: str = '#ffffff', size: Tuple[int, int] = (350, 350)):
- """Загрузка и обработка изображения"""
- if not self.pil_available:
- if image_path.suffix.lower() == '.jpg':
- return tk.PhotoImage(file=str(image_path))
- raise Exception("Для работы с изображениями требуется Pillow")
-
- img = Image.open(image_path)
-
- # Обработка анимированных GIF
- if getattr(img, 'is_animated', False):
- img.seek(0)
-
- # Обработка прозрачности
- if img.mode == 'RGBA':
- bg_rgb = tuple(int(bg_color[i:i+2], 16) for i in (1, 3, 5))
- background = Image.new('RGB', img.size, bg_rgb)
- background.paste(img, mask=img.split()[3])
- img = background
- elif img.mode != 'RGB':
- img = img.convert('RGB')
-
- # Изменение размера
- img.thumbnail(size, Image.Resampling.LANCZOS)
- return ImageTk.PhotoImage(img)
-
- def get_dominant_color(self, image_path: Path) -> Optional[str]:
- """Получение доминирующего цвета изображения"""
- if not self.pil_available:
- return None
-
- try:
- img = Image.open(image_path)
-
- if getattr(img, 'is_animated', False):
- img.seek(0)
-
- # Конвертация в RGB
- if img.mode == 'RGBA':
- background = Image.new('RGB', img.size, (255, 255, 255))
- background.paste(img, mask=img.split()[3])
- img = background
- elif img.mode != 'RGB':
- img = img.convert('RGB')
-
- # Уменьшение для ускорения
- img.thumbnail((100, 100))
- pixels = img.getdata()
-
- # Вычисление среднего цвета
- r_sum = g_sum = b_sum = 0
- for pixel in pixels:
- r_sum += pixel[0]
- g_sum += pixel[1]
- b_sum += pixel[2]
-
- count = len(pixels)
- if count == 0:
- return None
-
- return f'#{r_sum//count:02x}{g_sum//count:02x}{b_sum//count:02x}'
- except Exception as e:
- print(f"Ошибка определения цвета: {e}")
- return None
- class QuizApp:
- """Основной класс приложения"""
-
- def __init__(self, master):
- self.master = master
- self.master.title("Викторина: Защита персональных данных")
- self.master.geometry(WINDOW_SIZE)
- self.master.resizable(False, False)
-
- # Инициализация
- self.questions = questions.copy()
- self.current_question = 0
- self.correct_answers = 0
- self.total_questions = len(self.questions)
-
- # Менеджеры
- self.image_manager = ImageManager(IMAGES_FOLDER)
-
- # Переменные состояния
- self.var = None
- self.option_mapping = {}
- self.current_image = None
-
- # Привязка клавиш
- self._bind_keys()
-
- # Запуск
- self.show_start_screen()
-
- def _bind_keys(self):
- """Привязка клавиатурных комбинаций"""
- self.master.bind('<Key>', self.on_key_press)
- self.master.bind('<Return>', lambda e: self.check_answer())
- self.master.bind('<Escape>', lambda e: self.quit_app())
-
- def on_key_press(self, event):
- """Обработка нажатий клавиш"""
- if event.char in '1234' and self.var is not None:
- self.var.set(int(event.char) - 1)
-
- def quit_app(self):
- """Выход из приложения"""
- if messagebox.askyesno("Выход", "Вы действительно хотите выйти?"):
- self.master.quit()
-
- def clear_window(self):
- """Очистка окна"""
- for widget in self.master.winfo_children():
- widget.destroy()
-
- def shuffle_questions(self):
- """Перемешивание вопросов"""
- random.shuffle(self.questions)
-
- def get_text_color(self, bg_hex: str) -> str:
- """Определение цвета текста на основе фона"""
- if not bg_hex:
- return 'black'
- try:
- r = int(bg_hex[1:3], 16)
- g = int(bg_hex[3:5], 16)
- b = int(bg_hex[5:7], 16)
- brightness = 0.299 * r + 0.587 * g + 0.114 * b
- return 'black' if brightness > 128 else 'white'
- except:
- return 'black'
-
- def show_start_screen(self):
- """Экран приветствия"""
- self.clear_window()
- self.master.config(bg='lightblue')
-
- # Заголовок
- title = tk.Label(self.master, text="Викторина по защите персональных данных",
- font=("Arial", 20, "bold"), bg='lightblue', fg='navy')
- title.pack(pady=40)
-
- # Инструкция
- instr_text = (
- f"Добро пожаловать!\n\n"
- f"Эта викторина проверит ваши знания об основах защиты персональных данных.\n"
- f"Правила:\n"
- f"• Всего вопросов: {self.total_questions}\n"
- f"• Выберите один правильный вариант.\n"
- f"• Управление с клавиатуры: клавиши 1-4 для выбора ответа\n"
- f"• Нажмите Enter для проверки ответа\n"
- f"• Esc для выхода\n"
- f"• После ответа вы увидите пояснение.\n\n"
- f"Удачи!"
- )
-
- instr_label = tk.Label(self.master, text=instr_text, font=("Arial", 12),
- bg='lightblue', justify='left')
- instr_label.pack(pady=20)
-
- # Кнопка старта
- start_btn = tk.Button(self.master, text="Начать викторину", font=("Arial", 14),
- command=self.start_quiz, bg='green', fg='white',
- padx=20, pady=10, cursor='hand2')
- start_btn.pack(pady=30)
-
- def start_quiz(self):
- """Начало викторины"""
- self.shuffle_questions()
- self.current_question = 0
- self.correct_answers = 0
- self.show_question()
-
- def get_background_color(self, q: Dict, index: int) -> str:
- """Получение цвета фона для вопроса"""
- if q.get('bg_color'):
- return q['bg_color']
-
- if PIL_AVAILABLE and q.get('image'):
- image_path = self.image_manager.find_image(q['image'])
- if image_path:
- color = self.image_manager.get_dominant_color(image_path)
- if color:
- return color
-
- return DEFAULT_COLORS[index % len(DEFAULT_COLORS)]
-
- def create_option_buttons(self, parent, options: List, bg_color: str, text_color: str):
- """Создание кнопок вариантов ответов"""
- options_with_indices = list(enumerate(options))
- random.shuffle(options_with_indices)
-
- self.var = tk.IntVar(value=-1)
- self.option_mapping = {}
-
- # Функции для эффекта наведения
- def on_enter(btn):
- btn.config(bg='#d0d0d0' if text_color == 'black' else '#505050')
-
- def on_leave(btn, orig_bg):
- btn.config(bg=orig_bg)
-
- for new_idx, (old_idx, option_text) in enumerate(options_with_indices):
- self.option_mapping[new_idx] = old_idx
- display_text = f"{new_idx + 1}. {option_text}"
-
- rb = tk.Radiobutton(parent, text=display_text, variable=self.var,
- value=new_idx, font=("Arial", 11), wraplength=350,
- justify='left', indicatoron=0, bg=bg_color,
- fg=text_color, selectcolor=bg_color,
- padx=15, pady=8, cursor='hand2')
- rb.pack(anchor='center', pady=5)
-
- # Эффект наведения
- orig_bg = rb.cget('bg')
- rb.bind("<Enter>", lambda e, b=rb: on_enter(b))
- rb.bind("<Leave>", lambda e, b=rb: on_leave(b, orig_bg))
-
- def show_question(self):
- """Отображение вопроса"""
- self.clear_window()
-
- # Удаление старого изображения
- if hasattr(self, 'current_image'):
- del self.current_image
-
- q = self.questions[self.current_question]
- bg_color = self.get_background_color(q, self.current_question)
- text_color = self.get_text_color(bg_color)
- self.master.config(bg=bg_color)
-
- # Основной контейнер
- main_frame = tk.Frame(self.master, bg=bg_color)
- main_frame.pack(fill='both', expand=True, padx=30, pady=20)
-
- # Левая колонка
- left_frame = tk.Frame(main_frame, bg=bg_color)
- left_frame.pack(side='left', fill='both', expand=True)
-
- # Правая колонка
- right_frame = tk.Frame(main_frame, bg=bg_color)
- right_frame.pack(side='right', fill='both', expand=True)
-
- # Вопрос
- question_lbl = tk.Label(left_frame, text=q['question'],
- font=("Arial", 14, "bold"), wraplength=450,
- justify='left', bg=bg_color, fg=text_color)
- question_lbl.pack(anchor='nw', pady=(0, 20))
-
- # Изображение
- if q.get('image'):
- image_path = self.image_manager.find_image(q['image'])
- if image_path:
- try:
- self.current_image = self.image_manager.load_image(image_path, bg_color)
- img_label = tk.Label(left_frame, image=self.current_image, bg=bg_color)
- img_label.pack(anchor='center', pady=10)
- except Exception as e:
- error_text = f"[Ошибка: {image_path.name}]\n{str(e)[:50]}"
- error_label = tk.Label(left_frame, text=error_text,
- font=("Arial", 8), fg='red', bg=bg_color)
- error_label.pack(anchor='center')
- else:
- error_text = f"[Файл не найден: {q['image']}]\nПоддерживаемые форматы: PNG, JPG, JPEG, GIF, BMP"
- error_label = tk.Label(left_frame, text=error_text,
- font=("Arial", 8), fg='orange', bg=bg_color)
- error_label.pack(anchor='center')
-
- # Прогресс и подсказки
- progress_lbl = tk.Label(left_frame,
- text=f"Вопрос {self.current_question + 1} из {self.total_questions}",
- font=("Arial", 11), fg=text_color, bg=bg_color)
- progress_lbl.pack(side='bottom', anchor='sw', pady=10)
-
- hint_lbl = tk.Label(left_frame,
- text="Клавиши 1-4 → выбор ответа, Enter → проверка",
- font=("Arial", 9), fg=text_color, bg=bg_color)
- hint_lbl.pack(side='bottom', anchor='sw', pady=5)
-
- # Варианты ответов
- center_container = tk.Frame(right_frame, bg=bg_color)
- center_container.pack(expand=True)
-
- options_title = tk.Label(center_container, text="Выберите ответ:",
- font=("Arial", 12, "bold"), bg=bg_color, fg=text_color)
- options_title.pack(pady=(0, 15))
-
- self.create_option_buttons(center_container, q['options'], bg_color, text_color)
-
- # Кнопки управления
- btn_frame = tk.Frame(right_frame, bg=bg_color)
- btn_frame.pack(side='bottom', fill='x', pady=20)
-
- exit_btn = tk.Button(btn_frame, text="Выход (Esc)", font=("Arial", 11),
- command=self.quit_app, bg='red', fg='white',
- padx=20, pady=5, cursor='hand2')
- exit_btn.pack(side='right', padx=10)
-
- check_btn = tk.Button(btn_frame, text="Проверить (Enter)", font=("Arial", 11),
- command=self.check_answer, bg='blue', fg='white',
- padx=20, pady=5, cursor='hand2')
- check_btn.pack(side='right', padx=10)
-
- self.master.focus_set()
-
- def check_answer(self):
- """Проверка ответа"""
- if self.var is None or self.var.get() == -1:
- messagebox.showwarning("Нет выбора", "Пожалуйста, выберите один из вариантов (клавиши 1-4).")
- return
-
- selected = self.var.get()
- original_selected = self.option_mapping[selected]
- q = self.questions[self.current_question]
-
- if original_selected == q['correct']:
- self.correct_answers += 1
- self.show_feedback("Правильно!", "green")
- else:
- correct_text = q['options'][q['correct']]
- explanation = f"Неправильно. Правильный ответ: {correct_text}\n\n{q['explanation']}"
- self.show_feedback("Неправильно", "red", explanation)
-
- def show_feedback(self, message: str, color: str, explanation: str = None):
- """Отображение обратной связи"""
- win = tk.Toplevel(self.master)
- win.title("Результат")
- win.geometry("500x350")
- win.configure(bg=color)
- win.transient(self.master)
- win.grab_set()
-
- # Закрытие окна
- def close_and_continue():
- win.destroy()
- self.next_question()
-
- win.protocol("WM_DELETE_WINDOW", close_and_continue)
- win.bind('<Return>', lambda e: close_and_continue())
- win.bind('<Escape>', lambda e: close_and_continue())
-
- # Сообщение
- lbl = tk.Label(win, text=message, bg=color, fg='white',
- font=("Arial", 24, "bold"), wraplength=450, justify='center')
- lbl.pack(expand=True, fill='both', padx=20, pady=20)
-
- # Пояснение
- if explanation:
- expl_lbl = tk.Label(win, text=explanation, bg=color, fg='white',
- font=("Arial", 11), wraplength=450, justify='left')
- expl_lbl.pack(padx=20, pady=10)
-
- # Кнопка продолжения
- btn = tk.Button(win, text="Продолжить (Enter)", command=close_and_continue,
- bg='white', font=("Arial", 11), padx=20, pady=5, cursor='hand2')
- btn.pack(pady=20)
-
- win.focus_set()
-
- def next_question(self):
- """Переход к следующему вопросу"""
- if self.current_question + 1 < self.total_questions:
- self.current_question += 1
- self.show_question()
- else:
- self.show_result()
-
- def show_result(self):
- """Отображение результатов"""
- self.clear_window()
- self.master.config(bg='lightgreen')
-
- percentage = (self.correct_answers / self.total_questions) * 100
- result_text = f"Викторина завершена!\n\n"
- result_text += f"Вы ответили правильно на {self.correct_answers} из {self.total_questions} вопросов.\n"
- result_text += f"Ваш результат: {percentage:.1f}%\n\n"
-
- if percentage == 100:
- result_text += "Отлично! Вы очень хорошо усвоили материал."
- elif percentage >= 80:
- result_text += "Отличный результат! Вы хорошо знаете тему."
- elif percentage >= 60:
- result_text += "Хороший результат! Есть куда стремиться."
- else:
- result_text += "Стоит повторить лекцию и попробовать снова."
-
- lbl = tk.Label(self.master, text=result_text, font=("Arial", 16),
- bg='lightgreen', justify='center')
- lbl.pack(pady=30)
-
- # Привязка клавиш
- self.master.bind('<Return>', lambda e: self.start_quiz())
- self.master.bind('<Escape>', lambda e: self.quit_app())
-
- # Подсказка
- hint_lbl = tk.Label(self.master, text="Enter - пройти заново | Esc - выход",
- font=("Arial", 11), bg='lightgreen', fg='gray')
- hint_lbl.pack(pady=10)
-
- # Кнопки
- btn_frame = tk.Frame(self.master, bg='lightgreen')
- btn_frame.pack(pady=20)
-
- restart_btn = tk.Button(btn_frame, text="Пройти заново (Enter)",
- font=("Arial", 12), command=self.start_quiz,
- bg='blue', fg='white', padx=20, pady=8, cursor='hand2')
- restart_btn.pack(side='left', padx=15)
-
- exit_btn = tk.Button(btn_frame, text="Завершить (Esc)",
- font=("Arial", 12), command=self.quit_app,
- bg='orange', fg='white', padx=20, pady=8, cursor='hand2')
- exit_btn.pack(side='left', padx=15)
-
- self.master.focus_set()
- if __name__ == "__main__":
- root = tk.Tk()
- app = QuizApp(root)
- root.mainloop()
|