Рубрики
Без рубрики

WXPYPHON: Введение в сетки

Получите практические, реальные навыки Python на наших ресурсах и пути

Автор оригинала: Mike Driscoll.

Виджет сетки в WXPYPHON является одним из самых сложных элементов GUI, с которыми вы будете работать в этом инструменте. В этой статье вы узнаете основы создания и использования сетки. Одним из основных использований для сетки является отображение табличных данных. Другое использование – создать какую-то электронную таблицу. Если вам нужно что-то, где вам нужно много ячеек, которые можно легко редактировать, то виджет сетки, вероятно, вы хотите. Режим «ListCtrl в режиме отчета» аналогичен появлению сетки и может использоваться в качестве замены для сетки в зависимости от ваших потребностей.

Создание простой сетки

Давайте посмотрим, как на самом деле создать сетку:

import wx
import wx.grid as gridlib

########################################################################
class MyForm(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="A Simple Grid")
        panel = wx.Panel(self)
        
        myGrid = gridlib.Grid(panel)
        myGrid.CreateGrid(12, 8)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(myGrid, 1, wx.EXPAND)
        panel.SetSizer(sizer)
        
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

Это один из самых простых способов создания виджета сетки. Все, что мы здесь сделали, было создать объект сетки, а затем вызовите его метод CreateGrid, чтобы сказать ему, сколько рядов и столбцов мы хотели. Мы помещаем его в Sizer в основном, потому что это просто правильный способ содержать виджеты и облегчает добавление дополнительных виджетов. Теперь у вас должна быть функциональная сетка!

Представляем некоторые методы сетки

Есть проблема с предыдущим примером: эта сетка на самом деле не делает ничего полезного! Нам нужен способ поставить данные в сетку и получать данные. Давайте узнаем, как это сделать и намного больше.

import wx
import wx.grid as gridlib

########################################################################
class MyForm(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="Grid Tutorial Two", size=(650,320))
        panel = wx.Panel(self)
        
        myGrid = gridlib.Grid(panel)
        myGrid.CreateGrid(15, 6)
        
        myGrid.SetCellValue(0,0, "Hello")
        myGrid.SetCellFont(0, 0, wx.Font(12, wx.ROMAN, wx.ITALIC, wx.NORMAL))
        print myGrid.GetCellValue(0,0)
        
        myGrid.SetCellValue(1,1, "I'm in red!")
        myGrid.SetCellTextColour(1, 1, wx.RED)
        
        myGrid.SetCellBackgroundColour(2, 2, wx.CYAN)
        
        myGrid.SetCellValue(3, 3, "This cell is read-only")
        myGrid.SetReadOnly(3, 3, True)
        
        myGrid.SetCellEditor(5, 0, gridlib.GridCellNumberEditor(1,1000))
        myGrid.SetCellValue(5, 0, "123")
        myGrid.SetCellEditor(6, 0, gridlib.GridCellFloatEditor())
        myGrid.SetCellValue(6, 0, "123.34")
        myGrid.SetCellEditor(7, 0, gridlib.GridCellNumberEditor())

        myGrid.SetCellSize(11, 1, 3, 3)
        myGrid.SetCellAlignment(11, 1, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
        myGrid.SetCellValue(11, 1, "This cell is set to span 3 rows and 3 columns")
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(myGrid)
        panel.SetSizer(sizer)

if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm()
    frame.Show()
    app.MainLoop()    

Выше код выше начнется так же, как код в первом примере. Тем не менее, вы быстро увидите, что здесь у нас есть много специфических методов сетки, которые мы используем для установки различных атрибутов виджета сетки. Например, мы используем Setcellvalue (0,0, “привет”) Чтобы установить значение верхней правой клетки в строку «Привет». Далее мы устанавливаем размер шрифта и стиль для этой же клетки, вызывая следующее:

Setcellfont (0, 0, wx.font (12, wx.roman, wx.clianic, wx.nommal)))

Вы можете создавать объекты WX.FONT, которые также используют шрифты на вашей системе. Чтобы установить цвет шрифта, мы используем SetCellTextColour и установить цвет фона ячейки, который мы используем SetCellbackgroundBolour. Как видите, методы сетки довольно просты и имеют интуитивные имена. Конечно, если вы американские, то вы заметите, что именование имеет тенденцию быть британской орфографией (то есть цвет вместо цвета), поэтому вам нужно остерегаться для этого.

Если вам нужно сделать только для чтения ячейки, вы можете сделать следующее: SETREADONLY (ROW, COL). Если вам нужно сделать всю сетку только для чтения, затем используйте включение (false). Наконец, если вам нужно установить все строки или столбцы только для чтения, то вы захотите использовать функцию атрибута ячейки. Что-то вроде этого должно начать:

Getcellattr (row, col) .setreadonly (isreadonly)

Затем используйте SetroWattr () и SetColattr (), чтобы установить соответствующую строку или столбец только для чтения. Я получил эту информацию от удивительной книги Робина Данна: WXPYPHON в действии. Обязательно примите к сведению SetCellAlignment, который установит выравнивание содержания клетки.

Обновление (2013-09-12): Я пытался выяснить, как на самом деле использовать вышеуказанную информацию, чтобы сделать весь ряд или столбец только для чтения, но я не думаю, что это работает, или она больше не работает. Вместо этого вы должны сделать что-то вроде этого:

attr = gridlib.GridCellAttr()
attr.SetReadOnly(True)
myGrid.SetRowAttr(0, attr)

Этот код сделает первый ряд (то есть ряд ряд) только для чтения.

Последний раздел важности в этом примере заключается в том, как настроить пользовательские редакторы клеток. Это довольно просто, чтобы все, что вам нужно сделать, это позвонить SetCelleditor и пройти в (строк, COL) кортеж вместе с вашим редактором выбора. В нашем примере мы используем GridCellnumbereDitor, GridCellfoatitor и GridCellnumberEditor. Увидеть Официальная документация для других вариантов.

События сетки

Для нашего последнего примера в нашем туре с решеткой Whirlwind мы посмотрим на специальные мероприятия сетки. Вот какой-то код, чтобы начать нас:

# gridEvents.py

import wx
import wx.grid as gridlib

########################################################################
class MyGrid(gridlib.Grid):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        gridlib.Grid.__init__(self, parent)
        self.CreateGrid(12, 8)
    
    
        # 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):
        print "OnCellLeftClick: (%d,%d) %s\n" % (evt.GetRow(),
                                                 evt.GetCol(),
                                                 evt.GetPosition())
        evt.Skip()

    def OnCellRightClick(self, evt):
        print "OnCellRightClick: (%d,%d) %s\n" % (evt.GetRow(),
                                                  evt.GetCol(),
                                                  evt.GetPosition())
        evt.Skip()

    def OnCellLeftDClick(self, evt):
        print "OnCellLeftDClick: (%d,%d) %s\n" % (evt.GetRow(),
                                                  evt.GetCol(),
                                                  evt.GetPosition())
        evt.Skip()

    def OnCellRightDClick(self, evt):
        print "OnCellRightDClick: (%d,%d) %s\n" % (evt.GetRow(),
                                                   evt.GetCol(),
                                                   evt.GetPosition())
        evt.Skip()

    def OnLabelLeftClick(self, evt):
        print "OnLabelLeftClick: (%d,%d) %s\n" % (evt.GetRow(),
                                                  evt.GetCol(),
                                                  evt.GetPosition())
        evt.Skip()

    def OnLabelRightClick(self, evt):
        print "OnLabelRightClick: (%d,%d) %s\n" % (evt.GetRow(),
                                                   evt.GetCol(),
                                                   evt.GetPosition())
        evt.Skip()

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

    def OnLabelRightDClick(self, evt):
        print "OnLabelRightDClick: (%d,%d) %s\n" % (evt.GetRow(),
                                                    evt.GetCol(),
                                                    evt.GetPosition())
        evt.Skip()

    def OnRowSize(self, evt):
        print "OnRowSize: row %d, %s\n" % (evt.GetRowOrCol(),
                                           evt.GetPosition())
        evt.Skip()

    def OnColSize(self, evt):
        print "OnColSize: col %d, %s\n" % (evt.GetRowOrCol(),
                                           evt.GetPosition())
        evt.Skip()

    def OnRangeSelect(self, evt):
        if evt.Selecting():
            msg = 'Selected'
        else:
            msg = 'Deselected'
        print "OnRangeSelect: %s  top-left %s, bottom-right %s\n" % (msg, evt.GetTopLeftCoords(),
                                                                     evt.GetBottomRightCoords())
        evt.Skip()


    def OnCellChange(self, evt):
        print "OnCellChange: (%d,%d) %s\n" % (evt.GetRow(), evt.GetCol(), evt.GetPosition())

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

        if value == 'no good':
            self.moveTo = evt.GetRow(), evt.GetCol()
            
    def OnSelectCell(self, evt):
        if evt.Selecting():
            msg = 'Selected'
        else:
            msg = 'Deselected'
        print "OnSelectCell: %s (%d,%d) %s\n" % (msg, 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

        print "OnEditorShown: (%d,%d) %s\n" % (evt.GetRow(), evt.GetCol(),
                                               evt.GetPosition())
        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

        print "OnEditorHidden: (%d,%d) %s\n" % (evt.GetRow(),
                                                evt.GetCol(),
                                                evt.GetPosition())
        evt.Skip()


    def OnEditorCreated(self, evt):
        print "OnEditorCreated: (%d, %d) %s\n" % (evt.GetRow(),
                                                  evt.GetCol(),
                                                  evt.GetControl())

########################################################################
class MyForm(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="An Eventful Grid")
        panel = wx.Panel(self)
        
        myGrid = MyGrid(panel)
                
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(myGrid, 1, wx.EXPAND)
        panel.SetSizer(sizer)
        
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

Это много кода, но в основном это просто обработчики событий. Мы отправим только пару из них. Ты умный, так что я уверен, что вы сможете выяснить остальные! Обратите внимание, что все события в этом образце предложены с помощью «Gridlib». Это означает, что эти события относятся только к экземплярам сетки и не будут влиять на любой другой виджет. Для нашего первого примера события мы посмотрим на EVT_GRID_CELL_LEFT_CLICK. Когда вы связываете с этим событием, он позволяет заразить событие, которое уволено, когда пользователь покинул указатель мыши на ячейке в вашей сетке. Насколько я могу сказать, это событие уволено перед событием SELECT (I.E. EVT_GRID_SELECT_CELL), чтобы вы могли использовать его для VETO, если вы хотите. Обратите внимание, что имеется правый щелчок и соответствующий двойной щелчке событий для обеих кнопок мыши.

Событие EVT_GRID_LABEL_LEFT_CLICK позволяет нам знать, когда пользователь нажимает на столбце сетки или меткой строки. Как и в случае предыдущего примера события, вы также можете поймать двойной щелчок и щелкнуть правой кнопкой мыши. Обратите внимание, что не в среднем кликере нет события. Вам, вероятно, понадобится использовать обычные события для мыши Mideblicle для этого.

EVT_GRID_EDITITITOR_SHOWN уволен при запуске редактирования ячейки. Вы можете использовать это событие для создания пользовательского редактора для отображения или вето редактирование. Посмотрите, можете ли вы понять, какие другие события делают самостоятельно.

Теперь давайте посмотрим на некоторые из обработчиков. Многие из них имеют следующий код:

(evt.GetRow(),
 evt.GetCol(),
 evt.GetPosition())

Это может быть довольно удобно для устранения неполадок, поскольку оно говорит нам, если мы в клетке мы ожидаем, что он будет в и он также дает нам координаты пикселей, где мы нажали. Последнее может быть удобно для контекстных всплывающих меню или позиционирования подсказки. Другой интересный обработчик Onrangeslect Что показывает нам, как сказать, что наш выбранный диапазон. Обратите внимание, что все, что нам нужно было сделать, было звонить Gettopleftcoords и GetBottomRightcoords, чтобы понять это. Разве это не так весело?

Теперь вы знаете основы для обработки событий сетки. Выйдите туда и постройте несколько классных приложений с вашими новыми знаниями! Держите глаза очищенными в следующей паре сетки для сетки, где вы узнаете, как использовать виртуальные таблицы, изменять ярлыки сетки и строки, добавить подсказки в столбцы и другие забавные вещи!

Примечание. Код в этом посте был протестирован следующим:

  • Windows XP Professional, WxPython 2.8.10.1 (Unicode), Python 2.5
  • Windows 7 Professional, WxPython 2.8.10.1 (Unicode), Python 2.6.4

Дальнейшее чтение