Overlapped controls [was: a scrollbar problem with xrc loaded grid]
Stuart McGraw
smcg4191 at frii.com
Sun Dec 2 17:50:50 PST 2007
Robin Dunn wrote:
> Stuart wrote:
[...]
Robin, thank you for the excellent explanation of cause
and fix of the scrollbar anomaly in the grid control when
loaded via an xrc "unknown" control.
> A probably better way to take care of this is to not use the unknown
> control feature at all. You can use a normal grid class type in the
> XRC, and set the subclass attribute to the modulename.classname of your
> grid class. That causes the subclass factory to create an instance of
> the class, but in all other ways it will be treated as a wx.grid.Grid.
> Then there won't be any mysterious container panel created behind the
> scenes for you to get in the way. This takes a little tweaking of the
> class that will be loaded this way, see the demo for an example.
Yes, I will try doing that next. But since the current code
is so close to working, I want to finish it, if only for my
notes.
>> The reason there is no sizer in panel2 is that in the
>> real app, there is also an html control in there,
>> overlapping the grid, and I will hide one of the other
>> according to conditions, as per
>> http://lists.wxwidgets.org/archive/wxPython-users/msg14336.html
>> Would an "overlap sizer" be a useful addition to wxwidgets?
> =
> Most people do this simply by putting all of their page windows into a =
> box sizer, and then hiding all but the one they want shown. When you =
> want to show a different page then just show it, hide the old one and =
> call the sizer's Layout method.
Ahh, it didn't occur to me that the sizer would take the
control's visibility into account but it makes sense that
it would.
I tried follow your suggestion and it almost works but I still
have something wrong. I have an htmlwindow control and an
xrc.AttachUnknownControl attached Grid subclass in the same sizer,
and a button to change their Show() states so that when one is
shown the other is hidden.
One problem is that (as you pointed out in the previous response)
the Grid control is placed in an additional Panel created by the
xrc loader. So I found I had to show/hide that panel rather
than the grid itself, which I do by calling grid.GetParent().Show()
I suppose this is brittle in that XRC might decide to arrange things
differently someday. Is there any better way?
The second bigger (and remaining) problem is that the shown control
is not resized correctly after the show status of the grid and
htmlwindow are swapped (when the Chng View view button in the
sample code is clicked), but, as soon as the frame size is changed,
the shown control is properly resized and everything looks right.
I call the frame's Layout method but it doesn't help. I also
tried to generate a synthetic resize event with various permutation
of ProcessEvent() and CallAfter() but also with no luck, so again
I could use some help.
Attached are the files overlay.py and overlay.xrc. The problem
is evident when the Chng View button is clicked after starting or
after resizing the frame.
BTW, thanks for pointer the InspectionTool, it is fantastic.
Perhaps I am the only person who didn't know about it but in
case there are others, here are my cheat-sheet cut'n'paste notes
on using it, in hopes it will save someone a couple minutes.
...
import wx.lib.inspection as wxi
...
app =3D wx.Application (...)
wxi.InspectionTool().Show()
app.MainLoop ()
I also wrote in the original post:
>> I think a notebook control would also work well if I could
>> get rid of the tabs and control page switching from buttons
>> and menus. Is getting rid of the tabs possible?
Can I take the lack of an affirmative answer as a negative one?
I looked in the docs and demos and didn't notice anything that
suggested this was doable, but the waters of wxPython run deep... :-)
-------------- next part --------------
#!/usr/bin/env python
import sys, random, pdb
import wx, wx.xrc, wx.html, wx.grid
import wx.lib.inspection as wxi
XRC =3D wx.xrc.XRCCTRL
def main():
model =3D Model ()
app =3D Application (model)
## wxi.InspectionTool().Show()
app.MainLoop ()
class Application (wx.App):
def __init__ (self, model):
self.model =3D model
wx.App.__init__(self, redirect=3D0)
def OnInit (self):
xrcres =3D wx.xrc.XmlResource ("overlay.xrc")
frame =3D Frame (None, -1, "Entry", xrcres, self.model)
self.SetTopWindow (frame)
return True
# This class handles all the user-interface and GUI work.
# Window physical layout is defined in the .xrc file.
class Frame (wx.Frame):
def __init__ (self, parent, id, title, xrcres, model):
self.model =3D model # Database interface.
wx.Frame.__init__ (self, parent, id, title)
xrcres.LoadPanel (self, "PANEL1")
self.grid =3D MyGrid (self, ('AAA','BBB','CCC'), 20)
self.grid.SetMinSize((1,1))
xrcres.AttachUnknownControl ('grid', self.grid, self)
self.html =3D XRC(self, 'html')
self.init_cntls()
self.set_view (0) # Initial view: 0=3Dgrid, 1=3Dhtml
self.Show (True)
def init_cntls (self):
XRC (self, "view").Bind(wx.EVT_BUTTON, self.chng_view)
self.html.SetPage('This is some<p><br><b><font size=3D"+3">Text!</font></b=
>')
self.chng_data()
def chng_view (self, evt=3DNone):
self.view =3D 1 - self.view
# self.view: 0=3Dshow grid, 1=3Dshow htmlwindow.
self.html.Show (self.view =3D=3D 1)
self.grid.GetParent().Show (self.view =3D=3D 0)
self.Layout()
## size =3D self.GetSize()
## tweaked =3D (size.x - 1, size.y - 1)
## evt =3D wx.SizeEvent (tweaked)
## self.GetEventHandler().ProcessEvent (evt)
def set_view (self, view):
self.view =3D 1 - view #Flip view because chng_view() will flip it back.
self.chng_view()
def chng_data (self, evt=3DNone):
self.model.chng_data (12, 12)
self.grid.loaddata (self.model.data)
class MyGrid (wx.grid.Grid):
'''Subclass of wx.Grid that provides methods for adjusting
the number of rows, and for reloading grid data from an
array with adjustment of the number of rows to match.''' =
=
def __init__ (self, parent, colheads, maxrows, data=3D[]):
wx.grid.Grid.__init__(self, parent, -1) =
# Must create view with max rows we will ever need,
# to get window size right (I think). =
self.CreateGrid (maxrows, len(colheads))
# Not enough to specify in CreateGrid(), also have =
# actually populate it. Will delete the rows later
# when real data is added.
for r in range (maxrows):
for c in range (len(colheads)):
self.SetCellValue (r, c, '')
self.setcolheads (colheads)
self.loaddata (data)
def setcolheads (self, colheads):
for n,lbl in enumerate (colheads):
self.SetColLabelValue (n, lbl)
def loaddata (self, data):
self.adjustsize (len (data))
for c in range(self.GetNumberCols()):
for r in range (len(data)):
self.SetCellValue (r, c, str(data[r][c]))
def adjustsize (self, nrows):
" Adjust the number of rows in the grid so that it will"
" have exactly 'nrows' rows by inserting or deleting an"
" appropriate number of rows."
delta =3D nrows - self.GetNumberRows()
if delta > 0: =
if not self.InsertRows (0, delta):
raise RuntimeError ("Failed to insert %d rows into grid" % delta)
if delta < 0: =
if not self.DeleteRows (0, -delta):
raise RuntimeError ("Failed to delete %d rows from grid" % delta)
class Model:
def __init__(self):
self.data =3D []
def chng_data (self, maxrows=3D12, minrows=3D0):
# Create between minrows and maxrows rows of 3-column random data...
self.data =3D []
chars =3D list('abcdefg')
nrows =3D random.randint (minrows, maxrows)
for i in range (nrows):
random.shuffle (chars)
self.data.append (
(i * 10,
''.join(chars[:random.randint (2,6)]),
random.randint (0, 9999)))
if __name__ =3D=3D '__main__':
main()
-------------- next part --------------
A non-text attachment was scrubbed...
Name: overlay.xrc
Type: text/xml
Size: 1322 bytes
Desc: not available
Url : http://lists.wxwidgets.org/pipermail/wxpython-users/attachments/20071=
202/bc8b8780/overlay.bin
More information about the wxpython-users
mailing list