Python tkinter не может использовать функцию Entry.get () [решено] - PullRequest
0 голосов
/ 05 марта 2020

Итак, я уже некоторое время работаю над приложением для викторин (около 4 дней). Мне удалось сделать всю логическую часть кода (выполнение тестов, обработка вопросов теста, вывод результатов и т. Д. c.) Я знаю, что этот код не является ни лучшим, ни самым эффективным, каким только может быть, но я Я просто новичок. В любом случае, функция get () для функции ввода для tkinter ничего не возвращает. Я знаю, что есть способ исправить это, но я не уверен, как реализовать решение с внешним l oop. Пожалуйста, помогите мне. Вот мой код:

import random
from time import sleep
import tkinter as tk
from tkinter import *
import threading

class App(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.start()

    def callback(self):
        self.root.quit()

    def run(self):
        self.root = tk.Tk()
        self.root.protocol("WM_DELETE_WINDOW", self.callback)

        #label = tk.Label(self.root, text="Hello World")
        #label.pack()

        #Button(self.root, text = "Choose", command=btnPressed).pack()

        tk.Label(self.root, text="Answer: ").grid(row=0,column=0)
        #answerField_get = StringVar()
        answerField = tk.Entry(self.root)
        answerField.grid(row=0, column=1)
        #Button(self.root, text='Show').grid(row=3, column=1, sticky=tk.W, pady=4)
        print(str(answerField.get()))
        Button(self.root, text='Show', command = lambda arg1=answerField.get():btnPressed("<"+str(arg1)+">")).grid(row=3, column=1, sticky=tk.W, pady=4)
        self.root.mainloop()

    def sendTMP(self, sendStr):
        btnPressed(sendStr)

SCORE_SET = []
qasTmp = {}
qas = {}
qasSequenced = {}
incorrectResponses = []
incorrectResponses_replies = []
quiztaker_name = ""
attachAnsCode = "%% Fun fact: rgb computer parts lovers are somewhat weird hehe %%********^^&&^^&&^^&&"
qasQsSequenced = False
qasQsL = 0
qasQsL_divisionFactor = 2
qasINDEX = 0
err_noCode = "<!>NO_CODE<!>"
codes_answerCorrect = "A_C"
codes_answerIncorrect = "A_I"
answerCode = err_noCode
score = 0
randQs = False

# File
# the metadata will corrupt the reading from the file, a separate file, created in the targeted system, must be used to properly read the data.
# comment out the file name that is not being used.
filename_windows = "qas-windows"
filename_rpi = "qas-rpi"

filename = filename_windows
fileformat = "txt"
file_name_format = filename + "." + fileformat
spaceIndicator = "|"
char_commentLine_qasFile = "*"
char_newline = "`"

print("Information about modes: ")
print("     *Easy: No point deductions for an incorrect response")
print("     *Hard: One point deducted for every incorrect response")

modes_err = "0"
modes_ez = "1"
modes_hard = "2"
gameOn = False
selectedMode = modes_err
askReplay = True
data_prev = []

with open("SCORES.txt", 'r') as scores_prev:
    data_prev = scores_prev.readlines()
    scores_prev.close()

for i in range(0, len(data_prev)):
    SCORE_SET.append(data_prev[i])

def btnPressInform():
    print("A button has been pressed!")

def importAndClean():
    # import questions from qas-windows.txt
    with open(file_name_format, 'r') as document:
        for line in document:
            if line.strip():
                key, value = line.split(None, 1)
                if key[0] != char_commentLine_qasFile:  # Custom comments for the txt file
                    qasTmp[key] = value.split()

                    # Clean up dictionary input from the txt file
    for i in range(0, len(qasTmp)):  # FIVE FOR LOOPS!!!! (FOUR IN THIS ONE)
        for ii in qasTmp:
            output = ""
            output_ans = ""

            for iii in range(0, len(ii)):
                if ii[iii] != spaceIndicator:
                    output += ii[iii]
                else:
                    output += " "
            for iiii in range(0, len(qasTmp[ii])):
                TEMP = str(qasTmp[ii])
                for iiiii in range(2, len(TEMP) - 2):  # IGNORE [' and ']
                    # print(TEMP[iiiii])
                    if TEMP[iiiii] != spaceIndicator:
                        output_ans += TEMP[iiiii]
                    else:
                        output_ans += " "
            # print(output + " : " + output_ans) #Output question: answer
            qas[output] = output_ans


importAndClean()


def getL():
    qasQsL = len(qas) / qasQsL_divisionFactor  # only ask 1/qasQsL_divisionFactor the questions
    qasQsL = int(qasQsL)  # round to an integer as odd numbers will end in .5 after division
    if qasQsL < 1:
        qasQsL = 1  # Have atleast ONE question
    return qasQsL


def debug1(keys, vals, index, i):
    print(str(index) + "/" + str((len(keys) - 1)))
    print(keys)
    print(vals)
    print()
    print(keys[index] + " : " + vals[index] + "\n")
    print("Sorting original index " + str(i) + " at random index " + str(index))


def debug2(keys, vals, index):
    print(keys)
    print(vals)
    print("\n")


def debugFinal():
    print("Temp (OG reading): ")
    print(qasTmp)
    print("\nQAS (Non-sequenced, cleaned): ")
    print(qas)
    print("\nQAS Sequenced (Randomly sequenced, cleaned): ")
    print(qasSequenced)


def randomize(qasQsL_tmp):
    qas_keys = list(qas.keys())
    qas_vals = list(qas.values())

    if randQs == False:
        qasQsL_tmp = len(qas_keys)  # all questions
        print("You will be asked all " + str(qasQsL_tmp) + " questions")
    else:
        qasQsL_tmp = getL()  # random question
        print("You will be asked " + str(qasQsL_tmp) + " questions out of " + str(len(qas)) + " possible questions!")
    print("\n\nRandomly sequencing questions...")
    for i in range(0, qasQsL_tmp):
        INDEX = random.randint(0, qasQsL_tmp - 1)
        # debug1(qas_keys, qas_vals, INDEX, i)
        qasSequenced[qas_keys[INDEX]] = qas_vals[INDEX]
        qas_keys.pop(INDEX)
        qas_vals.pop(INDEX)
        qasQsL_tmp -= 1
        # debug2(qas_keys, qas_vals, INDEX)
        sleep(0.05)
    # debugFinal()
    print("Done sequencing! Starting quiz now! \n\n")
    return "0"


def quizController(index):
    qas_keys = list(qasSequenced.keys())
    qas_vals = list(qasSequenced.values())
    # print(qas_keys)
    # print(qas_vals)
    lines = []
    lines_index = 0
    tmp = ""
    # Splitter
    for i in range(0, len(qas_keys[index])):
        if lines_index < len(qas_keys[index]) - 1:
            if qas_keys[index][i] != char_newline:
                tmp += qas_keys[index][i]
            else:
                lines.append(tmp)
                tmp = ""
    lines.append(tmp)

    # Multiple choice
    mChoiceQ = False
    mChoice_startBrackets = 0
    mChoice_endBrackets = 0
    mChoice_options = []
    mChoice_numOptions = 0
    mChoice_seperatorsAt = []
    for i in range(0, len(qas_keys[index])):
        if qas_keys[index][i] == "[":
            mChoice_startBrackets = i
            mChoiceQ = True
        elif qas_keys[index][i] == "]":
            mChoice_endBrackets = i
        elif qas_keys[index][i] == "/":
            mChoice_seperatorsAt.append(i)

    if mChoiceQ == True:
        TEMP = ""
        for i in range(mChoice_startBrackets, mChoice_endBrackets + 1):
            if qas_keys[index][i] != "[":
                if qas_keys[index][i] != "/" and qas_keys[index][i] != "]":
                    TEMP += qas_keys[index][i]
                else:
                    mChoice_options.append(TEMP)
                    TEMP = ""

    mChoice_numOptions = len(mChoice_seperatorsAt) + 1
    # Default options (yes, no) full names
    for i in range(0, len(mChoice_options)):
        if mChoice_options[i].lower() == "y":
            mChoice_options.append("yes")
        elif mChoice_options[i].lower() == "n":
            mChoice_options.append("no")

    # if mChoiceQ == True:
    #    print("It is a multiple choice question! There are " + str(mChoice_numOptions) + " options. They are: ")
    #    print(mChoice_options)

    print("\nQuestion " + str(index + 1) + "/" + str(qasQsL) + ":")

    for i in range(0, len(lines)):
        print(lines[i])

    # answer = ""
    answer = input(">")
    # answer = input(qas_keys[index]+ ": ")

    if mChoiceQ == False:
        if len(answer) > 0:
            if answer.lower() == str(qas_vals[index]).lower():
                return codes_answerCorrect
            else:
                incorrectResponses.append(qas_keys[index])
                incorrectResponses_replies.append(answer)
                # print("DEBUG: Incorrect response! Expected '" + str(qas_vals[index]).lower() + "', received " + answer.lower())
                return codes_answerIncorrect
        else:
            print("Please insert an answer!")
    else:
        allowedResponse = False
        for i in range(0, len(mChoice_options)):
            if answer.lower() == mChoice_options[i].lower():
                allowedResponse = True

        if allowedResponse == True:
            ans = qas_vals[index].lower()
            yn = False
            ans_yesno = ""
            if ans.lower() == "y" or ans.lower() == "n":
                yn = True
            else:
                yn = False

            if yn == True:
                if ans == "y":
                    ans_yesno = "yes"
                elif ans == "n":
                    ans_yesno = "no"

            if len(answer) > 0:
                if yn == True:
                    if answer.lower() == ans.lower() or answer.lower() == ans_yesno.lower():
                        return codes_answerCorrect
                    else:
                        return codes_answerIncorrect
                        incorrectResponses.append(qas_keys[index])
                        incorrectResponses_replies.append(answer)
                else:
                    if answer.lower() == ans.lower():
                        return codes_answerCorrect
                    else:
                        return codes_answerIncorrect
                        incorrectResponses.append(qas_keys[index])
                        incorrectResponses_replies.append(answer)
            else:
                print("Please insert an answer!")
        else:
            print("Invalid response! You may only enter the following: " + str(mChoice_options))


def saveScore():
    # Clear file!
    score_file_CLEAR = open("SCORES.txt", "wt")
    score_file_CLEAR.close()
    # Save contents
    score_file = open("SCORES.txt", "wt")
    for i in range(0, len(SCORE_SET)):
        score_file.write(SCORE_SET[i])
    print("Done saving!")

def btnPressed(tmp):
    print(tmp)

app = App()

while True:
    qasQsL = len(qasSequenced)
    if gameOn == True and selectedMode != modes_err:
        if qasQsSequenced == True:
            if qasINDEX < qasQsL:
                answerCode = quizController(qasINDEX)
        else:
            output = randomize(qasQsL)

        if output == "0":
            qasQsSequenced = True

        if qasINDEX < qasQsL:
            if answerCode == codes_answerCorrect:
                score += 1
                qasINDEX += 1
                # print("DEBUG: Correct! Score set to: " + str(score))
            elif answerCode == codes_answerIncorrect:
                if selectedMode == modes_hard:
                    score -= 1
                qasINDEX += 1
                # print("Score set to: " + str(score))
        else:
            print("")
            if qasQsL != 0:
                score_per = score / qasQsL
                if score_per < 0:
                    score_per = 0
                if score < 0:
                    score = 0
                    print("You score was lower than 0, therefore it was set to 0")

                # print("Your score: " + str(score) + "/" + str(len(qasSequenced)) + " (" + str(int(score_per*100)) + "%)")
                # if score != qasQsL:
                #    print("You responded to the following questions incorrectly:")
                #    print(incorrectResponses)

                if score / qasQsL == 1:
                    SCORE_SET.append(quiztaker_name + " scored " + str(score) + " out of " + str(qasQsL) + "(" + str(
                        int(score / qasQsL) * 100) + "%). PART OF Qs: " + str(
                        int(randQs)) + " at division factor 1/" + str(qasQsL_divisionFactor) + ", MODE: " + str(
                        int(selectedMode)) + "\n")
                if score / qasQsL != 1:
                    SCORE_SET.append(quiztaker_name + " scored " + str(score) + " out of " + str(qasQsL) + " (" + str(
                        int(score / qasQsL) * 100) + "%). PART OF Qs: " + str(
                        int(randQs)) + " at division factor 1/" + str(qasQsL_divisionFactor) + ", MODE: " + str(
                        int(selectedMode)) + " They got the following questions wrong: \n")
                    for i in range(0, len(incorrectResponses)):
                        SCORE_SET.append("      " + str(i + 1) + ") " + incorrectResponses[i] + " --RESPONSE-- " +
                                         incorrectResponses_replies[i] + "\n")
                    SCORE_SET.append("\n")

                saveScore()
                qasQsSequenced = False
                gameOn = False
                print("\nGame over!")
                askReplay = True

            else:
                continue
    elif askReplay == False:
        TEMP = input("What mode would you like? (E = Easy, H = Hard): ")
        if len(str(TEMP)) > 0:
            if str(TEMP).lower() == "e":
                selectedMode = modes_ez
                gameOn = True
                print("Set mode to: NO POINT DEDUCTIONS")
            elif str(TEMP).lower() == "h":
                selectedMode = modes_hard
                gameOn = True
                print("Set mode to: POINT DEDUCTIONS ALLOWED")
            else:
                print("Error: Undefined response. Please try again!")

    elif askReplay == True:
        TEMP = input("Would you like to (re)do the quiz? (Y/N): ")
        if len(str(TEMP)) > 0:
            if str(TEMP).lower() == "y":
                askReplay = False
                qasQsSequenced = False
                qasQsL = 0
                qas.clear()
                qasSequenced.clear()
                qasTmp.clear()
                qasINDEX = 0
                incorrectResponses.clear()
                answerCode = err_noCode
                score = 0
                selectedMode = modes_err
                importAndClean()
                randQs = False
                USER_TEMP = input("Please enter your name >")
                if len(USER_TEMP) > 0:
                    quiztaker_name = str(USER_TEMP)
                    print("Welcome " + quiztaker_name + "!")
                USER_TEMP = input("Would you like all questions (a) or a part of the questions(p)? (A/P) > ")
                if len(USER_TEMP) > 0:
                    if USER_TEMP.lower() == "a":
                        print("Set to all questions!")
                        randQs = False
                    elif USER_TEMP.lower() == "p":
                        print("Set to 1/" + str(qasQsL_divisionFactor) + " questions (pre-set variable)")
                        randQs = True
                    else:
                        print("Undefined response! Setting to default value (ALL)")
                        randQs = False
                    gameOn = False
                    askReplay = False
            elif str(TEMP).lower() == "n":
                selectedMode = modes_hard
                gameOn = False
                print("Exiting now!")
                saveScore()
                sleep(2)
                exit(0)
            else:
                print("Error: Undefined response. Please try again!")

1 Ответ

1 голос
/ 05 марта 2020

Entry() не работает как input(). Он не ждет ваших данных, но только сообщает tkitner, что вы хотите отобразить Entry виджет (и mainloop() отобразит его), а Python переходит к следующим строкам кода и запускает print(str(answerField.get())) перед он даже отображает окно - поэтому вы пытаетесь получить из пустого Entry.

Вы должны получить его в функции, назначенной для Button, которую вы будете нажимать после ввода текста в Entry.

Та же проблема с

lambda arg1=self.answerField.get():print(arg1)

, который присваивает args значение из Entry только один раз, когда lambda определено в начале - так что получается пустая строка. Вы должны использовать его внутри функции

command=lambda:print(self.answerField.get())

или создать нормальную функцию и назначить ее кнопке.


Минимальный рабочий код

import tkinter as tk
import threading

class App(threading.Thread):

    def run(self):
        self.root = tk.Tk()
        #self.root.protocol("WM_DELETE_WINDOW", self.on_close)

        self.answerField = tk.Entry(self.root)
        self.answerField.grid(row=0, column=1)

        #b = tk.Button(self.root, text='Show', command=lambda:print(self.answerField.get()))
        b = tk.Button(self.root, text='Show', command=self.on_click)
        b.grid(row=1, column=1)

        self.root.mainloop()

    def on_click(self):
        print(self.answerField.get())

    #def on_close(self):
    #    self.root.destroy()

App().start()
#App().run()
...