Hello all
I’ve created a script, which shows a list of buttons inside a ScrolledWindow. It allows to move a button to a different position within this list. A button can moved if the left mouse button is hold:
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, title):
super(MyFrame, self).__init__(parent, title=title, size=(300, 400))
self.dragged_button = None
self.scroll_pos_y = 0
self.label_list = ["RED (1)",
"BLUE (2)",
"GREEN (3)",
"WHITE (4)",
"BLACK (5)",
"YELLOW (6)",
"VIOLETT (7)",
"GREY (8)",
"LEMMON (9)",
"ORANGE (10",
"LIGHT BLUE (11)",
"DARK BLUE (12)",
"DARK GREY (13)",
"GOLD (14)",
"SILVER (15)",
"VIOLETT (16)",
"GREY (17)",
"LEMMON (18)",
"ORANGE (19",
"LIGHT BLUE (20)",
"DARK BLUE (21)",
"DARK GREY (22)",
"GOLD (23)",
"SILVER (24)",
]
self.button_list = []
self.scroll_window = wx.ScrolledWindow(self)
self.scroll_window.SetScrollRate(0, 10)
self.sw_sizer = wx.BoxSizer(wx.VERTICAL)
self.scroll_window.SetSizerAndFit(self.sw_sizer)
for idx, lbl in enumerate(self.label_list):
self.add_button(lbl)
self.sw_sizer.Add(self.button_list[idx])
def add_button(self, lbl):
button = wx.Button(self.scroll_window, label=lbl)
self.button_list.append(button)
button.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
button.Bind(wx.EVT_MOTION, self.OnMotion)
button.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
def OnLeftDown(self, event):
touched = event.GetEventObject()
self.last_button = self.button_list[-1]
self.sw_sizer.Hide(self.last_button)
self.last_button.SetLabel(touched.GetLabel())
self.last_button.Show()
ix = 0
for button in self.button_list:
if button == touched:
ix += 1
if ix == len(self.label_list):
break
button.SetLabel(self.label_list[ix])
ix += 1
self.OnMotion(event)
def OnMotion(self, event):
if event.LeftIsDown():
self.last_button.SetPosition(wx.GetMousePosition() - (30, 80))
self.move_to = ((self.scroll_window.CalcUnscrolledPosition(wx.GetMousePosition())[1] - 60) //
self.button_list[0].GetSize()[1])
limit = (self.scroll_window.GetScrollLines(wx.VSCROLL) -
self.scroll_window.GetScrollPixelsPerUnit()[1])
step = 0.5
# moving the list with buttons if dragged button reaches top / bottom area of window
if wx.GetMousePosition()[1] > self.scroll_window.GetSize()[1] + 40:
self.scroll_pos_y = self.scroll_pos_y + step if self.scroll_pos_y < limit else limit
self.scroll_window.Scroll(-1, int(self.scroll_pos_y))
if wx.GetMousePosition()[1] < 90:
self.scroll_pos_y = self.scroll_pos_y - step if self.scroll_pos_y > 0 else 0
self.scroll_window.Scroll(-1, int(self.scroll_pos_y))
def OnLeftUp(self, event):
self.label_list.remove(self.last_button.GetLabel())
self.label_list.insert(self.move_to, self.last_button.GetLabel())
for ix, button in enumerate(self.button_list):
button.SetLabel(self.label_list[ix])
self.sw_sizer.Layout()
self.sw_sizer.FitInside(self.scroll_window)
self.scroll_pos_y = self.scroll_window.GetViewStart()[1]
app = wx.App()
frame = MyFrame(None, "Draggable Buttons")
frame.Show()
app.MainLoop()
Now moving and repositioning a button works fine.
If a button is moved to the top / end of the window, the content scrolls as well, but - and that’s my problem - only, if the mouse is moved. That’s normal, since the scrolling routine is part of the wx.EVT_MOTION handlder (method “OnMotion”).
Is it possible to allow a continuous scrolling (once the mouse is inside the top / botton area) without the need to move the mouse in this area?
Many thanks for your ideas!