Python Forum
[Tkinter] tkinter freezes by clicking button
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] tkinter freezes by clicking button
#20
*** UPDATES ***

- save function checks wether sudokufile dir already exists. if not -> makedir
- filepaths should be platform independent
- init function can now handle cases: where there are non sudoku.txt files in the dir, where sudoku.txt file does not contain a valid sudoku
- sudoku.txt files can also use "0" as " "
- progressbar implemented
- print button works
- main function changed the way you suggested

# SudokuSolver_main.py

if __name__ == '__main__':
    import SudokuSolver_class as Sudokuolver
    from tkinter import Tk

    def main():
        root = Tk()
        app = Sudokuolver.SudokuSolver(root)
        root.mainloop()

    main()
# SudokuSolver_class.py

import os
import SudokuSolver_solver as Solver
from random import randint
from tkinter import ttk
from tkinter import *
from tkcallasync import tk_call_async, MULTIPROCESSING


class SudokuSolver(Frame):

    disabled = False
    backtrack_ctr = 0
    sudoku = [[" " for col in range(9)] for row in range(9)]
    solution = [[" " for col in range(9)] for row in range(9)]
    exampleSudoku = [[' ',' ',' ','2','1',' ',' ',' ',' '],
                     [' ',' ','7','3',' ',' ',' ',' ',' '],
                     [' ','5','8',' ',' ',' ',' ',' ',' '],
                     ['4','3',' ',' ',' ',' ',' ',' ',' '],
                     ['2',' ',' ',' ',' ',' ',' ',' ','8'],
                     [' ',' ',' ',' ',' ',' ',' ','7','6'],
                     [' ',' ',' ',' ',' ',' ','2','5',' '],
                     [' ',' ',' ',' ',' ','7','3',' ',' '],
                     [' ',' ',' ',' ','9','8',' ',' ',' ']]

    def __init__(self, parent):
        Frame.__init__(self, parent, name='frame')
        self.parent = parent
        self.initUI()
        self.blankSUDOKU()
        self.sudokudir = os.path.join(os.getcwd(), 'sudokus')

    def initUI(self):
        self.message_txt = StringVar()
        self.values = {}

        self.parent.title('Sudoku Solver')
        self.pack(fill=BOTH, expand=True)

        self.message = Label(self, textvariable=self.message_txt)
        self.message.grid(row=10,column=0,columnspan=9, sticky=E+W)

        self.solveBtn = Button(self, text="solve",width=6,command=self.execute_solver)
        self.solveBtn.grid(row=0,column=0)

        self.newBtn = Button(self, text="new",width=6,command=self.blankSUDOKU)
        self.newBtn.grid(row=0,column=1)

        self.initBtn = Button(self, text="init",width=6,command=self.initSUDOKU)
        self.initBtn.grid(row=0,column=2)

        self.printBtn = Button(self, text="print",width=6,command=self.printALL)
        self.printBtn.grid(row=0,column=8)

        self.checkBtn = Button(self, text="check",width=6,command=self.checkSOLUTION)
        self.checkBtn.grid(row=0,column=6)

        self.saveBtn = Button(self, text="save",width=6,command=self.saveSUDOKU)
        self.saveBtn.grid(row=0,column=7)

        self.pbar = ttk.Progressbar(self, mode='indeterminate')
        self.pbar.grid(row=11,column=0, columnspan=9, sticky=W+E)

    # --- clear all fields and delete all values in sudoku[][] and solution[][] --- #
    def blankSUDOKU(self):
        self.message_txt.set('')
        for row in range(9):
            for col in range(9):
                self.sudoku[row][col] = ' '
                self.solution[row][col] = ' '
                self.numEntry = Entry(self, width=5, justify=CENTER,
                                 font="Helvetica 12 bold")
                self.values[row,col] = self.numEntry
                self.numEntry.grid(row=row+1,column=col, ipady=5)

    # ----- get a random Sudoku from textfiles ----- #
    def initSUDOKU(self):
        self.blankSUDOKU()
        self.message_txt.set('')
        Files = []
        valid = True
        for filename in os.listdir(self.sudokudir):
            if filename.startswith('sudoku') and filename.endswith('.txt'):
                Files.append(filename)
        L = len(Files)
        if L < 1:
            self.message_txt.set('No Sudokus saved, yet! Try this one')
            self.sudoku = self.copySUDOKU(self.exampleSudoku)
        else:
            # ----- fill sudoku array with values from textfile ----- #
            R = randint(0, L-1)
            sudokuFile = open(os.path.join(self.sudokudir,Files[R]))
            row, col = 0, 0
            for value in sudokuFile.read():
                if value.isdigit() or value==' ':
                    if value=='0': value = ' '      # zeros can also be used as blanks
                    self.sudoku[row][col] = value
                    col += 1
                    if col==9:
                        if row==8: break
                        row += 1
                        col = 0
            sudokuFile.close()
            valid = self.checkSUDOKU(self.sudoku)[0]
        if not valid:
            self.message_txt.set('%s does not contain a valid sudoku' % Files[R])
        else:
        # ----- make values from random sudoku appear in the GUI ----- #
            for row in range(9):
                for col in range(9):
                    value = self.sudoku[row][col]
                    if value!=' ':
                        self.values[row,col].insert(0,value)

    def printSUDOKU(self, matrix):
        for row in range(9):
            print("|-----------------------------------|")
            for col in range(9):
                print("| " + matrix[row][col] + " ",end='')
            print("|")
        print("|-----------------------------------|")

    def printALL(self):
        print('Sudoku:')
        self.printSUDOKU(self.sudoku)
        print('Solution:')
        self.printSUDOKU(self.solution)

    def saveSUDOKU(self):
       CHECK = self.checkSUDOKU(self.solution)
       if CHECK[0] and CHECK[1]:    # check if Sudoku is valid and complete
           filecount = 1    # variable for how many sudoku files are already existing
           if not os.path.exists(self.sudokudir): os.makedirs(self.sudokudir)
           while os.path.isfile(self.path_to("sudoku%s.txt" % filecount)):
               filecount += 1
           sudokuFile = open(self.path_to("sudoku%s.txt" % filecount), 'w')
           solutionFile = open(self.path_to("solution%s.txt" % filecount), 'w')
           # ----- create textfiles for sudoku and the solution ----- #
           for row in range(9):
               for col in range(9):
                   sudokuFile.write(self.sudoku[row][col])
                   solutionFile.write(self.solution[row][col])
               sudokuFile.write('\n')
               solutionFile.write('\n')
           sudokuFile.close()
           solutionFile.close()
           self.message_txt.set('Files saved...')
       else:
           self.message_txt.set('Sudoku must be valid and complete!')

    def copySUDOKU(self, matrix):
        matrix_copy = [[" " for col in range(9)] for row in range(9)]
        for row in range(9):
            for col in range(9):
                matrix_copy[row][col] = matrix[row][col]
        return matrix_copy

    # ----- check if user input makes sense -----#
    def checkSUDOKU(self, matrix):
        valid, complete, ctr = True, True, 0
        for row in range(9):
            for col in range(9):
                value = matrix[row][col]
                if value!=' ':
                    matrix[row][col]=' '
                    if not self.consistent(matrix, row, col, value):
                        valid, complete = False, True
                        return valid, complete, row, col
                    matrix[row][col] = value
                    ctr += 1
                else: complete = False
        if ctr<17: valid = False
        return valid, complete

    # ----- check if solution is valid ----- #
    def checkSOLUTION(self):
        self.getinput(self.sudoku)
        CHECK = self.checkSUDOKU(self.sudoku)
        if CHECK[0] and CHECK[1]: self.message_txt.set("Solution correct!")
        elif not CHECK[1]: self.message_txt.set("Sudoku is not complete!")
        elif not CHECK[0]: self.message_txt.set("Mistake at row %s, col %s"
                                      % (CHECK[2], CHECK[3]))

    # ----- write user input into values{} ----- #
    def getinput(self, matrix):
        for row in range(9):
            for col in range(9):
                value = self.values[row,col].get()
                if value=='': matrix[row][col] = ' '
                elif len(value)!=1: matrix[row][col] = ' '
                elif not value.isdigit(): matrix[row][col] = ' '
                elif int(value)<1 or int(value)>9: matrix[row][col] = ' '
                else : matrix[row][col] = value

    # ----- check if this input leads to a valid solution ----- #
    def consistent(self, matrix, row, col, value):
        for i in range(9):
            if matrix[row][i]==value: return False
            if matrix[i][col]==value: return False
        rowStart = row - row%3
        colStart = col - col%3
        for m in range(3):
            for k in range(3):
                if matrix[rowStart+k][colStart+m]==value: return False
        return True

    def path_to(self, name):
        return os.path.join(self.sudokudir, name)

    def execute_solver(self):
        self.getinput(self.sudoku) # user input from GUI -> sudoku array
        if not self.checkSUDOKU(self.sudoku)[0]:    # check if user input makes sense
            self.message_txt.set("This sudoku does not have a solution")
        else:
            if self.disabled:
                self.message_txt.set("warning, It's still calculating...")
                return
        
            def callback(result):
                self.disabled
                self.disabled = False
                status, self.solution = result
                self.pbar.stop()
                self.printSUDOKU(self.sudoku)
                self.printSUDOKU(self.solution)
                self.message_txt.set('Solution found!' if status else 'No Solution found!')
                self.fill_solution()

            self.disabled = True
            self.pbar.start(20)
            tk_call_async(self, Solver.do_solve, args=(self.sudoku,),
                      callback=callback, method=MULTIPROCESSING)

    def fill_solution(self):
        for row in range(9):
            for col in range(9):
                self.values[row,col].delete(0,END)
                self.values[row,col].insert(0,self.solution[row][col])
what I want to do/fix next:
- the "check" button overwrites the original sudoku to the current sudoku. if you press check before save, then the sudoku.txt and the solution.txt file are identical. this should be relativly easy to fix
- implementing a stop button to interrupt the backtracking algorithm. this is probably a bit harder.
- making some kind of .exe file so that someone cand launch the program without using cmd or IDE
- ...
Reply


Messages In This Thread
tkinter freezes by clicking button - by Zatox11 - Mar-30-2018, 11:38 AM
RE: tkinter freezes by clicking button - by Zatox11 - Mar-30-2018, 02:31 PM
RE: tkinter freezes by clicking button - by Zatox11 - Mar-30-2018, 03:32 PM
RE: tkinter freezes by clicking button - by woooee - Mar-30-2018, 07:35 PM
RE: tkinter freezes by clicking button - by Zatox11 - Mar-31-2018, 08:46 AM
RE: tkinter freezes by clicking button - by Zatox11 - Mar-31-2018, 09:18 AM
RE: tkinter freezes by clicking button - by Zatox11 - Mar-31-2018, 10:23 AM
RE: tkinter freezes by clicking button - by Zatox11 - Mar-31-2018, 10:48 AM
RE: tkinter freezes by clicking button - by Zatox11 - Mar-31-2018, 02:15 PM
RE: tkinter freezes by clicking button - by Zatox11 - Apr-01-2018, 11:38 AM
RE: tkinter freezes by clicking button - by Zatox11 - Apr-02-2018, 12:58 PM
RE: tkinter freezes by clicking button - by Zatox11 - Apr-02-2018, 04:07 PM
RE: tkinter freezes by clicking button - by Zatox11 - Apr-03-2018, 10:50 AM
RE: tkinter freezes by clicking button - by Zatox11 - Apr-03-2018, 02:58 PM
RE: tkinter freezes by clicking button - by sylas - Apr-06-2018, 07:57 AM
RE: tkinter freezes by clicking button - by sylas - Apr-06-2018, 09:10 AM
RE: tkinter freezes by clicking button - by sylas - Apr-08-2018, 09:32 AM
RE: tkinter freezes by clicking button - by sylas - Apr-08-2018, 12:01 PM
RE: tkinter freezes by clicking button - by sylas - Apr-08-2018, 01:05 PM
RE: tkinter freezes by clicking button - by sylas - Apr-08-2018, 03:28 PM
RE: tkinter freezes by clicking button - by Zatox11 - Apr-10-2018, 09:03 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  [Tkinter] TKinter Remove Button Frame Nu2Python 8 1,537 Jan-16-2024, 06:44 PM
Last Post: rob101
  tkinter - touchscreen, push the button like click the mouse John64 5 1,169 Jan-06-2024, 03:45 PM
Last Post: deanhystad
  Centering and adding a push button to a grid window, TKinter Edward_ 15 6,194 May-25-2023, 07:37 PM
Last Post: deanhystad
  [Tkinter] Clicking on the button crashes the TK window ODOshmockenberg 1 2,379 Mar-10-2022, 05:18 PM
Last Post: deanhystad
  Can't get tkinter button to change color based on changes in data dford 4 3,648 Feb-13-2022, 01:57 PM
Last Post: dford
  Creating a function interrupt button tkinter AnotherSam 2 5,817 Oct-07-2021, 02:56 PM
Last Post: AnotherSam
  [Tkinter] Have tkinter button toggle on and off a continuously running function AnotherSam 5 5,353 Oct-01-2021, 05:00 PM
Last Post: Yoriz
  tkinter showing image in button rwahdan 3 5,895 Jun-16-2021, 06:08 AM
Last Post: Yoriz
  tkinter button image Nick_tkinter 4 4,282 Mar-04-2021, 11:33 PM
Last Post: deanhystad
  tkinter python button position problem Nick_tkinter 3 3,760 Jan-31-2021, 05:15 AM
Last Post: deanhystad

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020