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

WxPython: создание «темного режима»

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

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

Однажды на работе в прошлом месяце мне сказали, что у нас есть запрос на функцию для одной из моих программ. Они хотели «темный режим», когда они использовали свое приложение ночью, так как обычные цвета были видны в виду. Моя программа используется в ноутбуках в полицейских машинах, поэтому я мог понять их разочарование. Я провел некоторое время, глядя в дело и получил в основном рабочий скрипт, который я собираюсь поделиться с моими читателями. Конечно, если вы долгое время читатель, вы, вероятно, знаете, я говорю о программе WXPYPHON. Я пишу почти все мои интернет-интерфейсы, используя wxpython. Во всяком случае, давайте продолжим историю!

В темноту

Получение виджетов для изменения цвета в Wxpython довольно легко. Единственные два метода, которые вам нужны Setbackgroundolour . и Setforegroundleour Отказ Единственная основная проблема, в которой я столкнулся, когда я делал, это делала свой виджет listctrl/objectlistview, чтобы поменять цвета соответствующим образом. Вам нужно верить каждый список и изменить их цвета индивидуально. Я альтернативные цвета ряд, так что сделали вещи более интересными. Другая проблема, которую я имел восстановить цвет фона listctrl. Обычно вы можете установить цвет фона виджета в wx.nullcolour (или wx.nullcolor), и он вернется к его цвету по умолчанию. Тем не менее, некоторые виджеты не работают таким образом, и вы должны на самом деле указать цвет. Следует также отметить, что некоторые виджеты, похоже, не обращают внимания на SetBackground Colorour вообще. Один такой виджет, который я нашел, это WX.ToggleButton.

Теперь вы знаете, что я знаю, так что давайте посмотрим на код, который я придумал, чтобы решить мою проблему:

import wx
try:
    from ObjectListView import ObjectListView
except:
    ObjectListView = False

#----------------------------------------------------------------------
def getWidgets(parent):
    """
    Return a list of all the child widgets
    """
    items = [parent]
    for item in parent.GetChildren():
        items.append(item)
        if hasattr(item, "GetChildren"):
            for child in item.GetChildren():
                items.append(child)
    return items

#----------------------------------------------------------------------
def darkRowFormatter(listctrl, dark=False):
    """
    Toggles the rows in a ListCtrl or ObjectListView widget. 
    Based loosely on the following documentation:
    http://objectlistview.sourceforge.net/python/recipes.html#recipe-formatter
    and http://objectlistview.sourceforge.net/python/cellEditing.html
    """
    
    listItems = [listctrl.GetItem(i) for i in range(listctrl.GetItemCount())]
    for index, item in enumerate(listItems):
        if dark:
            if index % 2:
                item.SetBackgroundColour("Dark Grey")
            else:
                item.SetBackgroundColour("Light Grey")
        else:
            if index % 2:
                item.SetBackgroundColour("Light Blue")
            else:
                item.SetBackgroundColour("Yellow")
        listctrl.SetItem(item)

#----------------------------------------------------------------------
def darkMode(self, normalPanelColor):
    """
    Toggles dark mode
    """
    widgets = getWidgets(self)
    panel = widgets[0]
    if normalPanelColor == panel.GetBackgroundColour():
        dark_mode = True
    else:
        dark_mode = False
    for widget in widgets:
        if dark_mode:
            if isinstance(widget, ObjectListView) or isinstance(widget, wx.ListCtrl):
                darkRowFormatter(widget, dark=True)
            widget.SetBackgroundColour("Dark Grey")
            widget.SetForegroundColour("White")
        else:
            if isinstance(widget, ObjectListView) or isinstance(widget, wx.ListCtrl):
                darkRowFormatter(widget)
                widget.SetBackgroundColour("White")
                widget.SetForegroundColour("Black")
                continue
            widget.SetBackgroundColour(wx.NullColor)
            widget.SetForegroundColour("Black")
    self.Refresh()
    return dark_mode

Этот код немного запутанный, но это сделает работу. Давайте немного сломаемся и посмотрим, как это работает. Во-первых, мы пытаемся импортировать ObjectListView, прохладный трехчайный виджет, который оборачивает wx.listctrl и делает его намного проще в использовании. Тем не менее, это не часть WxPython прямо сейчас, поэтому вам нужно проверить на это существование. Я просто установил его на ложь, если оно не существует.

GetWidgets Функция принимает родительский параметр, который обычно был бы WX.Frame или WX.Panel и проходит через все его дети для создания списка виджетов, которые он затем возвращается в функцию вызова. Основная функция – DarkMode Отказ Требуется два параметра тоже плохо называемые «я», что относится к родительскому виджету и цвет панели по умолчанию. Он вызывает GetWidgets, а затем использует условный оператор для решения того, должен быть включен, если он должен включен или нет. Далее он циклирует через виджеты и меняет цвета соответственно. Когда это сделано, он будет обновлять пропущенные родителя и вернуть Bool, чтобы вы знали, если DEMP MODE включен или выключен.

Есть еще одна функция под названием DarkRowFormatter Это только для установки цветов listiTems в wx.listctrl или виджете объектаlistview. Здесь мы используем понимание списка для создания списка WX.LiStitems, которые мы повторяем, изменяя их цвета. Чтобы на самом деле применить изменение цвета, нам нужно вызововать setiTem и пропустить его экземпляр объекта wx.listitem.

Пробовать темный режим

Так что теперь вы, вероятно, задаетесь вопросом, как на самом деле использовать скрипт выше. Ну, этот раздел покажет вам, как это сделано. Вот простая программа со списком управлением в нем и кнопку Toggle!

import wx
import darkMode

########################################################################
class MyPanel(wx.Panel):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """Constructor"""
        wx.Panel.__init__(self, parent)
        self.defaultColor = self.GetBackgroundColour()
 
        rows = [("Ford", "Taurus", "1996", "Blue"),
                ("Nissan", "370Z", "2010", "Green"),
                ("Porche", "911", "2009", "Red")
                ]
        self.list_ctrl = wx.ListCtrl(self, style=wx.LC_REPORT)
 
        self.list_ctrl.InsertColumn(0, "Make")
        self.list_ctrl.InsertColumn(1, "Model")
        self.list_ctrl.InsertColumn(2, "Year")
        self.list_ctrl.InsertColumn(3, "Color")
 
        index = 0
        for row in rows:
            self.list_ctrl.InsertStringItem(index, row[0])
            self.list_ctrl.SetStringItem(index, 1, row[1])
            self.list_ctrl.SetStringItem(index, 2, row[2])
            self.list_ctrl.SetStringItem(index, 3, row[3])
            if index % 2:
                self.list_ctrl.SetItemBackgroundColour(index, "white")
            else:
                self.list_ctrl.SetItemBackgroundColour(index, "yellow")
            index += 1
            
        btn = wx.ToggleButton(self, label="Toggle Dark")
        btn.Bind(wx.EVT_TOGGLEBUTTON, self.onToggleDark)
        normalBtn = wx.Button(self, label="Test")
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.list_ctrl, 0, wx.ALL|wx.EXPAND, 5)
        sizer.Add(btn, 0, wx.ALL, 5)
        sizer.Add(normalBtn, 0, wx.ALL, 5)
        self.SetSizer(sizer)
        
    #----------------------------------------------------------------------
    def onToggleDark(self, event):
        """"""
        darkMode.darkMode(self, self.defaultColor)
 
########################################################################
class MyFrame(wx.Frame):
    """"""
 
    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, wx.ID_ANY,
                          "MvP ListCtrl Dark Mode Demo")
        panel = MyPanel(self)
        self.Show()
 
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

Если вы запускаете программу выше, вы должны увидеть что-то вроде этого:

Если вы нажмете ToggleButton, вы должны увидеть что-то вроде этого:

Обратите внимание, как кнопка Toggle не была затронута методом SetbackgroundBolour. Также обратите внимание, что заголовки столбцов управления списком также не меняют цвета. К сожалению, WXPYPHON не подвергается доступу к заголовкам столбцов, поэтому нет способа манипулировать своим цветом.

Во всяком случае, давайте найдя момент, чтобы увидеть, как используется код Dark Mode. Сначала нам нужно импортировать его. В этом случае модуль называется DarkMode Отказ На самом деле называть это, нам нужно посмотреть на обработчик событий ToggleButton:

darkMode.darkMode(self, self.defaultColor)

Как видите, все, что мы сделали, было позвонить DarkMode.darkMode с объектом панели («я) и по умолчанию, который мы устанавливаем в начале метода WX.Panel INIT. Это все, что мы должны были сделать. Мы, вероятно, Установите его с переменной, чтобы поймать возвращенное значение, но для этого примера мы не заботимся.

Обертывание

Теперь мы закончили, и вы тоже можете создать «темный режим» для ваших приложений. В какой-то момент я хотел бы обобрать это еще несколько, чтобы вписать в сценарий чейнджера цвета, где я могу пройти все, что я хочу этого. Что было бы действительно круто, это сделать его в микс. Но это что-то на будущее. Сейчас наслаждайтесь!

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

Исходный код

  • 2011-11-5-wxpython-dark-mode
  • Вы также можете потянуть источник из Битбукет