Что нового

Перемешивание кнопок с разным текстом в окне

SergVrn

Чайник
Сообщения
44
Репутация
0
Доброго времени суток.
Помогите поправить код.

Есть окно с тестом, которое периодически вылетает на экран и требует ответить на вопрос.
Все нормально работает.
Но немного смущает то, что кнопки с возможными ответами - расставлены всегда в том порядке - в каком они представлены в txt-файле, откуда скрипт их достает.
Это создает такой эффект, что можно просто запомнить положение кнопки с верным ответом - и просто щелкать по ней, не читая что на этой кнопке написано.

Как можно изменить скрипт, чтобы он размещал возможные ответы на кнопках - случайным образом ?
То есть чтобы скрипт - перемешивал кнопки с ответами - чтобы они в разном порядке шли.

Код:
#pragma compile(Icon, 1.ico)

#NoTrayIcon
#include <WindowsConstants.au3>
#include <GUIConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <Math.au3>
#include <TrayConstants.au3>
#include <MsgBoxConstants.au3>
Opt("TrayAutoPause", 0)
Opt("GUIOnEventMode", 1)
Opt("GUIResizeMode", $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKMENUBAR)

Global Const $GUI_TITLE = "Тест"
Global Const $QUESTION_FILE = @ScriptDir & "\Тестовые вопросы и ответы.txt"
Global Const $ANSWER_CORRECT_PAUSE = 10 ;мин.
Global Const $ANSWER_INCORRECT_PAUSE = 1 ;мин.

Global Const $GUI_WIDTH = 425
Global Const $PIC_HEIGHT = 200
Global Const $PIC_ONLYREDUCE = False
Global Const $LABEL_HEIGHT = 20
Global Const $BUTTON_HEIGHT = 30
Global Const $CONTROL_INDENT = 10

Global Enum $TST_QUESTION, $TST_CORRECT, $TST_PIC, $TST_ANSWERS, $TST_MAX
Global Enum $ANS_ID, $ANS_TEXT, $ANS_MAX
Global $g_hGUI, $g_idQuest, $g_idInfo, $g_idPic, _
        $g_aTest[][$TST_MAX] = [[0, -1]], $g_hTimer

_GUI_Init()
_Test_Init()
_Test_Start()

While Sleep(10)
WEnd

Func _GUI_Init()
    $g_hGUI = GUICreate($GUI_TITLE, $GUI_WIDTH)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    Local $iY = $CONTROL_INDENT, $iFullWidth = $GUI_WIDTH - $CONTROL_INDENT * 2
    $g_idQuest = GUICtrlCreateLabel("", $CONTROL_INDENT, $iY, $iFullWidth, $LABEL_HEIGHT, BitOR($SS_CENTERIMAGE, $SS_CENTER))
    $iY += $LABEL_HEIGHT + $CONTROL_INDENT
    $g_idPic = GUICtrlCreatePic("", $CONTROL_INDENT, $iY, $iFullWidth, $PIC_HEIGHT, $SS_CENTERIMAGE)
    GUICtrlSetState(-1, $GUI_HIDE)
    $iY += $PIC_HEIGHT + $CONTROL_INDENT
    $g_idInfo = GUICtrlCreateLabel("", $CONTROL_INDENT, $iY, $iFullWidth, $LABEL_HEIGHT, BitOR($SS_CENTERIMAGE, $SS_CENTER))
    GUICtrlSetColor(-1, 0xFF0000)
    GUICtrlSetState(-1, $GUI_HIDE)
EndFunc   ;==>_GUI_Init

Func _Test_Init()
    Local $sRead = FileRead($QUESTION_FILE)
    Local $aData = StringRegExp($sRead, "(?i)Вопрос \d+\R(.+?)\R((?s).+?)\RПравильный:\R(.+)", $STR_REGEXPARRAYGLOBALMATCH)
    If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, $GUI_TITLE, StringFormat('Вопросы не найдены -> "%s"', $QUESTION_FILE))
    Local $iIdx, $iCount = UBound($aData)
    Dim $g_aTest[$iCount / 3 + 1][$TST_MAX] = [[0, -1]]
    For $i = 0 To $iCount - 1 Step 3
        $g_aTest[0][0] += 1
        $iIdx = $g_aTest[0][0]

        $g_aTest[$iIdx][$TST_QUESTION] = $aData[$i]
        $g_aTest[$iIdx][$TST_CORRECT] = $aData[$i + 2]
        _Test_MakeSubData($aData[$i + 1])
    Next
EndFunc   ;==>_Test_Init

Func _Test_MakeSubData($sData)
    Local $aSubData, $iIdx = $g_aTest[0][0], $iOffset = 1
    $aSubData = StringRegExp($sData, "(?i)Адрес:\R(.+)", $STR_REGEXPARRAYMATCH)
    If Not @error Then
        $g_aTest[$iIdx][$TST_PIC] = $aSubData[0]
        $iOffset = @extended
    EndIf

    Local $aSplit, $sAnswers = "Некорректный вопрос (без ответов)", $bCorrect
    $aSubData = StringRegExp($sData, "(?i)Ответы:\R((?s).+)", $STR_REGEXPARRAYMATCH, $iOffset)
    If Not @error Then $sAnswers = $aSubData[0]
    $aSplit = StringSplit(StringStripCR($sAnswers), @LF)
    Local $aAnswers[$aSplit[0] + 1][$ANS_MAX] = [[$aSplit[0]]]
    For $i = 1 To $aSplit[0]
        $aAnswers[$i][$ANS_TEXT] = $aSplit[$i]
        If Not $bCorrect Then $bCorrect = $g_aTest[$iIdx][$TST_CORRECT] = $aAnswers[$i][$ANS_TEXT]
    Next
    If Not $bCorrect Then MsgBox($MB_ICONERROR + $MB_TOPMOST, $GUI_TITLE, StringFormat('Верный ответ не найден -> "%s"', $g_aTest[$iIdx][$TST_QUESTION]))
    $g_aTest[$iIdx][$TST_ANSWERS] = $aAnswers
EndFunc   ;==>_Test_MakeSubData

Func _Test_Start()
    Local $iIdx = $g_aTest[0][1]
    Do
        $iIdx = Random(1, $g_aTest[0][0], 1)
    Until $iIdx <> $g_aTest[0][1]

    GUICtrlSetData($g_idQuest, $g_aTest[$iIdx][$TST_QUESTION])
    Local $iY = $CONTROL_INDENT * 2 + $LABEL_HEIGHT, $iFullWidth = $GUI_WIDTH - $CONTROL_INDENT * 2
    If $g_aTest[$iIdx][$TST_PIC] Then
        _GUICtrlPic_SetImageWithResize($g_idPic, $g_aTest[$iIdx][$TST_PIC], $PIC_ONLYREDUCE)
        GUICtrlSetState($g_idPic, $GUI_SHOW)
        $iY += $PIC_HEIGHT + $CONTROL_INDENT
    Else
        GUICtrlSetState($g_idPic, $GUI_HIDE)
    EndIf
    $aAnswers = $g_aTest[$iIdx][$TST_ANSWERS]
    For $i = 1 To $aAnswers[0][0]
        $aAnswers[$i][$ANS_ID] = GUICtrlCreateButton($aAnswers[$i][$ANS_TEXT], $CONTROL_INDENT, $iY, $iFullWidth, $BUTTON_HEIGHT)
        GUICtrlSetOnEvent(-1, "_Test_Proc")
        $iY += $BUTTON_HEIGHT + $CONTROL_INDENT
    Next
    $g_aTest[$iIdx][$TST_ANSWERS] = $aAnswers
    GUICtrlSetPos($g_idInfo, Default, $iY)
    $iY += $BUTTON_HEIGHT
    $iY += $LABEL_HEIGHT + $CONTROL_INDENT
    WinMove($g_hGUI, "", Default, $g_aTest[0][1] == -1 ? (@DesktopHeight - $iY) / 2 : Default, Default, $iY)
    $g_aTest[0][1] = $iIdx
    GUISetState()
EndFunc   ;==>_Test_Start

Func _Test_Proc()
    Local $iIdx = $g_aTest[0][1], $aAnswers
    If GUICtrlRead(@GUI_CtrlId) = $g_aTest[$iIdx][$TST_CORRECT] Then
        GUISetState(@SW_HIDE)
        $aAnswers = $g_aTest[$iIdx][$TST_ANSWERS]
        For $i = 1 To $aAnswers[0][0]
            GUICtrlDelete($aAnswers[$i][$ANS_ID])
        Next
        TraySetState($TRAY_ICONSTATE_SHOW)
        Sleep($ANSWER_CORRECT_PAUSE * 1000 * 60)
        TraySetState($TRAY_ICONSTATE_HIDE)
        _Test_Start()
    Else
        _Test_SetState($GUI_DISABLE)
        $g_hTimer = TimerInit()
        GUICtrlSetState($g_idInfo, $GUI_SHOW)
        AdlibRegister("_Test_Timer")
    EndIf
EndFunc   ;==>_Test_Proc

Func _Test_SetState($iState)
    Local $iIdx = $g_aTest[0][1], $aAnswers = $g_aTest[$iIdx][$TST_ANSWERS]
    For $i = 1 To $aAnswers[0][0]
        GUICtrlSetState($aAnswers[$i][$ANS_ID], $iState)
    Next
EndFunc   ;==>_Test_SetState

Func _Test_Timer()
    Local $sInfo = StringFormat("Неверный ответ, до нового вопроса осталось: %i сек.", $ANSWER_INCORRECT_PAUSE * 60 - Round(TimerDiff($g_hTimer) / 1000))
    If GUICtrlRead($g_idInfo) <> $sInfo Then GUICtrlSetData($g_idInfo, $sInfo)
    If TimerDiff($g_hTimer) >= $ANSWER_INCORRECT_PAUSE * 1000 * 60 Then
        AdlibUnRegister("_Test_Timer")
        GUICtrlSetState($g_idInfo, $GUI_HIDE)
        _Test_SetState($GUI_ENABLE)
    EndIf
EndFunc   ;==>_Test_Timer

Func _GUICtrlPic_SetImageWithResize($idPic, $sFile, $bOnlyReduce = True)
    Local $tRect, $iPicW, $iPicH
    $tRect = _WinAPI_GetWindowRect(GUICtrlGetHandle($idPic))
    $iPicW = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left")
    $iPicH = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top")
    _GDIPlus_Startup()
    Local $hImage, $iImageW, $iImageH, $iScale, $hImageSc, $hHBMP, $hPrevImage
    $hImage = _GDIPlus_BitmapCreateFromFile($sFile)
    $iImageW = _GDIPlus_ImageGetWidth($hImage)
    $iImageH = _GDIPlus_ImageGetHeight($hImage)
    $iScale = _Min($iPicW / $iImageW, $iPicH / $iImageH)
    If $bOnlyReduce Then $iScale = _Min($iScale, 1)
    $hImageSc = _GDIPlus_ImageScale($hImage, $iScale, $iScale)
    $hHBMP = _GDIPlus_BitmapCreateDIBFromBitmap($hImageSc)
    $hPrevImage = GUICtrlSendMsg($idPic, $STM_SETIMAGE, 0, $hHBMP)
    If $hPrevImage Then _WinAPI_DeleteObject($hPrevImage)
    _GDIPlus_BitmapDispose($hImage)
    _GDIPlus_BitmapDispose($hImageSc)
    _WinAPI_DeleteObject($hHBMP)
    _GDIPlus_Shutdown()
EndFunc   ;==>_GUICtrlPic_SetImageWithResize

Func _Exit()
    Exit
EndFunc   ;==>_Exit
 

Вложения

Tempo

Скриптер
Сообщения
495
Репутация
144
Код:
#pragma compile(Icon, 1.ico)

#NoTrayIcon
#include <WindowsConstants.au3>
#include <GUIConstants.au3>
#include <GDIPlus.au3>
#include <WinAPIConstants.au3>
#include <WinAPISysWin.au3>
#include <WinAPISys.au3>
#include <Math.au3>
#include <TrayConstants.au3>
#include <MsgBoxConstants.au3>
#include <Array.au3>
Opt("TrayAutoPause", 0)
;~ Opt("TrayMenuMode", 1)
Opt("GUIOnEventMode", 1)
Opt("GUIResizeMode", $GUI_DOCKLEFT + $GUI_DOCKRIGHT + $GUI_DOCKMENUBAR)

Global Const $GUI_TITLE = "Тест"
Global Const $QUESTION_FILE = @ScriptDir & "\Тестовые вопросы и ответы.txt"
Global Const $ANSWER_CORRECT_PAUSE = 10 ;мин.
Global Const $ANSWER_INCORRECT_PAUSE = 1 ;мин.

Global Const $GUI_WIDTH = 425
Global Const $PIC_SIZE = 200
Global Const $PIC_ONLYREDUCE = False
Global Const $LABEL_HEIGHT = 20
Global Const $BUTTON_HEIGHT = 30
Global Const $CONTROL_INDENT = 10

Global Enum $TST_QUESTION, $TST_CORRECT, $TST_PIC, $TST_ANSWERS, $TST_MAX
Global Enum $ANS_ID, $ANS_TEXT, $ANS_MAX
Global Const $FIRST_ANSWER = -1
Global $g_hGUI, $g_idQuest, $g_idInfo, $g_idPic, _
        $g_aTests[][$TST_MAX] = [[0, $FIRST_ANSWER]], $g_hTimer
_GUI_Init()
_Test_Init()
_Test_Start()

While Sleep(10)
WEnd

Func _GUI_Init()
    $g_hGUI = GUICreate($GUI_TITLE, $GUI_WIDTH)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    Local $iY = $CONTROL_INDENT, $iFullWidth = $GUI_WIDTH - $CONTROL_INDENT * 2
    $g_idQuest = GUICtrlCreateLabel("", $CONTROL_INDENT, $iY, $iFullWidth, $LABEL_HEIGHT, BitOR($SS_CENTERIMAGE, $SS_CENTER))
    $iY += $LABEL_HEIGHT + $CONTROL_INDENT
    $g_idPic = GUICtrlCreatePic("", ($GUI_WIDTH - $PIC_SIZE) / 2, $iY, $PIC_SIZE, $PIC_SIZE, $SS_CENTERIMAGE)
    GUICtrlSetState(-1, $GUI_HIDE)
    $iY += $PIC_SIZE + $CONTROL_INDENT
    $g_idInfo = GUICtrlCreateLabel("", $CONTROL_INDENT, $iY, $iFullWidth, $LABEL_HEIGHT, BitOR($SS_CENTERIMAGE, $SS_CENTER))
    GUICtrlSetColor(-1, 0xFF0000)
    GUICtrlSetState(-1, $GUI_HIDE)
EndFunc   ;==>_GUI_Init

Func _Test_Init()
    Local $sRead = FileRead($QUESTION_FILE)
    Local $aData = StringRegExp($sRead, "(?i)Вопрос \d+\R(.+?)\R((?s).+?)\RПравильный:\R(.+)", $STR_REGEXPARRAYGLOBALMATCH)
    If @error Then Exit MsgBox($MB_ICONERROR + $MB_TOPMOST, $GUI_TITLE, StringFormat('Вопросы не найдены -> "%s"', $QUESTION_FILE))
    Local $iIdx, $iCount = UBound($aData)
    Dim $g_aTests[$iCount / 3 + 1][$TST_MAX] = [[0, -1]]
    For $i = 0 To $iCount - 1 Step 3
        $g_aTests[0][0] += 1
        $iIdx = $g_aTests[0][0]

        $g_aTests[$iIdx][$TST_QUESTION] = $aData[$i]
        $g_aTests[$iIdx][$TST_CORRECT] = $aData[$i + 2]
        _Test_MakeSubData($aData[$i + 1])
    Next
EndFunc   ;==>_Test_Init

Func _Test_MakeSubData($sData)
    Local $aSubData, $iIdx = $g_aTests[0][0], $iOffset = 1
    $aSubData = StringRegExp($sData, "(?i)Адрес:\R(.+)", $STR_REGEXPARRAYMATCH)
    If Not @error Then
        $iOffset = @extended
        If FileExists($aSubData[0]) Then
            $g_aTests[$iIdx][$TST_PIC] = $aSubData[0]
        Else
            MsgBox($MB_ICONERROR + $MB_TOPMOST, $GUI_TITLE, StringFormat('Изображение не найдено -> "%s"', $aSubData[0]))
        EndIf
    EndIf

    Local $aSplit, $sAnswers = "Некорректный вопрос (без ответов)", $bCorrect
    $aSubData = StringRegExp($sData, "(?i)Ответы:\R((?s).+)", $STR_REGEXPARRAYMATCH, $iOffset)
    If Not @error Then $sAnswers = $aSubData[0]
    $aSplit = StringSplit(StringStripCR($sAnswers), @LF)
    Local $aAnswers[$aSplit[0] + 1][$ANS_MAX] = [[$aSplit[0]]]
    For $i = 1 To $aSplit[0]
        $aAnswers[$i][$ANS_TEXT] = $aSplit[$i]
        If Not $bCorrect Then $bCorrect = $g_aTests[$iIdx][$TST_CORRECT] = $aAnswers[$i][$ANS_TEXT]
    Next
    If Not $bCorrect Then MsgBox($MB_ICONERROR + $MB_TOPMOST, $GUI_TITLE, StringFormat('Верный ответ не найден -> "%s"', $g_aTests[$iIdx][$TST_QUESTION]))
    $g_aTests[$iIdx][$TST_ANSWERS] = $aAnswers
EndFunc   ;==>_Test_MakeSubData

Func _Test_Start()
    Local $iCurIdx = $g_aTests[0][1]
    Do
        $iCurIdx = Random(1, $g_aTests[0][0], 1)
    Until $iCurIdx <> $g_aTests[0][1]

    GUICtrlSetData($g_idQuest, $g_aTests[$iCurIdx][$TST_QUESTION])
    Local $iY = $CONTROL_INDENT * 2 + $LABEL_HEIGHT, $iFullWidth = $GUI_WIDTH - $CONTROL_INDENT * 2
    If $g_aTests[$iCurIdx][$TST_PIC] And _GUICtrlPic_SetImageWithResize($g_idPic, $g_aTests[$iCurIdx][$TST_PIC], $PIC_ONLYREDUCE) Then
        GUICtrlSetState($g_idPic, $GUI_SHOW)
        $iY += $PIC_SIZE + $CONTROL_INDENT
    Else
        If @error Then MsgBox($MB_ICONERROR + $MB_TOPMOST, $GUI_TITLE, StringFormat('Не удалось установить изображение -> "%s"', $g_aTests[$iCurIdx][$TST_PIC]))
        GUICtrlSetState($g_idPic, $GUI_HIDE)
    EndIf
    $aAnswers = $g_aTests[$iCurIdx][$TST_ANSWERS]
    _ArrayShuffle($aAnswers, 1)
    For $i = 1 To $aAnswers[0][0]
        $aAnswers[$i][$ANS_ID] = GUICtrlCreateButton($aAnswers[$i][$ANS_TEXT], $CONTROL_INDENT, $iY, $iFullWidth, $BUTTON_HEIGHT)
        GUICtrlSetOnEvent(-1, "_Test_Proc")
        $iY += $BUTTON_HEIGHT + $CONTROL_INDENT
    Next
    $g_aTests[$iCurIdx][$TST_ANSWERS] = $aAnswers
    GUICtrlSetPos($g_idInfo, Default, $iY)
    $iY += $LABEL_HEIGHT + $CONTROL_INDENT
    _GUIResize($g_hGUI, Default, (($g_aTests[0][1] == $FIRST_ANSWER) ? ((@DesktopHeight - $iY) / 2) : Default), Default, $iY)
    $g_aTests[0][1] = $iCurIdx

    GUISetState()
EndFunc   ;==>_Test_Start

Func _Test_Proc()
    Local $iCurIdx = $g_aTests[0][1], $aAnswers
    If GUICtrlRead(@GUI_CtrlId) = $g_aTests[$iCurIdx][$TST_CORRECT] Then
        GUISetState(@SW_HIDE)
        $aAnswers = $g_aTests[$iCurIdx][$TST_ANSWERS]
        For $i = 1 To $aAnswers[0][0]
            GUICtrlDelete($aAnswers[$i][$ANS_ID])
        Next
        TraySetState($TRAY_ICONSTATE_SHOW)
        Sleep($ANSWER_CORRECT_PAUSE * 1000 * 60)
        TraySetState($TRAY_ICONSTATE_HIDE)
        _Test_Start()
    Else
        _Answers_SetState($GUI_DISABLE)
        $g_hTimer = TimerInit()
        GUICtrlSetState($g_idInfo, $GUI_SHOW)
        AdlibRegister("_Test_Timer")
    EndIf
EndFunc   ;==>_Test_Proc

Func _Answers_SetState($iState)
    Local $iCurIdx = $g_aTests[0][1], $aAnswers = $g_aTests[$iCurIdx][$TST_ANSWERS]
    For $i = 1 To $aAnswers[0][0]
        GUICtrlSetState($aAnswers[$i][$ANS_ID], $iState)
    Next
EndFunc   ;==>_Answers_SetState

Func _Test_Timer()
    Local $sInfo = StringFormat("Неверный ответ, до нового вопроса осталось: %i сек.", $ANSWER_INCORRECT_PAUSE * 60 - Round(TimerDiff($g_hTimer) / 1000))
    If GUICtrlRead($g_idInfo) <> $sInfo Then GUICtrlSetData($g_idInfo, $sInfo)
    If TimerDiff($g_hTimer) >= $ANSWER_INCORRECT_PAUSE * 1000 * 60 Then
        AdlibUnRegister("_Test_Timer")
        GUICtrlSetState($g_idInfo, $GUI_HIDE)
        _Answers_SetState($GUI_ENABLE)
    EndIf
EndFunc   ;==>_Test_Timer

Func _GUICtrlPic_SetImageWithResize($idPic, $sFile, $bOnlyReduce = True)
    Local $tRect, $iPicW, $iPicH, $iError = 0
    $tRect = _WinAPI_GetWindowRect(GUICtrlGetHandle($idPic))
    $iError += @error
    $iPicW = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left")
    $iPicH = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top")
    _GDIPlus_Startup()
    Local $hImage, $iImageW, $iImageH, $iScale, $hImageSc, $hHBMP, $hPrevImage
    $hImage = _GDIPlus_BitmapCreateFromFile($sFile)
    $iError += @error
    $iImageW = _GDIPlus_ImageGetWidth($hImage)
    $iImageH = _GDIPlus_ImageGetHeight($hImage)
    $iScale = _Min($iPicW / $iImageW, $iPicH / $iImageH)
    If $bOnlyReduce Then $iScale = _Min($iScale, 1)
    $hImageSc = _GDIPlus_ImageScale($hImage, $iScale, $iScale)
    $hHBMP = _GDIPlus_BitmapCreateDIBFromBitmap($hImageSc)
    $hPrevImage = GUICtrlSendMsg($idPic, $STM_SETIMAGE, 0, $hHBMP)
    If $hPrevImage Then _WinAPI_DeleteObject($hPrevImage)
    _GDIPlus_BitmapDispose($hImage)
    _GDIPlus_BitmapDispose($hImageSc)
    _WinAPI_DeleteObject($hHBMP)
    _GDIPlus_Shutdown()
    Return SetError($iError, 0, Not $iError)
EndFunc   ;==>_GUICtrlPic_SetImageWithResize

Func _GUIResize($hGUI, $iX, $iY = Default, $iW = Default, $iH = Default)
    Local $aClientWH = WinGetClientSize($hGUI)
    If @error Then Return SetError(@error, 0, 0)
    Local $aXYWH = WinGetPos($hGUI)
    If @error Then Return SetError(@error, 0, 0)
    If $iW <> Default Then $iW += $aXYWH[2] - $aClientWH[0]
    If $iH <> Default Then $iH += $aXYWH[3] - $aClientWH[1]
    Return WinMove($hGUI, "", $iX, $iY, $iW, $iH)
EndFunc   ;==>_GUIResize

Func _Exit()
    Exit
EndFunc   ;==>_Exit
 
Верх