pythontkinterbuttonsyntax-errorword-wrap

the text value doesn't fit in the button


This is a tkinter module related problem

like in my code there is a variable named optButton1 I have made it and used this code sample-

Button(bottomFrame, text=firstOption[0], font=("arial", 18, "bold"), bg="black", fg="white", bd="0", activebackground="black", activeforeground="white", cursor="hand2")

In the text property I have inserted a variable named firstOption's first index and some other properties.(the value of firstOption[0] is "Crab" which is small word and gets fit in the button of firstOption)

When I run the code there is GUI in which that button appears if I click it will change the option's value or should I say simply that the optButton1's text value changes to firstOption[1] which is :

optButton1.config(text=firstOption[1])

The value of text=firstOption[1] is "Doctor of Principal" so it is too long for my button size but the problem is that I don't want to change the size of that button so it just doesn't fit and whole text is not visible on the button.

I tried to use the property wrap="word" in the optButton1 which is:

optButton1 = Button(bottomFrame, text=firstOption[0], wrap="word",font=("arial", 18, "bold"), bg="black", fg="white", bd="0", activebackground="black", activeforeground="white", cursor="hand2")

if I run the above line of code then it throws an error!

from tkinter import *

def select(event):      # Function to set what happens after the option buttons are clicked
    b = event.widget
    value = b["text"]
    if value == correctAns[0]: #if correct answer chosen
        questionArea.delete(1.0, END)   #deletes everthing in Question Area
        questionArea.insert(END, questions[1])  #new question appears
        
        optButton1.config(text=firstOption[1])  #new options appear
        optButton2.config(text=secondOption[1])
        optButton3.config(text=thirdOption[1])
        optButton4.config(text=fourthOption[1])

#Question and options and correct options

correctAns = ["Chinkara", "Doctor of Philosophy", "Desert",
              "Sep 8", "Prayag. Haridwar, Ujjain, Nasik", 

              "MRTPC", "1,2 and3", "Free on Board",
              "the world's first hospital on rails operating in India.","Haryana",
              
              "Bharathatyarn", "Veena", "Uttar Pradesh",
              "Sangeet Academy", "New Delhi"]

questions = ["Which of these animals does not live in the sea?",
             "What is the meaning of education degree, P.H.D?",
             "What type of region is Cholistan, located in Pakistan?",
             "The International Literacy Day is observed on",
             "In which group of places the Kumbha Mela is held every twelve years?",
             
             "The BVO (Brominated Vegetable Oil) was banned in soft drinks by which of the following organisations?",
             "Which of the following is/are youth organisations?\t1. NCC 2. NSS 3. NYK",
             "The abbreviation 'fob' stands for",
             "The Lifeline Express is",
             "Which of the following was the first Indian state to issue photo identity cards to its voters?",
            
             "Thillana is a format of",
             "Most 'ancient musical' instrument among the following is",
             "Of which of the following states is Nautanki, a folk dance?",
             "Which of the following Academy is responsible for fostering the development of dance, drama and music in India?",
             "The headquarters of the Sahitya Academy is at"]

firstOption = ["Crab","Doctor of Principal",
               "River","Sep 8",
               "Ujjain. Purl; Prayag. Haridwar","I.S.I.",
               "1 only","Free on Board",
               "a de-addiction programme to save drug addicts.","Tamil Nadu",
               "Kuchipudi","Sarod",
               "Uttar Pradesh","Lalit Kala Academy",
               "Mumbai"]

secondOption = ["Lobster","Doctor of Philosophy",
                "Mountain","Nov 28",
                "Prayag. Haridwar, Ujjain,. Nasik","AGMARK",
                "2 only","Free of Bargain",
                "the world's first hospital on rails operating in India.","Rajasthan",
                "Odissi","Tabla",
                "Arunachal Pradesh","Sahitya Academy",
                "Chennai"]

thirdOption = ["Shrimp","Doctor of Physiology",
               "Desert","May 2",
               "Rameshwaram. Purl, Badrinath. Dwarika","MRTPC",
               "1 and 2","Fellow of Britain",
               "a popular health magazine founded by Ramoath Goenka.","West Bengal",
               "Bharathatyarn","Sitar",
               "Meghalaya","National School of Drama",
               "New Delhi"]

fourthOption = ["Chinkara","Doctor of Phsychology",
                "Lake","Sep 22",
                "Chittakoot, Ujjain, Prayag,'Haridwar","None of These",
                "1,2 and3","None of these",
                "A health show","Haryana",
                "Kathak","Veena",
                "Orissa","Sangeet Academy",
                "Kolkata"]

root = Tk()
# Window Customization
root.geometry("1272x652+0+0")
root.title("Kaun Banega Crorepati created by Arnav Kumar")
root.config(bg = "black")

#Frames
leftFrame = Frame(root, bg="black", padx=90)
leftFrame.grid(row=0, column=0)

topFrame = Frame(leftFrame, bg="black", pady=15)
topFrame.grid()

middleFrame = Frame(leftFrame, bg="black", pady=15)
middleFrame.grid(row=1, column=0)

bottomFrame = Frame(leftFrame)
bottomFrame.grid(row=2, column=0)

rightFrame = Frame(root, pady=25, padx=50, bg="black")
rightFrame.grid(row=0, column=1)

#Images and label simply designing
img50 = PhotoImage(file="50-50.png")
lifeLine50Button = Button(topFrame, image=img50, bg="black", bd=0, activebackground="black", width=180, height=80)
lifeLine50Button.grid(row=0, column=0)

audiencePoll = PhotoImage(file="audiencePole.png")
audiencePollButton = Button(topFrame, image=audiencePoll, bg="black", bd=0, activebackground="black", width=180, height=80)
audiencePollButton.grid(row=0, column=1)

phoneImg = PhotoImage(file="phoneAFriend.png")
phoneLifelineButton = Button(topFrame, image=phoneImg, bg="black", bd=0, activebackground="black", width=180, height=80)
phoneLifelineButton.grid(row=0, column=2)

centerImg = PhotoImage(file="center.png")
logoLabel = Label(middleFrame, image=centerImg, bg="black", width=300, height=200)
logoLabel.grid(row=0, column=0)

amountImg = PhotoImage(file="Picture0.png")
amountLabel = Label(rightFrame, image=amountImg, bg="black")
amountLabel.grid(row=0, column=0)

layoutImg = PhotoImage(file="lay.png")
layoutLabel = Label(bottomFrame, image=layoutImg, bg="black")
layoutLabel.grid(row=0, column=0)

#question box
questionArea = Text(bottomFrame, font=("arial", 18, "bold"), width=34, height=2, wrap="word", bg="black", fg="white", bd = 0)
questionArea.place(x=70, y=10)

questionArea.insert(END,questions[0])   #inserting questions in question area

labelA = Label(bottomFrame, text="A:", font=("arial", 16, "bold"), bg="black", fg="white", bd = 0)  #Labels of Options i.e. "A:","B:","C","D" 
labelA.place(x=60, y=110)
optButton1 = Button(bottomFrame, text=firstOption[0], font=("arial", 18, "bold"), bg="black", fg="white", bd="0", activebackground="black", activeforeground="white", cursor="hand2", wrap="word")   #Option Buttons formation
optButton1.place(x=100,y=100)

labelB = Label(bottomFrame, text="B:", font=("arial", 16, "bold"), bg="black", fg="white", bd = 0)  #Labels of Options i.e. "A:","B:","C","D"
labelB.place(x=332, y=110)
optButton2 = Button(bottomFrame, text=secondOption[0], font=("arial", 18, "bold"), bg="black", fg="white", bd="0", activebackground="black", activeforeground="white", cursor="hand2")  #Option Buttons formation
optButton2.place(x=370,y=100)

labelC = Label(bottomFrame, text="C:", font=("arial", 16, "bold"), bg="black", fg="white", bd = 0)  #Labels of Options i.e. "A:","B:","C","D"
labelC.place(x=60, y=190)
optButton3 = Button(bottomFrame, text=thirdOption[0], font=("arial", 18, "bold"), bg="black", fg="white", bd="0", activebackground="black", activeforeground="white", cursor="hand2")   #Option Buttons formation
optButton3.place(x=100,y=180)

labelD = Label(bottomFrame, text="D:", font=("arial", 16, "bold"), bg="black", fg="white", bd = 0)  #Labels of Options i.e. "A:","B:","C","D"
labelD.place(x=332, y=190)
optButton4 = Button(bottomFrame, text=fourthOption[0], font=("arial", 18, "bold"), bg="black", fg="white", bd="0", activebackground="black", activeforeground="white", cursor="hand2")  #Option Buttons formation
optButton4.place(x=370,y=180)

#Setting the functionality of Option Buttons
optButton1.bind("<Button-1>", select)
optButton2.bind("<Button-1>", select)
optButton3.bind("<Button-1>", select)
optButton4.bind("<Button-1>", select)

root.mainloop()

Solution

  • At the risk of answering a poorly asked question, here's a possible solution that uses the built-in textwrap module

    NOTE: I've had to take some liberties here since no real example was provided - you'll need to adapt this to your code

     """Basic example app showing button text wrapping via `textwrap`"""
    import tkinter as tk
    from textwrap import wrap
    
    
    root = tk.Tk()
    root.geometry('400x400')
    
    optButton1 = tk.Button(
        root, 
        text='Doctor of Principal',
        font=('Arial', 18, 'bold'),
    )
    
    # get the text from the button widget
    btn_text = optButton1.cget('text')
    # set the desired wrap length (in characters)
    max_len = 10
    if len(btn_text) >= max_len:
        # wrap the text if it's longer than the maximum desired length
        btn_text = '\n'.join(wrap(btn_text, max_len))
        optButton1.config(text=btn_text)
    
    optButton1.pack()
    
    
    if __name__ == '__main__':
        root.mainloop()
    

    You could put the text wrapping code into a function like so

    def wrap_btn_text(event):
        btn = event.widget
        btn_text = btn.cget('text')
        max_len = 10
        if len(btn_text) >= max_len:
            # wrap the text if it's longer than the maximum desired length
            btn_text = '\n'.join(wrap(btn_text, max_len))
            btn.config(text=btn_text)
    

    And then bind it to the button's '<Configure>' to wrap the text as-needed whenever the button is modified

    optButton1.bind('<Configure>', wrap_btn_text)
    

    Here's the whole thing together:

    import tkinter as tk
    from textwrap import wrap
    
    
    def wrap_btn_text(event):
        btn = event.widget
        btn_text = btn.cget('text')
        max_len = 10
        if len(btn_text) >= max_len:
            # wrap the text if it's longer than the maximum desired length
            btn_text = '\n'.join(wrap(btn_text, max_len))
            btn.config(text=btn_text)
    
    
    root = tk.Tk()
    root.geometry('400x400')
    
    optButton1 = tk.Button(
        root, 
        text='Doctor of Principal',
        font=('Arial', 18, 'bold'),
    )
    optButton1.pack()
    optButton1.bind('<Configure>', wrap_btn_text)
    
    # here's an example of an update that will trigger the text wrap callback
    optButton1.config(text='Especially Long Button Text')
    # the callback will also trigger if you set the text from a `textvariable`
    
    
    if __name__ == '__main__':
        root.mainloop()