1

I'm building a Python tkinter popup as a subclass of simpledialog.Dialog with nothing but specialized buttons. The body method only gives the dialog label and returns None.

The buttonbox method defines the buttons and the commands are fine. When I place the buttons with pack, everything works fine. But if I try to use grid instead, as I normally do in the body method of other dialogs, the dialog doesn't show at all though the app continues to run.

Is there a call I'm missing to make it appear?

The buttonbox methods has nothing except the button creations and placements. No other calls.

For several reasons, I prefer to use grid, not pack.

The basic structure is body, apply, and buttonbox plus the command methods. The same problem occurs if I grid a Label into the body.

Note: other questions are similar, but I think this is a buttonbox issue specifically.


from tkinter import simpledialog, Button, Tk, LEFT

class FooDialog(simpledialog.Dialog):

    def __init__(self, root):
        super().__init__(root)

    __val = "mumble"
    
    @classmethod
    def get(cls):
        return FooDialog.__val
    
    def getResult(self):
        return FooDialog.__val
     
    def handle(self, which):
        if not which:
            FooDialog.__val = "jumble"
        self.destroy()
   
    def buttonbox(self):
        noButton = Button(self, text="Foo", width=10, command= lambda t=False: self.handle(t))
        noButton.pack(side=LEFT, padx=5, pady=5)
   
    def body(self, master):
        self.title('Foo')    
        return None
    
    def apply(self):
        FooDialog.__val = self.getResult()
        

def foo():

    root = Tk()
    root.withdraw()
    FooDialog(root)
    root.destroy()
    return FooDialog.get()

if __name__ == '__main__':

    print( foo())

If I replace the grid call with:

    noButton.grid(row=0, column=0)

nothing will appear

Buffy
  • 113
  • 5
  • Please refer to this guide on how to provide a [mre], and read about [ask]. Remember, we can't help you if we don't know what you've already tried. – JRiggles May 19 '23 at 18:27
  • Tkinter has no widget *ButtonBox*, how can it specifically related to this not existing widget? Your question lacks of details and a [mre]. There shouldn't be any other differences when using `grid`or `pack` except for geometrical placement. Does your widget hides behind any margins? – Thingamabobs May 19 '23 at 18:44
  • @Thingamabobs, buttonbox is a method of simpledialog.Dialog. It isn't a separate widget. – Buffy May 19 '23 at 18:46
  • Are you subclassing [this](https://github.com/python/cpython/blob/main/Lib/tkinter/simpledialog.py#L89) widget? – Thingamabobs May 19 '23 at 18:50
  • @Thingamabobs, yes, and overriding both body and buttonbox (and apply) – Buffy May 19 '23 at 18:54
  • Can you share this class? Because it sounds like a mistake you've made somewhere along the line, but from the code you've shared I can't spot it. Or it might be because of recent changes in that particular module. As I said, can't tell from here. – Thingamabobs May 19 '23 at 18:55
  • @Thingamabobs here is the code. As it it runs, but replacing pack with the grid call fails – Buffy May 19 '23 at 19:10

1 Answers1

2

When replacing pack with grid I get the following error:

_tkinter.TclError: cannot use geometry manager grid inside .!foodialog which already has slaves managed by pack

and this is because of a little bit odd design decision of this rather old module.
They first pack a frame for the body *1 in the scope of __init__, so you can't reach it easily but you can stick to the design *2.

This means you will need to pack another frame within you can choose a different layout/geometry-manager.

from tkinter import simpledialog, Button, Tk, LEFT, Frame

class FooDialog(simpledialog.Dialog):

    def __init__(self, root):
        super().__init__(root)

    __val = "mumble"
    
    @classmethod
    def get(cls):
        return FooDialog.__val
    
    def getResult(self):
        return FooDialog.__val
     
    def handle(self, which):
        if not which:
            FooDialog.__val = "jumble"
        self.destroy()
   
    def buttonbox(self):
        button_frame = Frame(self)
        noButton = Button(button_frame, text="Foo", width=10,
            command= lambda t=False: self.handle(t))
        noButton.grid(row=0, column=0)
        button_frame.pack()
   
    def body(self, master):
        self.title('Foo')    
        return None
    
    def apply(self):
        FooDialog.__val = self.getResult()
        

def foo():

    root = Tk()
    root.withdraw()
    FooDialog(root)
    root.destroy()
    return FooDialog.get()

if __name__ == '__main__':

    print( foo())

You might find this answer helpful.

Thingamabobs
  • 7,274
  • 5
  • 21
  • 54
  • Yes, creating the frame and later packing it, along with adding the buttons to the frame did the trick. Thanks. – Buffy May 19 '23 at 19:33
  • @Buffy if you don't get any error, you might need to check your python version and update it. Because this error is as long as I code around and this is a few years now. Be aware that there is even an end for [security support in older versions](https://devguide.python.org/versions/) – Thingamabobs May 19 '23 at 19:40
  • That is a bit hard. I'm on an older mac using Eclipse and pydev. And the error didn't appear. Honestly though, I'm pretty sure I wouldn't have been able to interpret it correctly an would still need to ask. But it isn't for a critical app in any case. I'm working on materials for novices and Python isn't my native tongue. – Buffy May 19 '23 at 20:00
  • @Buffy if you interested, you can join the [tkinter chat](https://chat.stackoverflow.com/rooms/249491/tkinter) from time to time. If all you need is a little help to provide examples for students, it might be a better place to talk about related topics. I do not know everything, but I rate myself above average in *python* and *tkinter*. – Thingamabobs May 20 '23 at 08:36