[solved] DirectSlider stuck

I’ve made some DirectGui subclasses to simplify layout control, but the DirectSlider subclass isn’t working properly. Its thumb is stuck at the middle of the slider, although the value can be set as desired.

from direct.gui.DirectFrame import DirectFrame
from direct.gui.DirectSlider import DirectSlider
import direct.directbase.DirectStart

class Frame(DirectFrame):

    def __init__(self, width, bottom, top, parent=None):

        super(Frame, self).__init__(parent=parent)

        self.initialiseoptions(type(self))

        self.setProp('frameSize', (- width / 2, width / 2, bottom, top))

        self.setProp('borderWidth', (0.005, 0.005))

class Slider(DirectSlider, Frame):

    def __init__(self, command, ** kwargs):

        DirectSlider.__init__(
            self,
            thumb_borderWidth=(0.005, 0.005),
            value=0.3,
            command=command
        )
        Frame.__init__(self, ** kwargs)

        self.thumb.setProp('frameSize', (- 0.015, 0.015, self['frameSize'][2], self['frameSize'][3]))

        self['scrollSize'] = 0.6
        self.setScrollSize()
        self['value'] = 0.8

def show():

    print slider['value']

frame = Frame(
    width=0.5,
    top=-0.25,
    bottom=0.25
)

slider = Slider(
    command=show,
    width=0.8,
    top=-0.02,
    bottom=-0.08,
    parent=frame
)

print 'slider at', slider['value']

run()

What am I doing wrong here?

Hmm, first, it seems like trouble that you’re multiply inheriting from both DirectFrame and DirectSlider. These two both (indirectly) inherit from NodePath, which means you’ve got NodePath in your inheritance hierarchy twice–and this will cause problems because the NodePath constructor gets called twice, causing a memory leak the second time it is called. Also, both DirectFrame and DirectSlider will now be sharing the same dictionary, and I don’t know that they’re designed with this in mind.

I don’t think this is your current problem, though. Does it work if you just use a DirectSlider directly?

David

DirectFrame is in DirectSlider.mro, so I guessed it wouldn’t hurt. I’ve used a very similar construction for DirectLabel and DirectButton, and they work fine.

Yes, a DirectSlider works.

I noted that, when not using a parent frame for the slider, the slider’s thumb is stuck under the slider.

Well, my guess is that it’s some unexpected interplay when you combine the two objects in this way. Perhaps it’s as simple as something going wrong in the init constructors when they are called multiple times.

In any case, I’d recommend not multiply-inheriting in this way. It’s certainly going to lead to trouble eventually, even if it’s not causing obvious problems now. Multiple inheritance is a powerful but dangerous tool and should be used with caution (some object-oriented languages forbid it altogether because it’s too easy to naively do bad things with it).

I’m not sure what you mean here. Certainly I can create a DirectSlider in a scene by itself and it works fine. If you’re playing games with the rendering order, though, you might get this effect.

David

I found it: the init calls were wrong, as you suggested. By switching the parent classes and calling only one parent init function:

from direct.gui.DirectFrame import DirectFrame
from direct.gui.DirectSlider import DirectSlider
import direct.directbase.DirectStart

class Frame(DirectFrame):

    def __init__(self, width, bottom, top, ** kwargs):

        super(Frame, self).__init__(** kwargs)

        self.initialiseoptions(type(self))

        self.setProp('frameSize', (- width / 2, width / 2, bottom, top))

        self.setProp('borderWidth', (0.005, 0.005))

# switched the parent classes  
class Slider(Frame, DirectSlider):

    def __init__(self, command, ** kwargs):

        Frame.__init__(self,
            thumb_borderWidth=(0.005, 0.005),
            value=0.8,
            command=command, ** kwargs)
        # removed the second __init__ call

        self.thumb.setProp('frameSize', (- 0.015, 0.015, -0.04, 0.04))

        self['scrollSize'] = 0.6
        self.setScrollSize()

def show():

    print slider['value']

slider = Slider(
    command=show,
    width=0.8,
    top=-0.02,
    bottom=-0.08
)

run()