【发布时间】:2013-12-19 21:23:29
【问题描述】:
我有几个逐步打开的 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)
【问题讨论】:
-
...您当然可以将 wx.EVT_MOUSEWHEEL 的侦听器添加到文本字段以将滚动重定向到滚动条
-
听起来很理想,我该怎么做?
-
更新了我的答案,使其更符合您的要求....调整到 ScrolledWindow 很容易)
标签: python python-2.7 user-interface wxpython