Как бы вы разработали очень "Pythonic" UI Framework? - PullRequest
12 голосов
/ 12 сентября 2008

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

Shoes.app do
  t = para "Not clicked!"
  button "The Label" do
    alert "You clicked the button!" # when clicked, make an alert
    t.replace "Clicked!" # ..and replace the label's text
  end
end

Это заставило меня задуматься - как бы я спроектировал подобный удобный графический интерфейс в Python? Тот, у которого нет обычной связи с тем, что он в основном является обёрткой для библиотеки C * (в случае GTK, Tk, wx, QT и т. Д.)

Обувь берет вещи из веб-разработки (например, цветовая нотация в стиле * 1006, методы CSS-разметки, например :margin => 10) и из рубина (интенсивное использование блоков разумным образом)

Отсутствие в Python «рубиновых блоков» делает (метафорически) прямой порт невозможным:

def Shoeless(Shoes.app):
    self.t = para("Not clicked!")

    def on_click_func(self):
        alert("You clicked the button!")
        self.t.replace("clicked!")

    b = button("The label", click=self.on_click_func)

Нет, где почти так же чисто, и не будет почти столь же гибким, и я даже не уверен, будет ли это осуществимо.

Использование декораторов кажется интересным способом сопоставления блоков кода определенному действию:

class BaseControl:
    def __init__(self):
        self.func = None

    def clicked(self, func):
        self.func = func

    def __call__(self):
        if self.func is not None:
            self.func()

class Button(BaseControl):
    pass

class Label(BaseControl):
    pass

# The actual applications code (that the end-user would write)
class MyApp:
    ok = Button()
    la = Label()

    @ok.clicked
    def clickeryHappened():
        print "OK Clicked!"

if __name__ == '__main__':
    a = MyApp()
    a.ok() # trigger the clicked action

По сути, функция декоратора сохраняет функцию, затем, когда действие произошло (скажем, щелчок), соответствующая функция будет выполнена.

Область действия различных вещей (скажем, метка la в приведенном выше примере) может быть довольно сложной, но кажется, что она выполнима довольно аккуратно ...

Ответы [ 15 ]

1 голос
/ 03 декабря 2008

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

Это большая часть Django / SQLAlchemy, вдохновленная тем, что она в значительной степени основана на метапрограммировании и отделяет ваш код GUI от вашего «кода кода». Я также думаю, что он должен интенсивно использовать менеджеры компоновки, как это делает Java, потому что когда вы отбрасываете код, никто не хочет постоянно настраивать выравнивание пикселей. Я также думаю, что было бы здорово, если бы у нас были CSS-подобные свойства.

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

from happygui.controls import *

MAIN_WINDOW = Window(width="500px", height="350px",
    my_layout=ColumnLayout(padding="10px",
        my_label=Label(text="What's your name kiddo?", bold=True, align="center"),
        my_edit=EditBox(placeholder=""),
        my_btn=Button(text="CLICK ME!", on_click=Handler('module.file.btn_clicked')),
    ),
)
MAIN_WINDOW.show()

def btn_clicked(sender): # could easily be in a handlers.py file
    name = MAIN_WINDOW.my_layout.my_edit.text
    # same thing: name = sender.parent.my_edit.text
    # best practice, immune to structure change: MAIN_WINDOW.find('my_edit').text
    MessageBox("Your name is '%s'" % ()).show(modal=True)

Замечательно, что вы можете сослаться на ввод my_edit, сказав MAIN_WINDOW.my_layout.my_edit.text. Я думаю, что в объявлении для окна важно иметь возможность произвольно называть элементы управления в функции kwargs.

Это то же приложение, использующее только абсолютное позиционирование (элементы управления будут отображаться в разных местах, поскольку мы не используем модный менеджер компоновки):

from happygui.controls import *

MAIN_WINDOW = Window(width="500px", height="350px",
    my_label=Label(text="What's your name kiddo?", bold=True, align="center", x="10px", y="10px", width="300px", height="100px"),
    my_edit=EditBox(placeholder="", x="10px", y="110px", width="300px", height="100px"),
    my_btn=Button(text="CLICK ME!", on_click=Handler('module.file.btn_clicked'), x="10px", y="210px", width="300px", height="100px"),
)
MAIN_WINDOW.show()

def btn_clicked(sender): # could easily be in a handlers.py file
    name = MAIN_WINDOW.my_edit.text
    # same thing: name = sender.parent.my_edit.text
    # best practice, immune to structure change: MAIN_WINDOW.find('my_edit').text
    MessageBox("Your name is '%s'" % ()).show(modal=True)

Я пока не совсем уверен, действительно ли это отличный подход, но я определенно думаю, что он на правильном пути. У меня нет времени больше исследовать эту идею, но если бы кто-то занялся этим как проектом, я бы полюбил их.

1 голос
/ 03 декабря 2008

Лично я бы попытался реализовать JQuery как API в инфраструктуре GUI.

class MyWindow(Window):
    contents = (
        para('Hello World!'),
        button('Click Me', id='ok'),
        para('Epilog'),
    )

    def __init__(self):
        self['#ok'].click(self.message)
        self['para'].hover(self.blend_in, self.blend_out)

    def message(self):
        print 'You clicked!'

    def blend_in(self, object):
        object.background = '#333333'

    def blend_out(self, object):
        object.background = 'WindowBackground'
1 голос
/ 02 декабря 2008

Декларативный не обязательно более (или менее) питон, чем функциональный ИМХО. Я думаю, что многослойный подход был бы лучшим (с самого начала):

  1. Собственный уровень, который принимает и возвращает типы данных Python.
  2. Функциональный динамический слой.
  3. Один или несколько декларативных / объектно-ориентированных слоев.

Аналогично Эликсир + SQLAlchemy .

1 голос
/ 02 декабря 2008

Если вы действительно хотите кодировать пользовательский интерфейс, вы можете попытаться получить что-то похожее на ORM в django; Вот так вот, чтобы получить простой справочный браузер:

class MyWindow(Window):
    class VBox:
        entry = Entry()
        bigtext = TextView()

        def on_entry_accepted(text):
            bigtext.value = eval(text).__doc__

Идея заключалась бы в том, чтобы интерпретировать некоторые контейнеры (например, окна) как простые классы, некоторые контейнеры (например, таблицы, v / hboxes), распознаваемые по именам объектов, и простые виджеты как объекты.

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

О порядке элементов: в MyWindow выше вам не нужно отслеживать это (окно концептуально является контейнером с одним слотом). В других контейнерах вы можете попытаться отслеживать порядок, предполагая, что каждый конструктор виджета имеет доступ к некоторому глобальному списку виджетов. Вот как это делается в Django (AFAIK).

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

Однако я очень доволен PyGTK + Glade. Пользовательский интерфейс - это просто данные для меня, и его следует рассматривать как данные. Слишком много параметров для настройки (например, расстояние в разных местах), и лучше управлять этим с помощью инструмента с графическим интерфейсом. Поэтому я строю свой пользовательский интерфейс на поляне, сохраняю как xml и анализирую с помощью gtk.glade.XML ().

1 голос
/ 02 декабря 2008

У меня такая же проблема. Я хочу создать оболочку для любого GUI-инструментария для Python, которая проста в использовании и вдохновлена ​​Shoes, но требует подхода ООП (против блоков ruby).

Больше информации в: http://wiki.alcidesfonseca.com/blog/python-universal-gui-revisited

Любой желающий может присоединиться к проекту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...