我有几个逐步打开的GUI,它们都遇到了同样的问题。当我打开它们时,选择的第一个对象是TextCtrl
对象。这些GUI相当大,并且有滚动条。由于选择了TextCtrl
对象,因此使用鼠标滚轮滚动不会执行任何操作,并使其看起来好像滚动条已损坏。为了证明这一点,我做了以下代码:
import wx
class Tester(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Window", size=(500, 500))
self.panel = wx.ScrolledWindow(self,wx.ID_ANY)
self.panel.SetScrollbars(30,30,600,400)
textBox = wx.TextCtrl(panel, -1, "", size=(200, 150), style=wx.TE_MULTILINE|wx.TE_LEFT)
textStuff = wx.StaticText(panel, -1, "A\nbunch\nof\nlines\nto\nmake\nthis\nlong\nenough\nto\nhave\nscroll\nbars\n\n\n\n\n\n\n\n\n\nIts lonely down here\n\n\n\n:(")
lonelyBtn = wx.Button(panel, -1, "So Lonely")
vbox = wx.BoxSizer(wx.VERTICAL)
vbox.Add(textBox, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)
vbox.Add(textStuff, flag=wx.LEFT|wx.RIGHT|wx.TOP, border=10)
vbox.Add(lonelyBtn, flag=wx.LEFT|wx.RIGHT|wx.TOP, border=10)
panel.SetSizer(vbox)
panel.Layout()
app = wx.PySimpleApp()
Tester().Show()
app.MainLoop()
当你运行它并尝试向下滚动时,你会注意到你不能用鼠标滚轮滚动。
到目前为止,这一切都有道理。这里有点奇怪。如果所选对象是Button
,则使用鼠标滚轮接合滚动条。您可以通过按下按钮,然后使用鼠标滚轮进行测试。此外,单击面板,甚至滚动条本身,都不允许鼠标滚轮工作。
我正在寻找是一种确保如果有滚动条的方法,它们可以在显示GUI时与鼠标滚轮一起使用(默认选中它们)。我可以接受,一旦用户点击文本控件,鼠标滚轮就不会起作用。
此外,如果您有解释为什么鼠标滚轮适用于按钮而不是文本控件,我很乐意听到它
编辑:我知道我可以添加一个监听器(感谢Joran Beasley先生),但这意味着多行文本控件中的滚动条永远不会与鼠标滚轮一起使用。理想的解决方案(我不确定是否可行)是点击文本控件(面板或滚动条)外的任何位置,允许鼠标滚轮滚动面板。这可能吗?
此外,我已切换到使用ScrolledWindow
而不是ScrolledPanel
编辑2:修复方法是使用以下内容:
self.panel.Bind(wx.EVT_MOTION, self.onMouseMove)
def onMouseMove(self, event):
self.panel.SetFocusIgnoringChildren()
编辑3 实际的修复是为了做一些有点棘手的事情。使用下面的代码,我只将多行文字控件绑定到EVT_ENTER_WINDOW
和EVT_LEAVE_WINDOW
,并将每个项目(以及面板本身)绑定到EVT_MOUSEWHEEL
。然后逻辑self.inMLTxtCtrl
跟踪鼠标是否超过任何多行文本控件
self.panel.Bind(wx.EVT_MOUSEWHEEL, self.onWheel)
for sizerItem in self.panel.GetSizer().GetChildren():
try:
if sizerItem.GetWindow().IsMultiLine():
sizerItem.GetWindow().Bind(wx.EVT_ENTER_WINDOW, self.onMouseEnter)
sizerItem.GetWindow().Bind(wx.EVT_LEAVE_WINDOW, self.onMouseLeave)
sizerItem.GetWindow().Bind(wx.EVT_MOUSEWHEEL, self.onWheel)
except:
sizerItem.GetWindow().Bind(wx.EVT_MOUSEWHEEL, self.onWheel)
然后逻辑self.inMLTxtCtrl
跟踪鼠标是否超过任何多行文字控件,如下所示。
def onMouseEnter(self, event):
print "entering"
self.inMLTxtCtrl = True
def onMouseLeave(self, event):
print "leaving"
self.inMLTxtCtrl = False
最后,onWheel()
函数使用此逻辑标志来确定滚动的位置。如果在转动滚轮时鼠标位于多行文本控件中,它会尝试滚动该文本控件。然后,调用SetFocusIgnoringChildren()
函数并滚动面板。由于面板和文本控件使用不同的滚动方法,因此需要try...except
。
def onWheel(self, event):
if self.inMLTxtCtrl:
print "in", event.GetWheelRotation()
else:
print "out", event.GetWheelRotation()
self.panel.SetFocusIgnoringChildren()
try:
currScroll = self.panel.FindFocus().GetViewStart()
newScroll = (currScroll[0],currScroll[1]- event.GetWheelRotation()/60)
self.panel.FindFocus().Scroll(*newScroll)
except:
self.panel.FindFocus().ScrollLines(event.GetWheelRotation()/-60)
答案 0 :(得分:1)
class Tester(wx.Frame):
def OnTxtScroll(self,e):
currScroll = self.panel.GetViewStart()
newScroll = (currScroll[0],currScroll[1]- e.GetWheelRotation()/120)
self.panel.Scroll(*newScroll)
def __init__(self):
....
#your code
....
self.panel = panel
textBox.Bind(wx.EVT_MOUSEWHEEL,self.OnTxtScroll)
在你澄清之后......我认为这会起作用(它有点hacky并且没有完全按照你的描述......但它可能有效)
def OnTxtScroll(self,e):
print dir(e)
target = e.GetEventObject()
p1 = target.GetScrollPos(wx.VERTICAL)
e.Skip()
self.Update()
def updateScroll(p1,target,scroll_amt):
p2 = target.GetScrollPos(wx.VERTICAL)
if p1 ==p2:#scroll did not effect target object so lets scroll our main panel
currScroll = self.panel.GetViewStart()
newScroll = (currScroll[0],currScroll[1]- scroll_amt)
self.panel.Scroll(*newScroll)
wx.CallAfter(updateScroll,p1,target,e.GetWheelRotation()/120)