Hello there,
I have created a simple class for displaying a Listbox. It works quite fine, but now I have a small problem. When the Listbox has more than 16 items in it, the user can scroll with his (or her) mouse wheel. That is also working. But in my case, sometimes I will need two Listboxes and here my problem starts. Both Listboxes would scroll when I use the wheel and this is - of course! - not what I want. At this moment, my code is like this:
class PyrListBox():
def __init__(self, items, pos):
self.focus = False
self.max_items = 16
self.offset = 0
self.items = items
self.cards = []
self.nodes = []
self.pickedEntry = None
self.OnCollideIn = None
self.OnCollideOut = None
self.OnClick = None
self.cm = CardMaker('cm')
left,right,bottom,top = 0, 1.0, 0, 0.1
self.cm.setFrame(left,right,top,bottom)
self.NP = aspect2d.attachNewNode('listbox')
x, z = pos
self.NP.setPos(x, 0, z)
self.NP.setColor(0.1, 0.1, 0.1, 0.5)
self.NP.setTransparency(True)
tex = loader.loadTexture('textures/bg.png')
for i in range(len(self.items)):
self.cards.append(self.cm.generate())
text = TextNode('item name')
text.setText(self.items[i])
textNodePath = NodePath(self.cards[i]).attachNewNode(text)
textNodePath.setScale(0.07)
textNodePath.setPos(0.025, 0, 0.025)
textNodePath.setColor(1.0, 1.0, 1.0, 1.0)
self.nodes.append(self.NP.attachNewNode(self.cards[i]))
self.nodes[i].setTexture(tex)
self.nodes[i].setPos(0, 0, - i * 0.1)
self.nodes[i].setCollideMask(BitMask32.bit(21))
self.nodes[i].setTag('entry', self.items[i])
self.update()
self.cTrav = CollisionTraverser()
self.handler = CollisionHandlerEvent()
self.handler.addInPattern('ray-into-entry')
self.handler.addOutPattern('ray-out-entry')
self.pickerNode = CollisionNode('mouseraycnode')
self.pickerNP = base.render2d.attachNewNode(self.pickerNode)
self.pickerNP.show()
self.pickerRay = CollisionRay(0, -1, 0, 0, 1, 0)
self.pickerNode.addSolid(self.pickerRay)
self.pickerNode.setFromCollideMask(BitMask32.bit(21))
self.pickerNode.setIntoCollideMask(BitMask32.allOff())
self.cTrav.addCollider(self.pickerNP, self.handler)
self.DO = DirectObject()
taskMgr.add(self.rayUpdate, 'updatePicker')
self.hide()
def update(self):
for i in range(len(self.nodes)):
self.nodes[i].detachNode()
self.nodes = []
for i in range(self.offset, self.offset + self.max_items):
if i > len(self.cards)-1:
break
self.nodes.append(self.NP.attachNewNode(self.cards[i]))
self.nodes[i - self.offset].setPos(0, 0, - (i - self.offset) * 0.1)
def scroll_down(self):
if len(self.items) > self.max_items:
if len(self.items) > self.max_items + self.offset:
self.offset += 1
self.update()
def scroll_up(self):
if self.offset > 0:
self.offset -= 1
self.update()
def rayUpdate(self, task):
if base.mouseWatcherNode.hasMouse():
mpos = base.mouseWatcherNode.getMouse()
self.pickerNP.setPos(render2d, mpos[0], 0, mpos[1])
self.cTrav.traverse(render2d)
return task.cont
def click(self):
if self.OnClick <> None:
self.OnClick(self.pickedEntry)
def collideIn(self, entry):
np = entry.getIntoNodePath()
np.setColor(0.2, 0.2, 0.2, 0.5)
self.pickedEntry = np.getTag('entry')
#self.focus = True
if self.OnCollideIn <> None:
self.OnCollideIn(self.pickedEntry)
def collideOut(self, entry):
np = entry.getIntoNodePath()
np.setColor(0.1, 0.1, 0.1, 0.5)
self.pickedEntry = None
#self.focus = False
def show(self):
self.NP.reparentTo(aspect2d)
self.DO.accept('ray-into-entry', self.collideIn)
self.DO.accept('ray-out-entry', self.collideOut)
self.DO.accept('wheel_up', self.scroll_up)
self.DO.accept('wheel_down', self.scroll_down)
self.DO.accept('mouse1', self.click)
def hide(self):
self.NP.reparentTo(hidden)
self.DO.ignoreAll()
init() takes the position on the screen and a list of all the items I wanna have. After creation, the variables like self.OnClick can be set to a function, so it is executed when the user clicks (quite simmilar like in Delphi or Lazarus).
I tried it with an variable in which I saved if the Listbox has the “focus” / if the mouse pointer is over an item and checked it before the increasing/decreasing of the self.offset value. This didn’t work well, it hangs mostly and scrolling wasn’t “smooth”. Even setting self.focus = True directly after scrolling and updating wasn’t the clue.
In my very case I COULD deactivate the Event handling of one Listbox, but this not the elegant way.
Has anyone a hint for me? Thanks in advance, I hope my english is good enough for you to understand what I mean, it is not my native language.
Jörn