Python Forum
[Tkinter] previous and next buttons - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: GUI (https://python-forum.io/forum-10.html)
+--- Thread: [Tkinter] previous and next buttons (/thread-34271.html)



previous and next buttons - rwahdan - Jul-13-2021

Hi

I have a db and i got the data and put them in python lists so I can get the records places 0,1,2...
for the first record i am able to assign the right data having the index of the first element which is [0]. Now if I click the button named next, what i can do to go to next record?

    global thephoto
    global answer1
    global answer2
    global answer3
    global answer4
    global correct_answer    

    thephoto = []
    answer1 = []
    answer2 = []
    answer3 = []
    answer4 = []
    correct_answer = []

    conn2 = sqlite3.connect('emsat_data.db')
    c2 = conn2.cursor()
    c2.execute("SELECT * from math_exam")
    conn2.commit()
    records = c2.fetchall()

    for record in records:
        thephoto.append(str(record[0]))
        answer1.append(str(record[1]))
        answer2.append(str(record[2]))
        answer3.append(str(record[3]))
        answer4.append(str(record[4]))
        correct_answer.append(str(record[5]))
        #how many questions are there in db
for first records I can access calling index [0] of each list but I think this is not the right way to deal with this. Any suggestions or tutorials appreciated.


RE: previous and next buttons - deanhystad - Jul-13-2021

You are not using "global" correctly. In this code "global" does nothing.
global thephoto
global answer1
global answer2
global answer3
global answer4
global correct_answer 
"global" tells Python to look for the variable in the global/module context. The problem is that this code is in the global/module context. It only makes sense to use the "global" keyword inside a function. You have no functions, so you should not be using "global".
a = None

def function():
    global a  # Tells Python to use global a instead of making function.a
    a = 5
But even if your database query were inside a function you still wouldn't have an need for "global".
thephoto = []
answer1 = []
answer2 = []
answer3 = []
answer4 = []
correct_answer = []

def get_quiz(database_name):
    conn = sqlite3.connect(database_name).cursor
    cursor = conn.cursor()
    cursor.execute("SELECT * from math_exam")
    conn.commit()
    
    for record in cursor.fetchall():
        thephoto.append(str(record[0]))
        answer1.append(str(record[1]))
        answer2.append(str(record[2]))
        answer3.append(str(record[3]))
        answer4.append(str(record[4]))
        correct_answer.append(str(record[5]))

get_quiz('emsat_data.db')
answer1 is not assigned inside function get_quiz(). We do not need a "global answer1" to force Python to use answer1 from the global/module scope. The function can see module variables and only modifies the list referenced by answer1. If there is no assignment (answer1 = something) there is no need to use "global".

Your code would benefit from a bit of structure. Structure can be introduced by breaking the code into functions, as I did in the example above. It can also be structured by structuring the data. In the example below I created a class to keep related data together.
class QuizQuestion:
    def __init__(self, question, answers, correct_answer):
        self.question = question
        self.answers = answers
        self.correct_answer = correct_answer

def get_quiz(database_name, quiz_name):
    quiz = []
    conn = sqlite3.connect(database_name).cursor
    cursor = conn.cursor()
    cursor.execute('SELECT * from' + quiz_name)
    conn.commit()
    
    for record in cursor.fetchall():
        quiz.append(QuizQuestion(record[0], record[1:-1], record[-1]))

quiz = get_quiz('emsat_data.db', 'math_exam')
This is much better than having a list of question and a list of possible answer_a and possible answer_b and so on. For one thing, I can now have True/False as well as multiple choice, and I can have different number of choices for each question. Being a class, QuizQuestion can do more than just store data. It can have functions. Class functions are called methods, and we could add a method that will ask a quiz question and return if the answer is correct.
class QuizQuestion:
    def __init__(self, question, answers, correct_answer):
        self.question = question
        self.answers = answers
        self.correct_answer = correct_answer

    def ask(self):
        print(self.question)
        for i, answer in enumerate(self.answers):
            print(f'{i+1:>5}: {answer}')
        return input('Answer: ') == self.correct_answer

print(QuizQuestion('What is 3 + 2?', ['1', '3', '6', '5', '11'], '4').ask())
print(QuizQuestion('What is 6 / 2?', [], '3').ask())
Now that all the question parts are all collected together, it is easy to get the related parts.
class QuizQuestion:
    """I am a question in a quiz"""
    def __init__(self, record):
        self.question = record[0]
        self.guesses = record[1:-1]
        self.answer = record[-1]

class Quiz:
    """I am a collection of quiz questions"""
    def __init__(self, name):
        conn = sqlite3.connect('emsat_data.db').cursor
        cursor = conn.cursor()
        cursor.execute("SELECT * from " + name)
        conn.commit()
        self.questions = [QuizQuestion(question) for question in cursor.fetchall()]

    def __iter__(self):
        """Return iterator to loop through the questions"""
        return self.questions  # A list has an iterator

    def __len__(self):
        """Return how many questions in the quiz"""
        return len(self.questions)

quiz = Quiz('grade6math')
for question in quiz:
    print(question.question)
    for guess in question.guesses:
        print(guess)
    print('The correct answer is', question.answer)