【问题标题】:Scrolled Panel MouseWheel Scroll滚动面板鼠标滚轮滚动
【发布时间】:2015-09-06 02:47:43
【问题描述】:

我希望您能帮帮我:) 我的头撞墙了,当我使用鼠标滚轮时,我无法让滚动面板上下滚动。当我单击它或拖动它时它会起作用。

我正在做的是用一堆 textctrls 填充一个面板,并使用滚动面板滚动它们。我试图在鼠标悬停时设置面板的焦点,甚至在单击时尝试设置,但是当我用鼠标滚轮在面板上上下滚动时没有任何反应。

我查看了 ScrolledPanels 的 wxPython 示例,但我不明白为什么他们的工作有效,而我的却没有。

提供的任何帮助都会令人惊叹!

编辑: 我发现,选择TextCrl时,它会激活滚动 - 但在使用Te_MultInine时不会启动滚动。 Expando 文本控件使用 TE_MULTILINE 样式,因此我只能在单击单行文本控件时激活滚动条。

单击多行文本控件时如何控制滚动条以使用鼠标滚轮?

import wx
import random
import wx.lib.platebtn as pbtn
import wx.lib.agw.gradientbutton as gbtn
import wx.lib.scrolledpanel as spanel
import requests
import json
import sys
import wx.lib.mixins.listctrl  as  listmix
import wx.lib.expando as etc


ticketInfo = """
*************************\n
TEST TICKET\n
*************************\n
BLAH BLAH BLAH BLAH\n
BLAH BLAH BLAH BLAH\n
BLAH BLAH BLAH BLAH\n
BLAH BLAH BLAH BLAH\n
BLAH BLAH BLAH BLAH\n
"""


class MyApp(wx.App):
    def OnInit(self):
        self.frame = MyFrame(None, title="Learning List Controls")
        self.SetTopWindow(self.frame)
        self.frame.Show()

        return True
class TicketViewer(wx.lib.scrolledpanel.ScrolledPanel):
    def __init__(self, parent):
        super(TicketViewer, self).__init__(parent, name="panel", style=wx.TE_AUTO_SCROLL)

        #Attributes
        vSizer = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(vSizer)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.PopulateTicketMessages(ticketInfo)
        self.SetSizer(vSizer)
        self.Layout()
        self.SetupScrolling()
        panelID = self.GetId()
    def PopulateTicketMessages(self, ticketInfo):
        msgBox = etc.ExpandoTextCtrl(self,
                         id=-1,
                         value=ticketInfo,
                         style=wx.TE_READONLY|wx.TE_WORDWRAP)
        sizer = self.GetSizer()
        sizer.Add(msgBox)
        msgBox.Bind(wx.EVT_LEFT_DOWN, self.OnMouseOver)
    def OnMouseOver(self, event):
        panel = wx.FindWindowByName("panel")
        panel.SetFocus()
        print(panel)
class MyFrame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(MyFrame, self).__init__(*args, **kwargs)

        #Attribues
        self.tktViewer = TicketViewer(self)


        frameSizer = wx.BoxSizer(wx.HORIZONTAL)
        frameSizer.Add(self.tktViewer, 1, wx.EXPAND)
        self.SetSizer(frameSizer)

        #self.SetSizerAndFit(frameSizer)
        self.CreateStatusBar()
        self.SetInitialSize()

    def OnMouseOver(self, event):
        panel = wx.FindWindowById(tktViewerID)
        panel.SetFocus()
        print(self)

if __name__ == "__main__":
    app = MyApp(False)
    app.MainLoop()

【问题讨论】:

  • 作为我的谜题的更新 - 我注意到 wx.TextCtrls 在单击时会自动获取焦点,但 ExpandoTextCtrls 出于某种原因不会 - 所以我不知道如何做到这一点滚动条与 Expando 样式文本控件一起使用。有人知道如何直接抓住滚动条的焦点吗?
  • 所以现在我发现 ExpandoTextCtrl 使用了 wx.TE_MULTILINE 样式的 TextCtrl。 When a TextCtrl with TE_MULTILINE style is selected, for some reason it doesn't activate the scrollbars in the scrolledpanel :(
  • 可能是因为在使用该样式时它没有使用标准的窗口控件。
  • Ignacio 你知道我怎样才能像单行文本控件那样让这些来激活滚动条吗?
  • 您可能需要捕捉鼠标滚轮事件并手动滚动。

标签: python wxpython


【解决方案1】:

原因是 ScrolledPanel 派生自 wx.Panel,它的代码每次收到焦点时都会尝试将焦点重置为其第一个子项。此外,在 Windows 中,滚轮事件仅发送到具有焦点的小部件。 (Useful thread with Robin Dunn remarks)

出现这种情况时的解决方法:

(1)在哪里赶上活动?在应用程序级别。 正如 wxpython 文档中关于事件表搜索的顺序所说:How Events are Processed

最后,即如果事件仍未处理,则 App 对象 本身(从 EvtHandler 派生)获得处理的最后机会 它。

所以wx.GetApp().Bind(wx.EVT_MOUSEWHEEL, your_handler)

(2)以及如何手动处理事件? 借鉴this post的想法(Doug Anderson根据pygcodeviewer/pygcodeviewer.py里面的cmets写的)

需要在我们感兴趣的wxWindow(滚动面板)上调用GetHandler().ProcessEvent(event)

..考虑到我们在应用程序级别进行捕获:我们必须确保事件来自我们的 wxWindow [滚动面板] 的子级,否则,跳过()它并让它过去。

所以,这是一个混合类的解决方案:

class TeMultilineScrollAwareMixin(object):
    """ Mixin class for wx.lib.scrolledpanel.ScrolledPanel so it's
    aware of scroll events from childs with the TE_MULTILINE style
    """

    def __init__(self, *args, **kwargs):
        self._pLastEvtObj = None        
        wx.GetApp().Bind(wx.EVT_MOUSEWHEEL, self.OnUnhandledMouseWheel)

    def OnUnhandledMouseWheel(self, event):
        # stops the same event object being processed repeatedly
        if self._pLastEvtObj == event.GetEventObject():
            return False

        self._pLastEvtObj = event.GetEventObject()

        def is_child_evt():
            parent = event.GetEventObject().GetParent()
            while parent:
                if parent == self: 
                    return True
                parent = parent.GetParent() 
            return False

        # as we are listening at app level, must ensure that event is from a widget of us
        if is_child_evt():
            print 'event from %s' % event.GetEventObject().__class__.__name__
            # if the event was not handled this window will handle it,
            # which is why we need the protection code at the beginning
            # of this method
            self.GetEventHandler().ProcessEvent(event)            
        else:
            # it's not of our interest, let it go
            event.Skip()

        self._pLastEvtObj = None
        return

记得在添加之后初始化mixin,你就完成了:

class TicketViewer(wx.lib.scrolledpanel.ScrolledPanel, TeMultilineScrollAwareMixin):
    def __init__(self, parent):
        ... your init code ...
        TeMultilineScrollAwareMixin.__init__(self)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-08
    • 1970-01-01
    • 2014-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 2013-04-20
    相关资源
    最近更新 更多