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

WXPYPHON: Советы сетки и трюки

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

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

В прошлом месяце я упомянул, что мы отправимся в путешествие, чтобы узнать несколько советов и трюков для виджета сетки WXPYPHON. Ну, кодирование сделано, и я думал, что пришло время на самом деле делать это. В следующей статье вы узнаете, как:

  • Создайте щелчок правой кнопкой мыши всплывающее меню в ячейке
  • Как получить COL/ROW на щелчок правой кнопкой мыши
  • Поместите всплывающие подсказки на этикетки ряд и колонны и на клетки
  • Как использовать клавиши со стрелками клавиатуры, чтобы выйти из клетки, которая редактируется
  • Скрыть строки/колонны этикетки/заголовки
  • Покажите всплывающее окно при нажатии на этикетку строки
  • Изменить строку/столбец этикетки

Ну, что же вы ждете? Нажмите на ссылку «Больше» и начните чтение!

Как создать всплывающее меню в ячейке сетки

Это супер легкий трюк для достижения. Давайте посмотрим на какой-нибудь код, чтобы вы могли видеть, насколько это просто!

import wx
import wx.grid as  gridlib

class MyForm(wx.Frame):
 
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, 
                          "Grid with Popup Menu")
 
        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        self.grid = gridlib.Grid(panel)
        self.grid.CreateGrid(25,8)
        self.grid.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK,
                       self.showPopupMenu)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid, 1, wx.EXPAND, 5)
        panel.SetSizer(sizer)
        
    #----------------------------------------------------------------------
    def showPopupMenu(self, event):
        """
        Create and display a popup menu on right-click event
        """
        if not hasattr(self, "popupID1"):
            self.popupID1 = wx.NewId()
            self.popupID2 = wx.NewId()
            self.popupID3 = wx.NewId()
            # make a menu
        
        menu = wx.Menu()
        # Show how to put an icon in the menu
        item = wx.MenuItem(menu, self.popupID1,"One")
        menu.AppendItem(item)
        menu.Append(self.popupID2, "Two")
        menu.Append(self.popupID3, "Three")
        
        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(menu)
        menu.Destroy()

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

Здесь есть только две вещи, которые мы действительно заботимся о: связывание событий и обработчик событий. Привязка проста: gridlib.evt_grid_cell_right_click. Обратите внимание, что вам нужно использовать событие сетки, а не General EVT_Right_Click. Обработчик событий исходит от демонстрации WXPYPHON. В нем вы просто построите меню на лету, а затем отображаете его, позвонив по попуткам. Меню будет уничтожено, когда вы нажимаете за пределы меню, или когда вы делаете выбор, и указанный метод выбора вызова (S) завершен.

Как получить COL/ROW на щелчок правой кнопкой мыши

Иногда вы хотите знать, какую ячейку вы точно щелкнули специально. Почему? Ну, если вы хотите выполнить контекстное меню, то вам нужно знать, на какой ячейке вы нажали. Код выше на самом деле не говорит вам об этом. Это просто создает небольшое всплывающее меню. Таким образом, вы можете использовать следующий фрагмент и комбинировать его с предыдущим, чтобы создать контекстное меню.

import wx
import wx.grid as gridlib
 
########################################################################
class MyForm(wx.Frame):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, parent=None, title="Getting the Row/Col")
        panel = wx.Panel(self)
 
        myGrid = gridlib.Grid(panel)
        myGrid.CreateGrid(12, 8)
        self.myGrid = myGrid
        self.myGrid.GetGridWindow().Bind(wx.EVT_RIGHT_DOWN, self.onRightClick)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(myGrid, 1, wx.EXPAND)
        panel.SetSizer(sizer)
        
    #----------------------------------------------------------------------
    def onRightClick(self, event):
        """"""
        x, y = self.myGrid.CalcUnscrolledPosition(event.GetX(),
                                                  event.GetY())
        row, col = self.myGrid.XYToCell(x, y)
        print row, col
        
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyForm().Show()
    app.MainLoop()

Вы, вероятно, задаетесь вопросом, почему мы обязательно связываемся с универсальным wx.evt_right_down вместо grid’s evt_grid_cell_right_click. Причина состоит в том, что правильный клик с решетками сетки не дает нам координаты X/Y. Нам нужны те координаты, чтобы перейти к сетке CalcunscrolledPosition метод. Это, в свою очередь, даст нам положение X/Y относительно сетки, чтобы перейти к другому методу сетки, а именно Xytocell который вернет строку и Col, нажав, на щелчке. Это даст нам информацию, которую нам нужно, если бы мы хотим создать контекстное меню на основе определенной ячейки.

Обновление: Некоторые могут сделать это тяжело, и они могут быть правы. Почему? Поскольку, в то время как объект события, который отправляется EVT_GRID_CELL_Right_Click, не имеет методов GetX/Gety, у него есть методы Getrow и GetCol. Таким образом, вы могли бы использовать его в конце концов. Если вы хотите перевести из произвольной точки пикселей, вышеуказанный метод – это путь. Если вы хотите быть уборщиком TAD, вы можете захотеть привязать к EVT_GRID_CELL_Right_Click вместо.

Сетки и подсказки

Набор подборок в сетках может быть несколько сложно выяснить. Я провел много времени на этом, прежде чем, наконец, просит помощь в списке WXPYPHON. Я хотел узнать, как надевать подсказки в определенную колонку и сделать их изменениями, когда я перешел на различные клетки. Первый метод предложил отлично сработать, пока мне не пришлось прокрутить сетку. К счастью, Робин Данн (Создатель WXPYPHON) имел ответ на этот вопрос тоже. Следующий код также покажет, как поставить подсказки на столбцах и наклеек строки.

import wx
import wx.grid as  gridlib

class MyForm(wx.Frame):
 
    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Grid Tooltips")
 
        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        
        self.grid = gridlib.Grid(panel)
        self.grid.CreateGrid(25,8)
        
        # put a tooltip on the cells in a column
        self.grid.GetGridWindow().Bind(wx.EVT_MOTION, self.onMouseOver)
        # the following is equivalent to the above mouse binding
##        for child in self.grid.GetChildren():
##             if child.GetName() == 'grid window':
##                 child.Bind(wx.EVT_MOTION, self.onMouseOver)
        
        # put a tooltip on a column label
        self.grid.GetGridColLabelWindow().Bind(wx.EVT_MOTION, 
                                               self.onMouseOverColLabel)
        # put a tooltip on a row label
        self.grid.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, 
                                               self.onMouseOverRowLabel)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid, 1, wx.EXPAND, 5)
        panel.SetSizer(sizer)
        
    #----------------------------------------------------------------------
    def onMouseOver(self, event):
        """
        Displays a tooltip over any cell in a certain column
        """
        # Use CalcUnscrolledPosition() to get the mouse position within the 
        # entire grid including what's offscreen
        # This method was suggested by none other than Robin Dunn
        x, y = self.grid.CalcUnscrolledPosition(event.GetX(),event.GetY())
        coords = self.grid.XYToCell(x, y)
        col = coords[1]
        row = coords[0]
        
        # Note: This only sets the tooltip for the cells in the column
        if col == 1:
            msg = "This is Row %s, Column %s!" % (row, col)
            event.GetEventObject().SetToolTipString(msg)
        else:
            event.GetEventObject().SetToolTipString('')
            
    #----------------------------------------------------------------------
    def onMouseOverColLabel(self, event):
        """
        Displays a tooltip when mousing over certain column labels
        """
        x = event.GetX()
        y = event.GetY()
        col = self.grid.XToCol(x, y)
        
        if col == 0:
            self.grid.GetGridColLabelWindow().SetToolTipString('Column One')
        elif col == 1:
            self.grid.GetGridColLabelWindow().SetToolTipString('Column Two')
        else:
            self.grid.GetGridColLabelWindow().SetToolTipString('')
        event.Skip()
        
    #----------------------------------------------------------------------
    def onMouseOverRowLabel(self, event):
        """
        Displays a tooltip on a row label
        """
        x = event.GetX()
        y = event.GetY()
        row = self.grid.YToRow(y)
        print row
        if row == 0:
            self.grid.GetGridRowLabelWindow().SetToolTipString("Row One")
        elif row == 1:
            self.grid.GetGridRowLabelWindow().SetToolTipString('Row Two')
        else:
            self.grid.GetGridRowLabelWindow().SetToolTipString("")
        event.Skip()
        
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

Мой первоначальный корпус использования для подборочных подборок на клетки определенного столбца заключался в том, что у меня были некоторые пользователи, которые хотели, чтобы данные, которые я отображал, преобразован на 10%, чтобы отразить другой способ расчета то же самое. У меня были больше пользователей, которые хотели, чтобы он остался один. Поэтому я скомпрометировал, сделав подсказки, которые могут выполнить расчет содержимого ячейки и отобразить другое спорное значение в подсказке. Раздражает, но потенциально удобно в будущем. Первый шаг в достижении этого влияния должен был выяснить правильное связывание. Вот:

self.grid.GetGridWindow().Bind(wx.EVT_MOTION, self.onMouseOver)

Обработчик событий заботится о следующей части уравнения через трехэтапный процесс. Давайте посмотрим смотреть:

def onMouseOver(self, event):
    """
    Displays a tooltip over any cell in a certain column
    """
    # Use CalcUnscrolledPosition() to get the mouse position within the 
    # entire grid including what's offscreen
    # This method was suggested by none other than Robin Dunn
    x, y = self.grid.CalcUnscrolledPosition(event.GetX(),event.GetY())
    coords = self.grid.XYToCell(x, y)
    col = coords[1]
    row = coords[0]
    
    # Note: This only sets the tooltip for the cells in the column
    if col == 1:
        msg = "This is Row %s, Column %s!" % (row, col)
        event.GetEventObject().SetToolTipString(msg)
    else:
        event.GetEventObject().SetToolTipString('')

Первый шаг влечет за собой получение строки клетки и координаты столбцов, используя CalcunscrolledPosition (Event.getx (), Event.gety ()) /Это вернет координаты X/Y, которые мы можем использовать Xytocell получить доступ к фактической строке/Col. Третий шаг будет захватить содержимое клетки, используя Getcellvalue , но так как мне не волнует в этом примере, я просто установил всплывающую подсказку, используя это: event.geteventobject (). Settortortipstring (MSG) Отказ Я думал, что это довольно аккуратно. Также обратите внимание на альтернативный метод для оригинального связывания события, которое я прокомментировал. Это был уродливый взлом, но он работал так долго, как у меня не было прокрутки (я думаю).

Следующие, связанные с подсказками, связанные с подсказками, связаны с тем, что они оба имеют дело с подборочными подсказками на этикетки; В частности, вы узнаете, как поставить подсказки на этикетки подряд и столбцов. Привязка и обработчики по существу одинаковы, вам просто нужно указать вызовы методов ряд или столбцов. Например, привязка столбца является GetGridCollabelwindow и связывание ряда это Getgridrowlabelwindow Отказ Следующим шагом является получение столбца или строки, которую вы меняете, поэтому мы используем XTocol для колонны и Итороу для ряда. Наконец, мы звоним на GetGridCollabelwindow (). Settolortipstring Чтобы установить всплывающую подсказку столбца. Ряд почти точно такой же.

Использование клавиш со стрелками для навигации из редактирования ячейки

В Microsoft Excel вы можете использовать клавиши со стрелками клавиатуры, чтобы остановить редактирование и многое другое в другую клетку, а не нажав вкладку или клавишу ввода. Поскольку большинство пользователей используются для этой функциональности, мы, вероятно, должны иметь его в наших приложениях. Вот один из способов сделать это:

import wx
import wx.grid as  gridlib

class MyForm(wx.Frame):
    
    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Navigating out of a cell")
 
        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        self.grid = gridlib.Grid(panel)
        self.grid.CreateGrid(25,8)
        
        self.grid.Bind(gridlib.EVT_GRID_EDITOR_CREATED, self.onCellEdit)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid, 1, wx.EXPAND, 5)
        panel.SetSizer(sizer)
        
    #----------------------------------------------------------------------
    def onCellEdit(self, event):
        '''
        When cell is edited, get a handle on the editor widget
        and bind it to EVT_KEY_DOWN
        '''        
        editor = event.GetControl()        
        editor.Bind(wx.EVT_KEY_DOWN, self.onEditorKey)
        event.Skip()
    
    #----------------------------------------------------------------------
    def onEditorKey(self, event):
        '''
        Handler for the wx.grid's cell editor widget's keystrokes. Checks for specific
        keystrokes, such as arrow up or arrow down, and responds accordingly. Allows
        all other key strokes to pass through the handler.
        '''
        keycode = event.GetKeyCode() 
        if keycode == wx.WXK_UP:
            print 'you pressed the UP key!'
            self.grid.MoveCursorUp(False)
        elif keycode == wx.WXK_DOWN:
            print 'you pressed the down key!'
            self.grid.MoveCursorDown(False)
        elif keycode == wx.WXK_LEFT:
            print 'you pressed the left key!'
            self.grid.MoveCursorLeft(False)
        elif keycode == wx.WXK_RIGHT:
            print 'you pressed the right key'
            self.grid.MoveCursorRight(False)
        else:
            pass
        event.Skip()
        
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

Ловля ключевых событий в камере сетки немного сложно. Сначала нужно связать ручку к событию EVT_GRID_EDITITOR_CREATED: self.grid.bind (gridlib.evt_grid_editor_created, self.oncelledit). Затем в обработчике вам нужно получить ручку в редакторе клеток, который создается при запуске редактирования ячейки. Для этого вам нужно использовать Event.getControl () Отказ Как только у вас есть эта ручка, вы можете связать wx.evt_key_down к нему и ловить ключевые события. В указанном выше коде мы связываем это событие для OneDitorkey В котором мы проверяем, нажал ли пользователь на одну из клавиш со стрелками. Если пользователь нажимал один из них, мы используем Movecursorxx Способ перемещения выбранной ячейки в указанном направлении. Если пользователь не нажимал клавишу со стрелкой, мы ничего не делаем. Обратите внимание, что нам нужно позвонить Event.skip () несмотря на. Причина в том, что мы хотим, чтобы ключи продолжали обрабатываться. Если вы не звоните Skip (), то большая часть вашей печати ничего не сделает.

Как скрыть наклейки ряд и колонны

Скрытый ряд или столбец метки чрезвычайно просты. На самом деле, эта информация поставляется в WXPYPHON FAQ Отказ Пол Макнетт, один из создателей DABO, внес эту информацию в Вики. Ниже приведен то, что имеет Wiki:

grid.SetRowLabelSize(0)
grid.SetColLabelSize(0)

Я решил создать пример приложения, которое показало пример в контексте:

import wx
import wx.grid as  gridlib

class MyForm(wx.Frame):
 
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Changing Row/Col Labels")
 
        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        grid = gridlib.Grid(panel)
        grid.CreateGrid(25,8)
        
        # http://bit.ly/aXbeNF - link to FAQ
        grid.SetRowLabelSize(0) # hide the rows
        grid.SetColLabelSize(0) # hide the columns
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 1, wx.EXPAND, 5)
        panel.SetSizer(sizer)

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

Отображайте что-нибудь (диалоговое окно/кадр/что угодно) Когда пользователь нажимает на метку строки

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

import wx
import wx.grid as  gridlib

class MyForm(wx.Frame):
    
    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY,
                          "Show Dialog on Row Label Click")
 
        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        self.grid = gridlib.Grid(panel)
        self.grid.CreateGrid(25,8)
        
        self.grid.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK, self.onRowClick)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.grid, 1, wx.EXPAND, 5)
        panel.SetSizer(sizer)
        
    #----------------------------------------------------------------------
    def onRowClick(self, event):
        """
        Displays a message dialog to the user which displays which row
        label the user clicked on
        """
        # Note that rows are zero-based
        row = event.GetRow()
        dlg = wx.MessageDialog(None, "You clicked on Row Label %s" % row,
                               "Notice",
                               wx.OK|wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()
        
# Run the program
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()

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

Как изменить метки столбца/строки

Изменение строки сетки или метки колонны очень просты; Но не берите мое слово для этого. Посмотрите на код вместо этого!

import wx
import wx.grid as  gridlib

class MyForm(wx.Frame):
 
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Hiding Rows and Columns")
 
        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        grid = gridlib.Grid(panel)
        grid.CreateGrid(25,8)
        
        # change a couple column labels
        grid.SetColLabelValue(0, "Name")
        grid.SetColLabelValue(1, "Phone")
        
        # change the row labels
        for row in range(25):
            rowNum = row + 1
            grid.SetRowLabelValue(row, "Row %s" % rowNum)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(grid, 1, wx.EXPAND, 5)
        panel.SetSizer(sizer)

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

Как вы можете видеть, все, что вам нужно сделать, чтобы изменить метку столбца, называется Setcollabelvalue Отказ Сетка также имеет аналогичный метод для ряда: Setrowlubelvalue Отказ Просто пройдите, в какой строке вы хотите изменить, и строка, которую вы хотите, чтобы отобразить, и вы должны быть установлены.

Обертывание

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

Загрузки

  • tips_and_tricks.zip
  • tips_and_tricks.tar.

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