Continuously press a directButton like a key (*-repeat)

Another newbie question here.

I use the keyboard “-repeat” feature to continuously call a specific method like this:
base.accept("a-repeat", scene.changePosition, ['myoption'])

To call the same method with a directButton i use this:
button = DirectButton(text = ("button text"), command=scene.changePosition,extraArgs=['myoption'])
but the DirectButton only call the changePosition method one time.

How can I obtain the same “repeat” behaviour with a DirectButton ?

Thanks !

This is not currently implemented, however there is a patch for this feature:

1 Like

Hi rdb,

I don’t know how are panda3d developments and patches organized/scheduled. When do you think this feature will be integrated ?

If you want a way of doing this in the meanwhile, you should be able to achieve it via “binding” events to the button (that is, via calling the button’s “bind” method), and adding a bit more logic.

Something like the following:

(This assumes that you have some sort of “update”-task running; if not, see the note after the code for another approach.)

    # Wherever you construct your button:
    myButton = DirectButton(<arguments here>)
    myButton.bind(DGG.B1PRESS, self.buttonDown)
    myButton.bind(DGG.B1RELEASE, self.buttonUp)
    self.buttonIsDown = False

def buttonDown(self):
    self.buttonIsDown = True

def buttonUp(self):
    self.buttonIsDown = False

def update(self, task):
    # Any update-logic that's to be performed first here...

    if self.buttonIsDown:
        scene.changePosition("myOption")

    # The rest of the update-task follows...

You could also have the button-events start and stop a task, if you prefer. I’m generally inclined to keep a central “update”-task, but I don’t claim to know whether that’s better or worse than spawning tasks freely. And if you don’t have an “update”-task at all, then starting and stopping a new task might be simpler than the above.

Thanks, I will try that.

1 Like

Thanks Thaumaturge, I made it work ! Here is my code:

from direct.gui.DirectGui import DirectButton,DGG
from direct.task import Task

class SmartButton(DirectButton):

  def __init__(self, **kwargs):
    self.buttonIsDown = False
    self.identifier = str(id(self))

    DirectButton.__init__(self,**kwargs)
    self.initialiseoptions(SmartButton)

    self.bind(DGG.B1PRESS, self.buttonDown)
    self.bind(DGG.B1RELEASE, self.buttonUp)

    print (self.identifier)

  def buttonDown(self,args):
    self.buttonIsDown = True
    taskMgr.add(self.update, self.identifier)

  def buttonUp(self,args):
    self.buttonIsDown = False
    taskMgr.remove(self.identifier)

  def update(self, task):
    print ("update")
    if self.buttonIsDown:
      print ("downButton")
    return Task.cont
1 Like

Nicely done! :slight_smile:

Although I’ll note that, if you’re using the “buttonDown” and “buttonUp” methods to add and remove a task respectively, I think that you probably don’t need the “buttonIsDown” variable–after all, the task should only be running while the button is held.

Yes, indeed ! :smiley:

from direct.gui.DirectGui import DirectButton,DGG
from direct.task import Task

class SmartButton(DirectButton):

  def __init__(self, **kwargs):
    self.identifier = str(id(self))

    DirectButton.__init__(self,**kwargs)
    self.initialiseoptions(SmartButton)

    self.bind(DGG.B1PRESS, self.buttonDown)
    self.bind(DGG.B1RELEASE, self.buttonUp)

  def buttonDown(self,args):
    self.buttonIsDown = True
    taskMgr.add(self.update, self.identifier)

  def buttonUp(self,args):
    self.buttonIsDown = False
    taskMgr.remove(self.identifier)

  def update(self, task):
    print ("downButton")
    return Task.cont
1 Like