2015-09-06 201 views
0

我希望你能幫助我:)我的頭撞牆,我無法獲得滾動面板上下滾動,當我使用鼠標滾輪時。它可以在我點擊它或拖動它時使用。滾動面板鼠標滾輪滾動

我在做什麼是與一堆textctrls填充面板和使用滾動面板來滾動它們。我試圖在鼠標懸停時嘗試設置面板的焦點,甚至在單擊時嘗試嘗試,但當鼠標滾輪在面板上上下滾動時,沒有任何反應。

我已經看過了ScrolledPanels的wxPython示例,但我無法明白他們爲什麼在工作,而我的工作不是。

任何幫助將是驚人的!

編輯: 我發現,當一個textctrl被選中時,它會激活滾動 - 但不是當使用TE_MULTILINE時。 Expando Text Ctrls使用TE_MULTILINE風格,所以我只能在單擊單行文本ctrls時才能使滾動條移動。

如何在單擊多行文本控件時控制滾動條以使用鼠標滾輪?

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

作爲更新到我的困惑 - 我注意到wx。TextCtrls在點擊時自動獲取焦點,但由於某些原因,ExpandoTextCtrls不會 - 所以我不知道如何使這個滾動條適用於Expando樣式的文本控件。任何人都知道如何直接抓住滾動條的焦點? – ThirdProphecy

+0

所以現在我發現了ExpandoTextCtrl使用了TextCtrl的wx.TE_MULTILINE風格。當選擇帶有TE_MULTILINE樣式的TextCtrl時,出於某種原因它不會激活滾動面板中的滾動條:( – ThirdProphecy

+0

可能是因爲它在使用該樣式時沒有使用標準窗口控件 –

回答

0

這樣做的原因是,從ScrolledPanel派生wx.Panel,至極有每次它接收到焦點將嘗試將焦點重置爲其第一個孩子代碼。此外,在Windows中,車輪事件只被發送到具有焦點的小部件。 (Useful thread with Robin Dunn remarks

當發生這種情況的解決方案:

(1)凡趕上事件?在應用程序級別。 如同在事件表搜索的順序wxPython的文檔說:How Events are Processed

最後,也就是說,如果仍不能處理的情況下,App對象 本身(從EvtHandler派生)得到一個最後機會過程 它。

所以wx.GetApp()。綁定(wx.EVT_MOUSEWHEEL,your_handler)

(2)如何手動處理事件? 以從this post想法

它需要調用GetHandler()。processEvent方法(事件)對我們的利益的wxWindow的(滾動面板)(據內部pygcodeviewer/pygcodeviewer.py評論道格·安德森寫的)

..考慮到我們正在捕捉應用程序級別:我們必須確保該事件來自我們的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 

記得將它添加後給init混入,就大功告成了:

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