[wxPython-users] Grid Resize overrides layout?

Mike Driscoll mdriscoll at co.marshall.ia.us
Tue Sep 4 09:26:40 PDT 2007


 

> -----Original Message-----
> From: Robin Dunn [mailto:robin at alldunn.com] 
> Sent: Saturday, September 01, 2007 7:58 PM
> To: wxPython-users at lists.wxwidgets.org
> Subject: Re: [wxPython-users] Grid Resize overrides layout?
> 
> Mike Driscoll wrote:
> > Hi,
> > 
> > I have a grid control that I'm using for what amounts to a 
> spreadsheet.
> > Since some older folks will be using it, I thought I'd try 
> to add the 
> > ability to change the font size. Alas, I seem to be doing 
> something wrong.
> > Currently, my proof of concept code is below:
> > 
> > def onChangeFont(self, event):
> >         font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
> >         self.sheet.SetCellFont(0,0,font)       
> >         self.sheet.AutoSize()
> >         self.panel.Layout()
> > 
> > The AutoSize command works great, although I wish I it would only 
> > resize certain columns or rows rather than all of them.
> 
> There are AutoSizeRow and AutoSizeColumn methods.
>

AutoSizeColumn will work for my situation. Sorry I missed that.
 
> 
> > My problem though is that
> > after it "autosizes", some buttons I have below the grid widget are 
> > pushed "off" the edge of my panel and I have to resize the panel to 
> > see them again. As I understand it, all I need to do is 
> call Layout, 
> > but it doesn't work.
> > 
> > In this case, my app is derived from a Frame object, so 
> "self" is a frame.
> > I tried calling Layout in the following two ways:
> > 
> > self.Layout() and self.panel.Layout()
> 
> If you can produce a small sample we can help better.  It 
> should work as you say, but there could be something about 
> the window/sizer hierarchy that is short-circuiting the layout.
> 
> 
> --
> Robin Dunn
> Software Craftsman
> http://wxPython.org  Java give you jitters?  Relax with wxPython!
> 
> 
> 

I would still like to know why the Layout() command doesn't work though.
I've created a sample script that illustrates the problem. When you click
the button, it changes the font size in cell (0,0) to 12 point Swiss, bold
and then calls the AutoSize function and then the Layout function. This
will then cause the grid to change shape slightly and "push" the button
off the edge of the panel. If you resize the panel with your mouse, the
button reappears.

It should be noted that I am using a slightly modified version of the
SimpleGrid from the demo for my "spreadsheet". To reiterate, I am using
wxPython 2.8.4 and Python 2.4 on Windows XP SP2.

Thanks for any pointers!

Mike
-------------- next part --------------
import wx
import wx.grid as gridlib
from ts_grid import SimpleGrid

class Worksheet(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, title='Timesheet')
        
        self.panel = wx.Panel(self, -1)
        self.sheet = SimpleGrid(self.panel)
        self.fontChgBtn = wx.Button(self.panel, -1, 'Change Font Size', size=(100,-1))
        self.Bind(wx.EVT_BUTTON, self.onFontChange, self.fontChgBtn)

        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(self.sheet, 0, wx.EXPAND|wx.ALL, 5)
        mainSizer.Add(self.fontChgBtn, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5)

        self.panel.SetSizer(mainSizer)
        mainSizer.Fit(self)
        mainSizer.SetSizeHints(self)
            
        self.Show(True)

    def onFontChange(self, event):
        font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)
        self.sheet.SetCellFont(0,0,font)
        self.sheet.AutoSize()
        self.panel.Layout()

###### Run script! ######
if __name__ == '__main__':
    app = wx.PySimpleApp()
    Worksheet().Show()   # '4' is a test userid number only
    app.MainLoop()
-------------- next part --------------
import wx
import wx.grid as gridlib


class SimpleGrid(gridlib.Grid): 
    def __init__(self, parent):
        gridlib.Grid.__init__(self, parent, wx.ID_ANY)        
        self.moveTo = None

        self.Bind(wx.EVT_IDLE, self.OnIdle)

        # Create the sheet (y,x)
        self.CreateGrid(17, 12)#, gridlib.Grid.SelectRows)
        ##self.EnableEditing(False)

        # Name the column positions with variable names
        dateCol = 0
        dayCol = 1
        regCol = 2
        otCol = 3
        ceCol = 4
        holCol = 5
        sklvCol = 6
        vacCol = 7
        ctCol = 8
        convCol = 9
        miscCol = 10
        commCol = 11

        self.SetColLabelValue(dateCol, "DATE")
        self.SetColLabelValue(dayCol, "DAY")
        self.SetColLabelValue(regCol, "REG")
        self.SetColFormatFloat(regCol, 2, 2) 
        self.SetColLabelValue(otCol, "OT")
        self.SetColFormatFloat(otCol, 2, 2)   
        self.SetColLabelValue(ceCol, "CE")
        self.SetColFormatFloat(ceCol, 2, 2)
        self.SetColLabelValue(holCol, "HOL")
        self.SetColFormatFloat(holCol, 2, 2)
        self.SetColLabelValue(sklvCol, "SKLV")
        self.SetColFormatFloat(sklvCol, 2, 2)
        self.SetColLabelValue(vacCol, "VAC")
        self.SetColFormatFloat(vacCol, 2, 2)
        self.SetColLabelValue(ctCol, "CT")
        self.SetColFormatFloat(ctCol, 2, 2)
        self.SetColLabelValue(convCol, "CONV")
        self.SetColFormatFloat(convCol, 2, 2)
        self.SetColLabelValue(miscCol, "MISC")
        self.SetColFormatFloat(miscCol, 2, 2)
        self.SetColLabelValue(commCol, "COMMENTS")
        self.SetColFormatFloat(commCol, 2, 2)

        for i in range(1,11):
            self.SetColSize(i,50)
        
        self.SetColSize(11,200)

        self.SetReadOnly(0,0,True)
        self.SetReadOnly(0,1,True)
        self.SetReadOnly(7,0,True)
        self.SetReadOnly(15,0,True)
        self.SetReadOnly(16,0,True)

        ############################################################################3
        
        # Gray the total rows
        attr = gridlib.GridCellAttr()
        attr.SetTextColour(wx.BLACK)
        attr.SetBackgroundColour('Light Gray')
        self.SetRowAttr(7, attr)
        self.SetRowAttr(15, attr)
        self.SetRowAttr(16, attr)
        
        self.SetCellValue(7,dateCol,'Week 1 Total')
        self.SetCellSize(7,dateCol,1,2)
        self.SetCellAlignment(7,dateCol,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
        self.SetCellFont(7,dateCol,wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))

        self.SetCellValue(15,dateCol,'Week 2 Total')
        self.SetCellSize(15,dateCol,1,2)
        self.SetCellAlignment(15,dateCol,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
        self.SetCellFont(15,dateCol,wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))

        self.SetCellValue(16,dateCol,'Grand Total')
        self.SetCellSize(16,dateCol,1,2)
        self.SetCellAlignment(16,dateCol,wx.ALIGN_CENTRE,wx.ALIGN_CENTRE)
        self.SetCellFont(16,dateCol,wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD))

        # Set defaults for the Total rows
        totals = [7,15,16]
        for n in totals:
            x = 1
            for i in range(9):
                x = x+1            
                self.SetCellValue(n,x,'0.00')
                self.SetCellAlignment(n,x,wx.ALIGN_RIGHT, wx.ALIGN_RIGHT)

        # set all float number rows and columns to use floats and block text
        for rows in range(17):
            for cols in range(11):
                self.SetCellEditor(rows, cols, gridlib.GridCellFloatEditor())
                
        self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_BOTTOM)
    
        # test all the events
        self.Bind(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnCellLeftClick)
        self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnCellRightClick)
        self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnCellLeftDClick)
        self.Bind(gridlib.EVT_GRID_CELL_RIGHT_DCLICK, self.OnCellRightDClick)

        self.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK, self.OnLabelLeftClick)
        self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.OnLabelRightClick)
        self.Bind(gridlib.EVT_GRID_LABEL_LEFT_DCLICK, self.OnLabelLeftDClick)
        self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_DCLICK, self.OnLabelRightDClick)

        self.Bind(gridlib.EVT_GRID_ROW_SIZE, self.OnRowSize)
        self.Bind(gridlib.EVT_GRID_COL_SIZE, self.OnColSize)

        self.Bind(gridlib.EVT_GRID_RANGE_SELECT, self.OnRangeSelect)
        self.Bind(gridlib.EVT_GRID_CELL_CHANGE, self.OnCellChange)
        self.Bind(gridlib.EVT_GRID_SELECT_CELL, self.OnSelectCell)

        self.Bind(gridlib.EVT_GRID_EDITOR_SHOWN, self.OnEditorShown)
        self.Bind(gridlib.EVT_GRID_EDITOR_HIDDEN, self.OnEditorHidden)
        self.Bind(gridlib.EVT_GRID_EDITOR_CREATED, self.OnEditorCreated)


    def OnCellLeftClick(self, evt):        
        evt.Skip()

    def OnCellRightClick(self, evt):
        evt.Skip()

    def OnCellLeftDClick(self, evt):
        evt.Skip()

    def OnCellRightDClick(self, evt):
        evt.Skip()

    def OnLabelLeftClick(self, evt):
        evt.Skip()

    def OnLabelRightClick(self, evt):
        evt.Skip()

    def OnLabelLeftDClick(self, evt):
##        self.log.write("OnLabelLeftDClick: (%d,%d) %s\n" %
##                       (evt.GetRow(), evt.GetCol(), evt.GetPosition()))
        evt.Skip()

    def OnLabelRightDClick(self, evt):
        evt.Skip()

    def OnRowSize(self, evt):
        evt.Skip()

    def OnColSize(self, evt):
        evt.Skip()

    def OnRangeSelect(self, evt):
        evt.Skip()


    def OnCellChange(self, evt):
        '''          
        Show how to stay in a cell that has bad data.  We can't just
        call SetGridCursor here since we are nested inside one so it
        won't have any effect.  Instead, set coordinates to move to in
        idle time.
        '''
        #value = self.GetCellValue(evt.GetRow(), evt.GetCol())       
        colNum = evt.GetCol()  # Get column number to calculate which total to update

        self.totalColumns(colNum)

    def totalColumns(self, colNum):
        # Totals the columns in the grid
        
        if colNum != 11:
            # List of cells for the 1st week's pay
            tempLst = [self.GetCellValue(0,colNum), self.GetCellValue(1,colNum), self.GetCellValue(2,colNum),
                       self.GetCellValue(3,colNum), self.GetCellValue(4,colNum), self.GetCellValue(5,colNum),
                       self.GetCellValue(6,colNum)]
            
            # List of cells for the 2nd week's pay
            tempLst2 = [self.GetCellValue(8,colNum), self.GetCellValue(9,colNum), self.GetCellValue(10,colNum),
                        self.GetCellValue(11,colNum), self.GetCellValue(12,colNum), self.GetCellValue(13,colNum),
                        self.GetCellValue(14,colNum)]
            # Put both lists in another list
            colLists = [tempLst, tempLst2]
            
            totRow = [7, 15]   # Row numbers of the totals
            i = 0       # iterator / counter

            # Iterate over each list
            for eachCol in colLists:
                numLst = []
                total = 0
                for eachCell in eachCol:
                    if eachCell == '':     # If cell is empty, add zero
                        numLst.append(0)
                    else:                  # else, add whatever number is in the cell
                        numLst.append(eachCell)
                for eachNum in numLst:
                    total = total + float(eachNum)
                self.SetCellValue(totRow[i],colNum, str(total))
                i += 1

            # Total the 2 week's totals to get the "Grand Total"        
            gTotal = float(self.GetCellValue(7,colNum)) + float(self.GetCellValue(15,colNum))
            self.SetCellValue(16,colNum, str(gTotal))
            

    def OnIdle(self, evt):
        if self.moveTo != None:
            self.SetGridCursor(self.moveTo[0], self.moveTo[1])
            self.moveTo = None

        evt.Skip()


    def OnSelectCell(self, evt):
##        self.log.write("OnSelectCell: (%d,%d) %s\n" %
##                       (evt.GetRow(), evt.GetCol(), evt.GetPosition()))

        # Another way to stay in a cell that has a bad value...
        row = self.GetGridCursorRow()
        col = self.GetGridCursorCol()

        if self.IsCellEditControlEnabled():
            self.HideCellEditControl()
            self.DisableCellEditControl()

        value = self.GetCellValue(row, col)

        if value == 'no good 2':
            return  # cancels the cell selection

        evt.Skip()


    def OnEditorShown(self, evt):
##        if evt.GetRow() == 6 and evt.GetCol() == 3 and \
##           wx.MessageBox("Are you sure you wish to edit this cell?",
##                        "Checking", wx.YES_NO) == wx.NO:
##            evt.Veto()
##            return        
        evt.Skip()


    def OnEditorHidden(self, evt):
##        if evt.GetRow() == 6 and evt.GetCol() == 3 and \
##           wx.MessageBox("Are you sure you wish to  finish editing this cell?",
##                        "Checking", wx.YES_NO) == wx.NO:
##            evt.Veto()
##            return       
        evt.Skip()


    def OnEditorCreated(self, evt):
        pass

    


More information about the wxpython-users mailing list