Python Forum
textfile to customtkinter combobox
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
textfile to customtkinter combobox
#1
hello.

Goal: Insert list of country names, stored in a text file, into the combobox.
Idea, create a list of values-
Sadly, country names shows up vertically, letter by letter, in the combobox.
Looks like there is a newline after each letter? Txt-file attached.
Any fix for that?

Can memory used by the list be released. If yes,how?

thank You.

import customtkinter
import tkinter


window = tkinter.Tk()
window.geometry(f"{1920}x{1200}")
window.minsize(1920, 1200)
window.resizable(False, False)
window.title("tittel")
window.state("normal")

def fillcomboland(window):
    f = open('d:\python311\Scripts\inpland.txt')
    list = "["
    for line in f:
        line = f.readline()
        line.strip()
        list = list + "\"" + line + "\"" + ","
    f.close()
    list = list +"\"" +"]"
    land = customtkinter.CTkComboBox(master=window,values=list,font=("Ariel",14,"bold"),width=200,height=32,border_width=2,corner_radius=10,fg_color="#cdebb0", text_color = "#003300")
    land.place(x=1140,y=745)
  
fillcomboland(window)  
    



TEXT-file:

[python]

Attached Files

.txt   inpland.txt (Size: 2.08 KB / Downloads: 80)
Reply
#2
One way

import tkinter as tk
from tkinter import ttk
import os

path = os.path.dirname(os.sys.argv[0])
if not path:
    path = '.'


file = f'{path}/country.txt'

with open(file, 'r') as lines:
    country = [line.strip() for line in lines]

root = tk.Tk()
root.geometry('400x200+300+300')

label = tk.Label(root, text='Combobox', font=(None, 14, 'bold'))
label.pack(side='top')

combobox = ttk.Combobox(root)
combobox['values'] = country
combobox['font'] = (None, 14, 'normal')
combobox.current(0)
combobox.pack(fill='x')
root.mainloop()
janeik likes this post
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#3
Do not use "list" as a variable name. It is a built-in python function and the name of a python datatype. This is a bad practice but it is not the source of your problem.

Another bad practice is putting your program files in the Python directory tree. You should not be putting ipland.txt or any file you write in d:\python311\Scripts. Create a folder that is not in the Python source directory tree and write your programs there. Adding files to the Python directory tree often leads to odd behaviors that are difficult to debug, but this is not the source of your problem.

A few more bad practices that are not the source of your problem:
1. Avoid using styling in your code. Your application should be in harmony with other applications, not in blaring contrast. Customtkinter has good theme support. Use that.
2. Windows should be resizeable unless there is a good reason for them to not be.
3. Do not use geometry to set the window size. Let the window size itself to fit the contents. If the user has set a large system font, your application should automatically adjust.
4. Do not use width and height to set the widget size. Let the widget set it's own size. If multiple widgets should be the same size, use grid(sticky) or pack(expand, fill) to tell the window geometry manager to resize the widgets.
5. Do not use place() to position widgets in the window. Use pack() or grid() to position widgets in the window.
6. Use defaults. For example, window's default state is normal. You don't have to set it to normal.

The source of the problem is that you are passing a string to Combobox values. The documentation says Combobox expects a list of strings, but it appears any iterable will work. Instead of passing a list of strings, you made one long string that kind of looks like a list of strings. When you iterate a string, it returns the characters one at a time. The solution, as menator01 shows, is putting the country names in a list, not a string named "list" that is formatted to look like a list when it is printed out.

menator also shows that it is silly to write a function that is only used once. I will show how you can take your idea and use it to make a useful function. The function combo_from_file() creates a Combobox object, loading the values from a file. This function could be used to make multiple combo boxes, specifying a different values file for each one.
def combo_from_file(*args, values=None, **kwargs):
    """Create combobox using values from a file."""
    with open(values, "r") as f:   # Use context manager to automatically close file when done.
        values = [value.strip() for value in f]
    return customtkinter.CTkComboBox(*args, values=values, **kwargs)

# Use forward slashes in filenames.  Prevents "\" from accidentally being part of an ascii escape sequence.
land = combo_from_file(window, value="d:/my_folder/inpland.txt", width=200)
land.pack(padx=50, pady=50)
But I would probably make a class instead of writing a function. If I needed to make a bunch of comboboxes, and the values might not be a list, might even be read from a file, I might write a class like this:
import tkinter as tk
from tkinter import ttk


class EnhancedCombo(ttk.Combobox):
    """A combobox where values don't have to be lists."""

    def __init__(self, *args, values=[], **kwargs):
        if type(values) is str:
            # Assume strings are filenames
            with open(values, "r") as f:
                values = [value.strip() for value in f]
        elif not isinstance(values, list):
            values = list(values)
        return super().__init__(*args, values=values, **kwargs)


numbers = {"one": 1, "two": 2, "three": 3}
window = tk.Tk()
EnhancedCombo(window, values=numbers, width=60).pack(padx=10, pady=10)
EnhancedCombo(window, values=numbers.values(), width=60).pack(padx=10, pady=10)
EnhancedCombo(window, values=numbers.keys(), width=60).pack(padx=10, pady=10)
EnhancedCombo(window, values=__file__, width=60).pack(padx=10, pady=10)
window.mainloop()
Reply
#4
(Aug-30-2023, 03:43 PM)menator01 Wrote: One way

import tkinter as tk
from tkinter import ttk
import os

path = os.path.dirname(os.sys.argv[0])
if not path:
    path = '.'


file = f'{path}/country.txt'

with open(file, 'r') as lines:
    country = [line.strip() for line in lines]

root = tk.Tk()
root.geometry('400x200+300+300')

label = tk.Label(root, text='Combobox', font=(None, 14, 'bold'))
label.pack(side='top')

combobox = ttk.Combobox(root)
combobox['values'] = country
combobox['font'] = (None, 14, 'normal')
combobox.current(0)
combobox.pack(fill='x')
root.mainloop()

Thank You, values shows nicely in combobox
Reply
#5
hello. I used capital letters so its easier to read, Im not shouting :)

(Aug-30-2023, 09:01 PM)deanhystad Wrote: Do not use "list" as a variable name. It is a built-in python function and the name of a python datatype. This is a bad practice but it is not the source of your problem.
[
Another bad practice is putting your program files in the Python directory tree. You should not be putting ipland.txt or any file you write in d:\python311\Scripts. Create a folder that is not in the Python source directory tree and write your programs there. Adding files to the Python directory tree often leads to odd behaviors that are difficult to debug, but this is not the source of your problem.
UNDERSTAND THE ABOVE
A few more bad practices that are not the source of your problem:
1. Avoid using styling in your code. Your application should be in harmony with other applications, not in blaring contrast. Customtkinter has good theme support. Use that.
COLORS ARE MENT TO FIT MAPCOLORS AND WITH HIGH CONTRAST.
2. Windows should be resizeable unless there is a good reason for them to not be.
REASON FOR NO RESIZE IS I DONT WANT RESIZE OF A MAP, BUT I COULD PROBABLY SET FIXED WHEN APP NEEDS IT
3. Do not use geometry to set the window size. Let the window size itself to fit the contents. If the user has set a large system font, your application should automatically adjust.
I WANT A MAP AND IMAGES NOT TO BE RESIZED OR CHANGED
4. Do not use width and height to set the widget size. Let the widget set it's own size. If multiple widgets should be the same size, use grid(sticky) or pack(expand, fill) to tell the window geometry manager to resize the widgets.
5. Do not use place() to position widgets in the window. Use pack() or grid() to position widgets in the window.
NEED FIXED POSITION FOR MOST OBJECTS DUE TO SOME MAP AND IMAGES, BUT ITS A HELL MUCH WORK TO DO CHANGES USING .place() THAN PACK/GRID
6. Use defaults. For example, window's default state is normal. You don't have to set it to normal.
K, WILL REMOVE SETTING

The source of the problem is that you are passing a string to Combobox values. The documentation says Combobox expects a list of strings, but it appears any iterable will work. Instead of passing a list of strings, you made one long string that kind of looks like a list of strings. When you iterate a string, it returns the characters one at a time. The solution, as menator01 shows, is putting the country names in a list, not a string named "list" that is formatted to look like a list when it is printed out.

THANKS FOR THE EXPLANATIONS ABOVE.

menator also shows that it is silly to write a function that is only used once. I will show how you can take your idea and use it to make a useful function. The function combo_from_file() creates a Combobox object, loading the values from a file. This function could be used to make multiple combo boxes, specifying a different values file for each one.
def combo_from_file(*args, values=None, **kwargs):
    """Create combobox using values from a file."""
    with open(values, "r") as f:   # Use context manager to automatically close file when done.
        values = [value.strip() for value in f]
    return customtkinter.CTkComboBox(*args, values=values, **kwargs)
THANK YOU VERY MUCH, I WILL USE IT. REASON I WANT TO USE FUNCTION IS THAT MAIN APP IS STARTING TO BE UNEASY TO READ IN ITS STRUCTURE. I DO  HAVE 3 COMBOBOXES IN APP.
# Use forward slashes in filenames.  Prevents "\" from accidentally being part of an ascii escape sequence.
land = combo_from_file(window, value="d:/my_folder/inpland.txt", width=200)
land.pack(padx=50, pady=50)
THANKS FOR THE ABOVE
But I would probably make a class instead of writing a function. If I needed to make a bunch of comboboxes, and the values might not be a list, might even be read from a file, I might write a class like this:
import tkinter as tk
from tkinter import ttk


class EnhancedCombo(ttk.Combobox):
    """A combobox where values don't have to be lists."""

    def __init__(self, *args, values=[], **kwargs):
        if type(values) is str:
            # Assume strings are filenames
            with open(values, "r") as f:
                values = [value.strip() for value in f]
        elif not isinstance(values, list):
            values = list(values)
        return super().__init__(*args, values=values, **kwargs)


numbers = {"one": 1, "two": 2, "three": 3}
window = tk.Tk()
EnhancedCombo(window, values=numbers, width=60).pack(padx=10, pady=10)
EnhancedCombo(window, values=numbers.values(), width=60).pack(padx=10, pady=10)
EnhancedCombo(window, values=numbers.keys(), width=60).pack(padx=10, pady=10)
EnhancedCombo(window, values=__file__, width=60).pack(padx=10, pady=10)
window.mainloop()
Reply
#6
(Aug-30-2023, 03:43 PM)menator01 Wrote: One way

import tkinter as tk
from tkinter import ttk
import os

path = os.path.dirname(os.sys.argv[0])
if not path:
    path = '.'


file = f'{path}/country.txt'

with open(file, 'r') as lines:
    country = [line.strip() for line in lines]

root = tk.Tk()
root.geometry('400x200+300+300')

label = tk.Label(root, text='Combobox', font=(None, 14, 'bold'))
label.pack(side='top')

combobox = ttk.Combobox(root)
combobox['values'] = country
combobox['font'] = (None, 14, 'normal')
combobox.current(0)
combobox.pack(fill='x')
root.mainloop()
Thank You again. It works.
I tried to use it with custom tkinter combobox without any luck :)
Reply
#7
Read the documentation. Tots of examples. Light on text. CTkComboBox does not have a "current()" method for setting the value. Use .set().
https://customtkinter.tomschimansky.com/...s/combobox
import customtkinter as tk

with open(__file__, "r") as file:
    values = [x.strip() for x in file]
root = tk.CTk()
cbox = tk.CTkComboBox(root, values=values, font=(None, 16), width=600)
cbox.pack()
cbox.set(values[5])
root.mainloop()
Are you happy now? You made me install customtkinter.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Importing python data to Textfile or CSV yanDvator 0 1,765 Aug-02-2020, 06:58 AM
Last Post: yanDvator
  Replace Line in Textfile Deadline 1 10,387 Nov-04-2019, 07:14 PM
Last Post: Larz60+
  Compare input() to textfile Trianne 4 3,524 Sep-29-2018, 02:32 PM
Last Post: gruntfutuk
  Write from URL with changing information to textfile wmc326 1 2,999 Jul-12-2017, 07:10 PM
Last Post: wavic
  Loop thru textfile, change 3 variables for every line herbertioz 11 9,156 Nov-10-2016, 04:56 PM
Last Post: Larz60+

Forum Jump:

User Panel Messages

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