繁体   English   中英

滚动面板鼠标

[英]Scrolled Panel MouseWheel Scroll

我希望您能帮到我:)我的头撞在墙上,当我使用鼠标滚轮时,无法使“滚动面板”上下滚动。 当我单击它或拖动它时,它可以工作。

我正在做的是用一堆textctrl填充面板,并使用滚动面板在其中滚动。 我试图在鼠标悬停时设置面板的焦点,甚至在单击时尝试尝试设置,但是当我用鼠标滚轮在面板上上下滚动时什么也没有发生。

我已经看过ScrolledPanels的wxPython示例,但是我看不到为什么我的不起作用。

提供的任何帮助都将是惊人的!

编辑:我发现,当选择textctrl时,它会激活滚动-但在使用TE_MULTILINE时不会。 Expando Text Ctrls使用TE_MULTILINE样式,因此仅在单击单行文本ctrl时,我才能使用滚动条。

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

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()

这样做的原因是ScrolledPanel派生自wx.Panel,其代码具有每次接收焦点时都会尝试将焦点重置为其第一个子对象的代码。 此外,在Windows中,轮事件仅发送到具有焦点的窗口小部件。 (有用的线程与罗宾·邓恩讲话

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

(1)在哪里赶活动? 在应用程序级别。 如wxpython docs中所述,有关事件表搜索的顺序: 如何处理事件

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

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

(2)以及如何手动处理事件? 这篇文章中 汲取想法(由Doug Anderson根据pygcodeviewer / pygcodeviewer.py中的评论编写

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

..并考虑到我们在应用程序级别上有所发展:我们必须确保该事件来自wxWindow [滚动面板]的子级,否则,请跳过并放开它。

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

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM