首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >滚动面板MouseWheel滚动

滚动面板MouseWheel滚动
EN

Stack Overflow用户
提问于 2015-09-06 10:47:43
回答 1查看 544关注 0票数 1

我希望你能帮助我:)我的头撞到了墙上,当我使用鼠标滚轮时,我无法让滚动面板上下滚动。当我单击或拖动它时,它可以正常工作。

我正在做的是用一堆textctrl填充一个面板,并使用滚动面板在它们之间滚动。当鼠标移到面板上时,我会尝试设置面板的焦点,甚至在单击时也会尝试,但当我使用鼠标滚轮在面板上上下滚动时,什么也没有发生。

我看过ScrolledPanels的wxPython示例,但我不明白为什么他们的示例可以工作,而我的不能。

任何给予的帮助都将是令人惊叹的!

编辑:我发现,当文本EDIT被选中时,它会激活滚动-但当使用TE_MULTILINE时却不会。Expando Text ctrls使用TE_MULTILINE样式,所以我只能在单击单行text Ctrls时激活滚动条。

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

代码语言:javascript
复制
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()
EN

回答 1

Stack Overflow用户

发布于 2015-11-22 12:59:18

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

发生这种情况时的解决方案:

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

最后,如果事件仍未被处理,则

对象本身(从EvtHandler派生)获得最后一次处理它的机会。

So wx.GetApp().Bind(wx.EVT_MOUSEWHEEL,your_handler)

(2)如何手动处理事件?取自this post的想法( Doug Anderson根据pygcodeviewer/pygcodeviewer.py内部的评论编写)

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

考虑到我们是在应用程序级别捕获的:我们必须确保事件来自滚动面板的wxWindow的子级,如果不是,跳过()它并让它过去。

因此,下面是一个作为mixin类的解决方案:

代码语言:javascript
复制
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

记得在添加混入之后初始化它,然后就完成了:

代码语言:javascript
复制
class TicketViewer(wx.lib.scrolledpanel.ScrolledPanel, TeMultilineScrollAwareMixin):
    def __init__(self, parent):
        ... your init code ...
        TeMultilineScrollAwareMixin.__init__(self)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32419535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档