0

The problem with this code is I have two autocomplete entry boxes one in Win1 and the other in Win3. It works in Win1 though but problem is when I click on Win3 the new entry box appears in win1. self.entername_e is used to receive the entry on Win3 and self.name_e is used to receive entries on Win1

import tkinter as tk
from tkinter import *
import sqlite3
import tkinter.messagebox
import datetime
import math
import os
import random
import re

The AutocompleteEntry is the class that is used by both the windows Win1 and Win3

#This is the Autocomplete class both the entries will use
class AutocompleteEntry(Entry):
    def __init__(self, autocompleteList, *args, **kwargs):

        # Listbox length
        if 'listboxLength' in kwargs:
            self.listboxLength = kwargs['listboxLength']
            del kwargs['listboxLength']
        else:
            self.listboxLength = 8

        # Custom matches function
        if 'matchesFunction' in kwargs:
            self.matchesFunction = kwargs['matchesFunction']
            del kwargs['matchesFunction']
        else:
            def matches(fieldValue, acListEntry):
                pattern = re.compile('.*' + re.escape(fieldValue) + '.*', re.IGNORECASE)
                return re.match(pattern, acListEntry)
                
            self.matchesFunction = matches

        
        Entry.__init__(self, *args, **kwargs)
        self.focus()

        self.autocompleteList = autocompleteList
        
        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.moveUp)
        self.bind("<Down>", self.moveDown)
        
        self.listboxUp = False

    def changed(self, name, index, mode):
        if self.var.get() == '':
            if self.listboxUp:
                self.listbox.destroy()
                self.listboxUp = False
        else:
            words = self.comparison()
            if words:
                if not self.listboxUp:
                    self.listbox = Listbox(width=self["width"], height=self.listboxLength)
                    self.listbox.bind("<Button-1>", self.selection)
                    self.listbox.bind("<Right>", self.selection)
                    self.listbox.place(x=self.winfo_x(), y=self.winfo_y() + self.winfo_height())
                    self.listboxUp = True
                
                self.listbox.delete(0, END)
                for w in words:
                    self.listbox.insert(END,w)
            else:
                if self.listboxUp:
                    self.listbox.destroy()
                    self.listboxUp = False
        
    def selection(self, event):
        if self.listboxUp:
            self.var.set(self.listbox.get(ACTIVE))
            self.listbox.destroy()
            self.listboxUp = False
            self.icursor(END)

    def moveUp(self, event):
        if self.listboxUp:
            if self.listbox.curselection() == ():
                index = '0'
            else:
                index = self.listbox.curselection()[0]
                
            if index != '0':                
                self.listbox.selection_clear(first=index)
                index = str(int(index) - 1)
                
                self.listbox.see(index) # Scroll!
                self.listbox.selection_set(first=index)
                self.listbox.activate(index)

    def moveDown(self, event):
        if self.listboxUp:
            if self.listbox.curselection() == ():
                index = '0'
            else:
                index = self.listbox.curselection()[0]
                
            if index != END:                        
                self.listbox.selection_clear(first=index)
                index = str(int(index) + 1)
                
                self.listbox.see(index) # Scroll!
                self.listbox.selection_set(first=index)
                self.listbox.activate(index) 

    def comparison(self):
        return [ w for w in self.autocompleteList if self.matchesFunction(self.var.get(), w) ]

This is where the code starts

class Win1:
    def __init__(self, master):
        self.master = master
        self.master = master 
        autocompleteList = [ 'Milo tin', 'Shito small', 'Deodorant', 'Spray']
        def matches(fieldValue, acListEntry):
            pattern = re.compile(re.escape(fieldValue) + '.*', re.IGNORECASE)
            return re.match(pattern, acListEntry)
        
        self.master.geometry("400x300")
        self.show_widgets()

Here is the AutocompleteEntry on Win1

        #Autocomplete Entry
        self.name_e = AutocompleteEntry(autocompleteList, listboxLength=10, width=25, font=('arial 18 bold'), bg='lightblue', matchesFunction=matches)
        self.name_e.place(x=260, y=150)
 
    def show_widgets(self):
        self.frame = tk.Frame(self.master)
        self.master.title("Window n.1")
        self.create_button("Click to open Window 2", Win2)
        self.create_button("Click to open Window 3", Win3)
        self.frame.pack()
 
    def create_button(self, text, _class):
        "Button that creates a new window"
        tk.Button(self.frame, text=text,command=lambda: self.new_window(_class)).pack()
 
    def new_window(self, _class):
        self.win = tk.Toplevel(self.master)
        _class(self.win)
 
 
class Win2(Win1):
    def __init__(self, master):
        self.master = master
        self.master.title("Window n.2")
        self.master.geometry("400x100+200+200")
        self.show_widgets()
 
    def show_widgets(self):
        "A frame with a button to quit the window"
        self.frame = tk.Frame(self.master, bg="red")
        self.quit_button = tk.Button(self.frame, text=f"Quit this window n. 2",command=self.close_window)
        self.quit_button.pack()
        self.create_button("Open window 3 from window 2", Win3)
        self.frame.pack()
 
    def close_window(self):
        self.master.destroy()
 
 
class Win3(Win1):
    def __init__(self, master):
        self.master = master
        self.master = master
 
        #This is the list of the autocomplete entry
        autocompleteList = [ 'Milo tin', 'Shito small', 'Deodorant', 'Spray' ]
        def matches(fieldValue, acListEntry):
            pattern = re.compile(re.escape(fieldValue) + '.*', re.IGNORECASE)
            return re.match(pattern, acListEntry)
        
        self.master.title("Window n.3")
        self.master.geometry("400x200+200+200")
        self.show_widgets()

Here's also the AutocompleteEntry on Win3

        #Autocomplete Entry
        self.entername_e = AutocompleteEntry(autocompleteList, listboxLength=10, width=25, font=('arial 18 bold'), bg='white', matchesFunction=matches)
        self.entername_e.place(x=260, y=150)
 
    def show_widgets(self):
        self.frame = tk.Frame(self.master, bg="green")
        self.quit = tk.Button(self.frame, text=f"Quit this window n. 3",command=self.close_window)
        self.quit.pack()
        self.label = tk.Label(self.frame, text="THIS IS ONLY IN THE THIRD WINDOW")
        self.label.pack()
        self.frame.pack()
 
    def close_window(self):
        self.master.destroy()
 
 
root = tk.Tk()
app = Win1(root)
root.mainloop()
  • This is an awful lot of code for us to wade through. Is there really no way to make the code shorter for the purpose of this question? – Bryan Oakley Jul 01 '20 at 17:36
  • You don't seem to be passing the parent widget to your custom Entries. – jasonharper Jul 01 '20 at 17:44
  • I assume you need to take a look at this: https://stackoverflow.com/questions/576169/understanding-python-super-with-init-methods – Thingamabobs Jul 01 '20 at 17:56
  • jasonharper I don't seem to get what you're trying to say can you explain further –  Jul 02 '20 at 22:38

0 Answers0