David Shaw
David Shaw

Reputation: 85

Why is Tkinter columnspan being ignored?

I am trying to write a data input form in Python 3 on Android (Pydroid3) and cannot get colspan to work as I want it to. The two relevant classes are

class LabelledInput(tk.Frame):
    '''A widget combining both a label and an input widget'''
    def __init__(
            self,
            parent,
            label='',
            input_class=ttk.Entry,
            input_variable=None,
            sticky=(tk.E + tk.W),
            label_position=tk.N,
            padding_x=(0, 0),
            padding_y=(0, 0),
            *args,
            **kwargs):
        super().__init__(parent, *args, **kwargs)
        
        input_args = {}
        grid_position = {}
        
        #Check if label_position is valid and default to tk.N if not
        if not (label_position in (tk.N, tk.S, tk.W, tk.E)):
            label_position = tk.N
        
        # Set up the grid positions for label and input widget
        if label_position == tk.N:
            grid_position['label'] = {'row':0, 'col':0}
            grid_position['input'] = {'row':1, 'col':0}
        elif label_position == tk.S:
            grid_position['label'] = {'row':1, 'col':0}
            grid_position['input'] = {'row':0, 'col':0}
        elif label_position == tk.W:
            grid_position['label'] = {'row':0, 'col':0}
            grid_position['input'] = {'row':0, 'col':1}
        elif label_position == tk.E:
            grid_position['label'] = {'row':0, 'col':1}
            grid_position['input'] = {'row':0, 'col':0}
        
        if input_class in (ttk.Checkbutton, ttk.Button, ttk.Radiobutton):
            input_args["text"] = label
            input_args["variable"] = input_variable
        else:
            self.label = ttk.Label(self, text=label)
            self.label.grid(
                row=grid_position['label']['row'],
                column=grid_position['label']['col'],
                sticky=sticky)
            input_args["textvariable"] = input_variable
        
        self.input = input_class(self, **input_args)
        self.input.grid(
            row=grid_position['input']['row'],
            column=grid_position['input']['col'],
            sticky=sticky)

to give me a combined label and input widget (to reduce repetitive typing) and

class CampaignDetails(tk.Frame):
    '''New campaign dialog'''
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        
        self.inputs = {}
        
        campaignEntry = tk.LabelFrame(self, text='Campaign Details')
        
        self.inputs['Campaign title'] = LabelledInput(
            campaignEntry,
            label='Campaign title',
            input_variable=tk.StringVar).grid(row=0, column=0, columnspan=2)
            
        self.inputs['Ruleset'] = LabelledInput(
            campaignEntry,
            label='Ruleset',
            input_variable=tk.StringVar).grid(row=1, column=0)
            
        self.inputs['Version'] = LabelledInput(
            campaignEntry,
            label='Version',
            input_variable=tk.StringVar).grid(row=1, column=1)
        
        campaignEntry.grid(row=0, column=0, sticky=tk.E + tk.W)

for the actual form itself. However, no matter what I try, the Campaign title widget is stubbornly one column wide. As written above, it is centered in the frame. If I add sticky=tk.W + tk.E, it left justifies, but remains the same width. If I try any form of campaignEntry.columnconfigure to try and set the weight, the overall width of the form changes, but Campaign title remains one column wide.

Upvotes: 0

Views: 167

Answers (1)

Bryan Oakley
Bryan Oakley

Reputation: 385930

Your use of columnspan is working. You didn't tell the widget to fill the space that was allocated to it, so it remains its natural size and centered in the space.

You need to use the sticky attribute if you want the widget to fill all of the space it is allocated.

self.inputs['Campaign title'] = LabelledInput(...).grid(..., sticky="ew")

You also need to use columnconfigure to give a weight to the first column in the LabelledInput frame so that the column expands to fill unallocated space in the frame.

class LabelledInput(tk.Frame):
    def __init__(...):
        ...
        self.grid_columnconfigure(0, weight=1)
        ...

Upvotes: 1

Related Questions