mardi 12 août 2014

python - Disablling défilement d'une barre de défilement tout en la gardant visibles dans wxPython - Stack Overflow


I am currently working with wxPython v3.0, python v2.7 on Windows 7 OS. I have question regarding the scroll bars. In my application I have a GUI which has many scrolled panels. The scroll bar of these scrolled panels are working fine too.


Problem: My question is that is it possible to disable the scrolling of a scroll bar while keeping it visible on a particular scrolled panel? The scroll bar shouldn't scroll when being clicked on the scroll buttons or by dragging the scroll bar.


I know that we can disable horizontal or vertical scrolling by using SetupScrolling(scroll_y=False) and SetupScrolling(scroll_x=False). But this will also make the scroll bar invisible. I also tried setting the scroll rate to 0 by using rate_y & rate_x, this also makes the scroll bar invisible. In short I want to show the scroll bar but make it do nothing.


Is there a way to capture the scroll events and make them to do nothing? I tried a hit and trial method by binding myPanel with wx.EVT_SCROLLWIN to execute a function that does nothing. Unfortunately it didn't worked (the scroll bar is still scrolling).


myPanel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
myPanel.Bind(wx.EVT_SCROLLWIN, self.onScroll)

def onScroll(self, event):
pass

Here is a quick & dirty code sample to play around and can be downloaded too! to avoid identation errors.:


#!/usr/bin/env python

import wx
import wx.lib.scrolledpanel


class GUI(wx.Frame):

def __init__(self, parent, id, title):
screenSize = (400, 400)
wx.Frame.__init__(self, None, id, title, size=screenSize)
myFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
panelsSizer = wx.BoxSizer(wx.VERTICAL)
sizer1 = wx.BoxSizer(wx.VERTICAL)
myPanel = wx.lib.scrolledpanel.ScrolledPanel(self, -1,style=wx.SIMPLE_BORDER)
myPanel.Bind(wx.EVT_SCROLLWIN, self.onScroll)
myPanel.SetupScrolling()
panel1 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel1.SetBackgroundColour('#FFFFFF')
panel2 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel2.SetBackgroundColour('#55F4FF')


k = 0
for i in range(1,7):
sPanel ='Panel' +str(k)
sPanel = wx.Panel(panel1)
label = str(k)+'This is panel-1'
text = wx.StaticText(sPanel, -1, label)
text.SetForegroundColour('#0101DF')
text.SetFont(myFont)
sizer1.Add(sPanel, 0, wx.ALL, 5)
sizer1.Add(wx.StaticLine(panel1), 0, wx.ALL|wx.EXPAND, 0)
k += 1

panel1.SetSizer(sizer1)
panelsSizer.Add(panel1, 1, wx.EXPAND)
panelsSizer.Add(panel2, 1, wx.EXPAND)
myPanel.SetSizer(panelsSizer)

def onScroll(self, event):
pass


if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()

Any suggestion? Thank you for your time.




I finally figured out a solution to my problem. But I didn't quite understand that why it works. :P


I was reading tutorial on http://wiki.wxpython.org/AnotherTutorial#Events and found something interesting. The wiki states:



wx.ScrollWinEvent event is generated, when we click on a built in Scrollbar. Built-in Scrollbar is activated with the SetScrollbar() method call. For stand-alone Scrollbars, there is another event type, namely wx.ScrollEvent.



So I decided to setup a Built-in scroll bar and then I'll bind my onScroll() to do nothing when scroll bar is moved. Now instead of creating a scrolledPanel I created a simple Panel.


myPanel = wx.Panel(self, -1,style=wx.SIMPLE_BORDER)

Then I create a Built-in scroll bar using setScrollbar().


myPanel.SetScrollbar(wx.VERTICAL, 0, 0, 2, 0)

Then I bind the onScroll() to the any scrolling events that are happening.


myPanel.Bind(wx.EVT_SCROLLWIN, self.OnScroll)

So, now you'll notice that the scroll bar on myPanel will do nothing on being clicked or dragged.


Not understood by me:


You really don't need to intercept any scrolling events. You don't need to bind the onScroll(). Even if you don't bind the onScroll(), the scroll bar is still not responding to any clicking or dragging! Perhaps I am missing something basic.


Here is the updated code to play around also available for download to avoid indentation problems:


class GUI(wx.Frame):

def __init__(self, parent, id, title):
screenSize = (400, 400)
wx.Frame.__init__(self, None, id, title, size=screenSize)
myFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
panelsSizer = wx.BoxSizer(wx.VERTICAL)
sizer1 = wx.BoxSizer(wx.VERTICAL)
myPanel = wx.Panel(self, -1,style=wx.SIMPLE_BORDER)
#Uncommenting the following line has no effect on scroll bar behavior!
#myPanel.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
myPanel.SetScrollbar(wx.VERTICAL, 0, 0, 2, 0)
panel1 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel1.SetBackgroundColour('#FFFFFF')
panel2 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel2.SetBackgroundColour('#55F4FF')


k = 0
for i in range(1,10):
sPanel ='Panel' +str(k)
sPanel = wx.Panel(panel1)
label = str(k)+'This is panel-1'
text = wx.StaticText(sPanel, -1, label)
text.SetForegroundColour('#0101DF')
text.SetFont(myFont)
sizer1.Add(sPanel, 0, wx.ALL, 5)
sizer1.Add(wx.StaticLine(panel1), 0, wx.ALL|wx.EXPAND, 0)
k += 1

panel1.SetSizer(sizer1)
panelsSizer.Add(panel1, 1, wx.EXPAND)
panelsSizer.Add(panel2, 1, wx.EXPAND)
myPanel.SetSizer(panelsSizer)

def OnScroll(self, evt):
print "Got it"
pass



if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()



Woo hoo, I read you solved it.


Meanwhile, this is the best awful hack I could come up with:


#!/usr/bin/env python

import wx
import wx.lib.scrolledpanel


class GUI(wx.Frame):

def __init__(self, parent, id, title):
screenSize = (400, 400)
wx.Frame.__init__(self, None, id, title, size=screenSize)
myFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
panelsSizer = wx.BoxSizer(wx.VERTICAL)
sizer1 = wx.BoxSizer(wx.VERTICAL)
myPanel = wx.lib.scrolledpanel.ScrolledPanel(self, -1,style=wx.SIMPLE_BORDER)
myPanel.Bind(wx.EVT_SCROLLWIN, self.onScroll)
myPanel.SetupScrolling()
panel1 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel1.SetBackgroundColour('#FFFFFF')
panel2 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel2.SetBackgroundColour('#55F4FF')


k = 0
for i in range(1,7):
sPanel ='Panel' +str(k)
sPanel = wx.Panel(panel1)
label = str(k)+'This is panel-1'
text = wx.StaticText(sPanel, -1, label)
text.SetForegroundColour('#0101DF')
text.SetFont(myFont)
sizer1.Add(sPanel, 0, wx.ALL, 5)
sizer1.Add(wx.StaticLine(panel1), 0, wx.ALL|wx.EXPAND, 0)
k += 1

panel1.SetSizer(sizer1)
panelsSizer.Add(panel1, 1, wx.EXPAND)
panelsSizer.Add(panel2, 1, wx.EXPAND)
myPanel.SetSizer(panelsSizer)
self.scrolled_panel=myPanel

def onScroll(self, event):
print "scroll event"
for child in self.scrolled_panel.GetChildren():
try:
child.SetThumbPosition(0)
print "set child"
except:
print "oops,probably not a scrollbar :) "


if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()

It doesn't stop them dragging the scrollbar, but it does pop it back after they let go.


Update: The code above only works on OSX, not Windows.


Under OSX, the children of a ScrolledPanel are reported as:


wxWindowList: [<wx._controls.ScrollBar; proxy of <Swig Object of type 'wxScrollBar *' at 0x10068f830> >, <wx._controls.ScrollBar; proxy of <Swig Object of type 'wxScrollBar *' at 0x100691230> >, <wx._core.Window; proxy of <Swig Object of type 'wxWindow *' at 0x100691d20> >, <wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScrolledWindow *' at 0x1004ac990> >, <wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScrolledWindow *' at 0x1004af8e0> >]

It's the two ScrollBar's that my hack is targetting.


Under Windows, the same call returns:


wxWindowList: [<wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScrolledWindo
w *' at 0x26837b8> >, <wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScroll
edWindow *' at 0x26839b0> >]

This is much harder to understand. Where are the scroll bars hiding? I guess this is what you get for hacking into components that are supposed to be encapsulated for you :)




I can't test this at the moment and it may be covered under what you have already tried, without more information I can't tell.


As far as I know there is no set way to disable scrolling without removing the scrollbar, what I would try in your position is, instead of using 'pass' when you fire the onScroll event, set the scrollbar position to 0 using set position, this might only reset the position after it has been moved though, I think you should be able to take control of the scroll event, I'm not sure why that isn't working for you.


Another option might be to set the scrollbars range to 0 or a very small number.



I am currently working with wxPython v3.0, python v2.7 on Windows 7 OS. I have question regarding the scroll bars. In my application I have a GUI which has many scrolled panels. The scroll bar of these scrolled panels are working fine too.


Problem: My question is that is it possible to disable the scrolling of a scroll bar while keeping it visible on a particular scrolled panel? The scroll bar shouldn't scroll when being clicked on the scroll buttons or by dragging the scroll bar.


I know that we can disable horizontal or vertical scrolling by using SetupScrolling(scroll_y=False) and SetupScrolling(scroll_x=False). But this will also make the scroll bar invisible. I also tried setting the scroll rate to 0 by using rate_y & rate_x, this also makes the scroll bar invisible. In short I want to show the scroll bar but make it do nothing.


Is there a way to capture the scroll events and make them to do nothing? I tried a hit and trial method by binding myPanel with wx.EVT_SCROLLWIN to execute a function that does nothing. Unfortunately it didn't worked (the scroll bar is still scrolling).


myPanel = wx.lib.scrolledpanel.ScrolledPanel(self, -1, style=wx.SIMPLE_BORDER)
myPanel.Bind(wx.EVT_SCROLLWIN, self.onScroll)

def onScroll(self, event):
pass

Here is a quick & dirty code sample to play around and can be downloaded too! to avoid identation errors.:


#!/usr/bin/env python

import wx
import wx.lib.scrolledpanel


class GUI(wx.Frame):

def __init__(self, parent, id, title):
screenSize = (400, 400)
wx.Frame.__init__(self, None, id, title, size=screenSize)
myFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
panelsSizer = wx.BoxSizer(wx.VERTICAL)
sizer1 = wx.BoxSizer(wx.VERTICAL)
myPanel = wx.lib.scrolledpanel.ScrolledPanel(self, -1,style=wx.SIMPLE_BORDER)
myPanel.Bind(wx.EVT_SCROLLWIN, self.onScroll)
myPanel.SetupScrolling()
panel1 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel1.SetBackgroundColour('#FFFFFF')
panel2 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel2.SetBackgroundColour('#55F4FF')


k = 0
for i in range(1,7):
sPanel ='Panel' +str(k)
sPanel = wx.Panel(panel1)
label = str(k)+'This is panel-1'
text = wx.StaticText(sPanel, -1, label)
text.SetForegroundColour('#0101DF')
text.SetFont(myFont)
sizer1.Add(sPanel, 0, wx.ALL, 5)
sizer1.Add(wx.StaticLine(panel1), 0, wx.ALL|wx.EXPAND, 0)
k += 1

panel1.SetSizer(sizer1)
panelsSizer.Add(panel1, 1, wx.EXPAND)
panelsSizer.Add(panel2, 1, wx.EXPAND)
myPanel.SetSizer(panelsSizer)

def onScroll(self, event):
pass


if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()

Any suggestion? Thank you for your time.



I finally figured out a solution to my problem. But I didn't quite understand that why it works. :P


I was reading tutorial on http://wiki.wxpython.org/AnotherTutorial#Events and found something interesting. The wiki states:



wx.ScrollWinEvent event is generated, when we click on a built in Scrollbar. Built-in Scrollbar is activated with the SetScrollbar() method call. For stand-alone Scrollbars, there is another event type, namely wx.ScrollEvent.



So I decided to setup a Built-in scroll bar and then I'll bind my onScroll() to do nothing when scroll bar is moved. Now instead of creating a scrolledPanel I created a simple Panel.


myPanel = wx.Panel(self, -1,style=wx.SIMPLE_BORDER)

Then I create a Built-in scroll bar using setScrollbar().


myPanel.SetScrollbar(wx.VERTICAL, 0, 0, 2, 0)

Then I bind the onScroll() to the any scrolling events that are happening.


myPanel.Bind(wx.EVT_SCROLLWIN, self.OnScroll)

So, now you'll notice that the scroll bar on myPanel will do nothing on being clicked or dragged.


Not understood by me:


You really don't need to intercept any scrolling events. You don't need to bind the onScroll(). Even if you don't bind the onScroll(), the scroll bar is still not responding to any clicking or dragging! Perhaps I am missing something basic.


Here is the updated code to play around also available for download to avoid indentation problems:


class GUI(wx.Frame):

def __init__(self, parent, id, title):
screenSize = (400, 400)
wx.Frame.__init__(self, None, id, title, size=screenSize)
myFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
panelsSizer = wx.BoxSizer(wx.VERTICAL)
sizer1 = wx.BoxSizer(wx.VERTICAL)
myPanel = wx.Panel(self, -1,style=wx.SIMPLE_BORDER)
#Uncommenting the following line has no effect on scroll bar behavior!
#myPanel.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
myPanel.SetScrollbar(wx.VERTICAL, 0, 0, 2, 0)
panel1 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel1.SetBackgroundColour('#FFFFFF')
panel2 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel2.SetBackgroundColour('#55F4FF')


k = 0
for i in range(1,10):
sPanel ='Panel' +str(k)
sPanel = wx.Panel(panel1)
label = str(k)+'This is panel-1'
text = wx.StaticText(sPanel, -1, label)
text.SetForegroundColour('#0101DF')
text.SetFont(myFont)
sizer1.Add(sPanel, 0, wx.ALL, 5)
sizer1.Add(wx.StaticLine(panel1), 0, wx.ALL|wx.EXPAND, 0)
k += 1

panel1.SetSizer(sizer1)
panelsSizer.Add(panel1, 1, wx.EXPAND)
panelsSizer.Add(panel2, 1, wx.EXPAND)
myPanel.SetSizer(panelsSizer)

def OnScroll(self, evt):
print "Got it"
pass



if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()


Woo hoo, I read you solved it.


Meanwhile, this is the best awful hack I could come up with:


#!/usr/bin/env python

import wx
import wx.lib.scrolledpanel


class GUI(wx.Frame):

def __init__(self, parent, id, title):
screenSize = (400, 400)
wx.Frame.__init__(self, None, id, title, size=screenSize)
myFont = wx.Font(15, wx.MODERN, wx.NORMAL, wx.BOLD)
panelsSizer = wx.BoxSizer(wx.VERTICAL)
sizer1 = wx.BoxSizer(wx.VERTICAL)
myPanel = wx.lib.scrolledpanel.ScrolledPanel(self, -1,style=wx.SIMPLE_BORDER)
myPanel.Bind(wx.EVT_SCROLLWIN, self.onScroll)
myPanel.SetupScrolling()
panel1 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel1.SetBackgroundColour('#FFFFFF')
panel2 = wx.lib.scrolledpanel.ScrolledPanel(myPanel, -1, style=wx.SIMPLE_BORDER)
panel2.SetBackgroundColour('#55F4FF')


k = 0
for i in range(1,7):
sPanel ='Panel' +str(k)
sPanel = wx.Panel(panel1)
label = str(k)+'This is panel-1'
text = wx.StaticText(sPanel, -1, label)
text.SetForegroundColour('#0101DF')
text.SetFont(myFont)
sizer1.Add(sPanel, 0, wx.ALL, 5)
sizer1.Add(wx.StaticLine(panel1), 0, wx.ALL|wx.EXPAND, 0)
k += 1

panel1.SetSizer(sizer1)
panelsSizer.Add(panel1, 1, wx.EXPAND)
panelsSizer.Add(panel2, 1, wx.EXPAND)
myPanel.SetSizer(panelsSizer)
self.scrolled_panel=myPanel

def onScroll(self, event):
print "scroll event"
for child in self.scrolled_panel.GetChildren():
try:
child.SetThumbPosition(0)
print "set child"
except:
print "oops,probably not a scrollbar :) "


if __name__=='__main__':
app = wx.App()
frame = GUI(parent=None, id=-1, title="Test")
frame.Show()
app.MainLoop()

It doesn't stop them dragging the scrollbar, but it does pop it back after they let go.


Update: The code above only works on OSX, not Windows.


Under OSX, the children of a ScrolledPanel are reported as:


wxWindowList: [<wx._controls.ScrollBar; proxy of <Swig Object of type 'wxScrollBar *' at 0x10068f830> >, <wx._controls.ScrollBar; proxy of <Swig Object of type 'wxScrollBar *' at 0x100691230> >, <wx._core.Window; proxy of <Swig Object of type 'wxWindow *' at 0x100691d20> >, <wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScrolledWindow *' at 0x1004ac990> >, <wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScrolledWindow *' at 0x1004af8e0> >]

It's the two ScrollBar's that my hack is targetting.


Under Windows, the same call returns:


wxWindowList: [<wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScrolledWindo
w *' at 0x26837b8> >, <wx.lib.scrolledpanel.ScrolledPanel; proxy of <Swig Object of type 'wxPyScroll
edWindow *' at 0x26839b0> >]

This is much harder to understand. Where are the scroll bars hiding? I guess this is what you get for hacking into components that are supposed to be encapsulated for you :)



I can't test this at the moment and it may be covered under what you have already tried, without more information I can't tell.


As far as I know there is no set way to disable scrolling without removing the scrollbar, what I would try in your position is, instead of using 'pass' when you fire the onScroll event, set the scrollbar position to 0 using set position, this might only reset the position after it has been moved though, I think you should be able to take control of the scroll event, I'm not sure why that isn't working for you.


Another option might be to set the scrollbars range to 0 or a very small number.


0 commentaires:

Enregistrer un commentaire