美文网首页
059-python库pyglet(四)

059-python库pyglet(四)

作者: AncientMing | 来源:发表于2019-04-17 12:00 被阅读0次

    一、The application event loop(应用程序事件循环)

    In order to let pyglet process operating system events such as mouse and keyboard events, applications need to enter an application event loop. The event loop continuously checks for new events, dispatches those events, and updates the contents of all open windows.

    为了让pyglet过程操作系统事件如鼠标和键盘事件,应用程序需要输入应用程序事件循环。事件循环不断检查新的事件,这些事件分派,并更新所有打开的窗口的内容。

    pyglet provides an application event loop that is tuned for performance and low power usage on Windows, Linux and Mac OS X. Most applications need only call:

    pyglet提供应用程序事件循环,调优性能和低功率使用在Windows、Linux和Mac OS x大多数应用程序只需要调用:

    pyglet.app.run()
    

    to enter the event loop after creating their initial set of windows and attaching event handlers. The run() function does not return until all open windows have been closed, or until pyglet.app.exit() is called.

    进入事件循环在创建的初始窗口和附加事件处理程序。run()函数不返回,直到所有打开的窗口已经关闭,或者直到pyglet.app.exit ()。

    The pyglet application event loop dispatches window events (such as for mouse and keyboard input) as they occur and dispatches the on_draw() event to each window after every iteration through the loop.

    pyglet应用程序事件循环调度窗口事件(比如鼠标和键盘输入)发生时,分派on_draw()事件后每个窗口每次迭代循环。

    To have additional code run periodically or every iteration through the loop, schedule functions on the clock (see Calling functions periodically). pyglet ensures that the loop iterates only as often as necessary to fulfill all scheduled functions and user input.

    额外的代码定期运行或通过循环的每次迭代中,调度函数时钟(见定期调用函数)。pyglet确保循环迭代只是经常需要满足所有预定的功能和用户的输入。

    Customising the event loop(定制的事件循环)

    The pyglet event loop is encapsulated in the EventLoop class, which provides several hooks that can be overridden for customising its behaviour. This is recommended only for advanced users – typical applications and games are unlikely to require this functionality.

    pyglet事件循环是封装在EventLoop类,它提供了几个钩子可以覆盖定制自己的行为。这是建议仅供高级用户,典型的应用程序和游戏不太可能需要此功能。

    To use the EventLoop class directly, instantiate it and call <cite>run</cite>:

    直接使用EventLoop类,实例化并调用运行:

    event_loop = pyglet.app.EventLoop()
    event_loop.run()
    

    Only one EventLoop can be running at a time; when the run() method is called the module variable pyglet.app.event_loopis set to the running instance. Other pyglet modules such as pyglet.window depend on this.

    只有一个EventLoop可以运行一次;在run()方法被调用模块变量pyglet.app。event_loop将正在运行的实例。其他pyglet pyglet等模块。依赖于这个窗口。

    Event loop events(事件循环的事件)

    You can listen for several events on the event loop instance. The most useful of these is on_window_close(), which is dispatched whenever a window is closed. The default handler for this event exits the event loop if there are no more windows. The following example overrides this behaviour to exit the application whenever any window is closed:

    你可以听几个事件事件循环的实例。其中最有用的是on_window_close(),每次关闭窗口。这个事件的默认处理程序退出事件循环如果没有其他窗口。下面的例子覆盖这种行为退出应用程序任何关闭窗口:

    event_loop = pyglet.app.EventLoop()
    
    @event_loop.event
    def on_window_close(window):
        event_loop.exit()
        return pyglet.event.EVENT_HANDLED
    
    event_loop.run()
    
    Overriding the default idle policy(覆盖默认的闲置政策)

    The pyglet.app.EventLoop.idle() method is called every iteration of the event loop. It is responsible for calling scheduled clock functions, redrawing windows, and deciding how idle the application is. You can override this method if you have specific requirements for tuning the performance of your application; especially if it uses many windows.

    pyglet.app.EventLoop.idle()方法被调用事件循环的每次迭代中。它负责打电话预定时钟功能,重绘窗口,并决定如何闲置的应用程序。你可以覆盖这个方法如果你有特殊要求,优化应用程序的性能;特别是如果它使用很多窗户。

    The default implementation has the following algorithm:

    默认实现有以下算法:

    1. Call pyglet.clock.tick() with poll=True to call any scheduled functions.

    poll = True调用pyglet.clock.tick()调用任何预定的功能。

    1. Dispatch the on_draw() event and call flip() on every open window.

    调度on_draw()事件和调用flip()在所有打开的窗口。

    3.Return the value of pyglet.clock.get_sleep_time().

    pyglet.clock.get_sleep_time()的返回值。

    The return value of the get_sleep_time() method is the number of seconds until the event loop needs to iterate again (unless there is an earlier user-input event); or None if the loop can wait for input indefinitely.

    的返回值get_sleep_time()方法的秒数,直到事件循环需要再次重复(除非有早期用户输入事件);或没有如果循环可以无限期等待输入。

    Note that this default policy causes every window to be redrawn during every user event – if you have more knowledge about which events have an effect on which windows you can improve on the performance of this method.

    注意,这个默认策略使每个窗口重绘期间每个用户事件——如果你有更多的了解,事件影响,windows可以提高该方法的性能。

    Dispatching events manually(手动调度事件)

    Earlier versions of pyglet and certain other windowing toolkits such as PyGame and SDL require the application developer to write their own event loop. This is usually just an inconvenience compared to pyglet.app.run(), but can be necessary in some situations when combining pyglet with other toolkits.

    早期版本的pyglet和某些其他窗口工具包PyGame和SDL等要求应用程序开发人员编写自己的事件循环。这通常只是一个不便pyglet.app.run相比(),但在某些情况下是必要的pyglet结合其他工具包。

    A simple event loop usually has the following form:

    一个简单的事件循环通常有以下形式:

    while True:
        pyglet.clock.tick()
    
        for window in pyglet.app.windows:
            window.switch_to()
            window.dispatch_events()
            window.dispatch_event('on_draw')
            window.flip()
    

    The dispatch_events() method checks the window’s operating system event queue for user input and dispatches any events found. The method does not wait for input – if ther are no events pending, control is returned to the program immediately.

    dispatch_events()方法检查窗口操作系统为用户输入事件队列和分派的任何事件。方法不等待输入——如果其他没有事件悬而未决,立即控制返回给程序。

    The call to pyglet.clock.tick() is required for ensuring scheduled functions are called, including the internal data pump functions for playing sounds, animations, and video.

    调用pyglet.clock.tick()需要确保预定功能,包括内部数据泵功能播放声音,动画,和视频。

    While it is possible to write your own event loop in this way, it is strongly discouraged for the following reasons:

    虽然有可能以这种方式编写自己的事件循环,强烈鼓励有以下原因:

    • The EventLoop class provides plenty of hooks for most toolkits to be integrated without needing to resort to a manual event loop.

    大多数工具包的EventLoop类提供了大量的钩子集成而无需求助于手动事件循环。

    • Because EventLoop is tuned for specific operating systems, it is more responsive to user events, and continues calling clock functions while windows are being resized, and (on Mac OS X) the menu bar is being tracked.

    因为EventLoop是针对特定的操作系统,更响应用户事件,并继续调用时钟函数虽然窗户被调整大小,和(在Mac OS X)菜单栏被跟踪。

    • It is difficult to write a manual event loop that does not consume 100% CPU while still remaining responsive to user input.

    很难写一个手动事件循环,不消耗100%的CPU的同时仍响应用户输入。

    The capability for writing manual event loops remains for legacy support and extreme cases where the developer knows what they are doing.

    写作手册事件循环的能力仍然遗留支持和极端情况下,开发者知道他们在做什么。

    二、The pyglet event framework(pyglet事件框架)

    The pyglet.window, pyglet.media, pyglet.app, pyglet.text, pyglet.input and other modules make use of a consistent event pattern. This provides several ways to attach event handlers to objects. You can also reuse this pattern in your own classes easily, by subclassing EventDispatcher.

    pyglet.window,pyglet.media,pyglet.app,pyglet.text,pyglet.input和其他模块使用一致的事件模式。这提供了几种方法来将事件处理程序附加到对象。你也可以重用此模式很容易在自己的类,子类化EventDispatcher。

    Throughout this documentation, an “event dispatcher” is an object that has events it needs to notify other objects about, and an “event handler” is some code that can be attached to a dispatcher.:

    在整个文档中,一个“事件调度器”事件是一个对象,它需要通知其它对象,和一个“事件处理程序”是一些代码,可以附加到一个调度程序。

    Setting event handlers(设置事件处理程序)

    An event handler is simply a function with a formal parameter list corresponding to the event type. For example, the pyglet.window.Window.on_resize() event has the parameters (width, height), so an event handler for this event could be written as:

    事件处理程序是一个简单的函数形式参数列表对应的事件类型。例如,pyglet.window.Window.on_resize()事件的参数(宽度、高度),因此该事件的事件处理程序可以写成:

    def on_resize(width, height):
        pass
    

    The Window class subclasses EventDispatcher, which enables it to dispatch it’s own events. There are a few different ways in which event handlers can be attached to recieve them. The simplest way is to directly attach the event handler to the corresponding attribute on the object. This will completely replace the default event handler:

    窗口类的子类EventDispatcher,使它派遣自己的事件。有几种不同的方式附加事件处理程序可以接待他们。最简单的方法是直接将事件处理程序附加到相应的属性对象。这将完全取代默认的事件处理程序:

    window = pyglet.window.Window()
    
    def on_resize(width, height):
        pass
    window.on_resize = on_resize
    

    If you don’t want to replace the default event handler, but instead want to add an additional one, pyglet provides a shortcut using the event decorator. Your custom event handler will run, followed by the default event handler:

    如果你不想替换默认的事件处理程序,而是想要添加一个额外的一个,pyglet使用事件装饰提供了一个快捷方式。您的自定义事件处理程序将运行,紧随其后的是默认的事件处理程序:

    window = window.Window()
    
    @window.event
    def on_resize(width, height):
        pass
    

    or if your handler has a different name:

    或如果您的处理程序有一个不同的名称:

    @window.event('on_resize')
    def my_resize_handler(width, height):
        pass
    

    In some cases, replacing the default event handler may be desired. For example, the defaultpyglet.window.Window.on_resize() event sets up a 2D orthographic OpenGL projection. If you wish to use another OpenGL projection, such as for a 3D scene, then you will likely want to replace this with your own custom event handler.

    在某些情况下,可能需要替换默认的事件处理程序。例如,默认pyglet.window.Window.on_resize()事件建立了二维直角的OpenGL投影。如果你想使用另一个OpenGL投影,如3 d场景,那么你可能会想这替换为您自己的自定义事件处理程序。

    In most simple cases, the event decorator is most convienent. One limitation of using the decorator, however, is that you can only add one additinal event handler. If you want to add multiple additional event handlers, the next section describes how to accomplish that.

    在最简单的情况下,事件装饰是最方便的。然而,使用装饰的一个限制是,你只能添加一个additinal事件处理程序。如果你想添加多个附加事件处理程序,下一节将描述如何完成。

    As a quick note, as shown in Subclassing Window, you can also replace default event handlers by subclassing the event dispatcher and adding the event handler as a method:

    一个简短的说明,如所示窗口子类化,还可以替换默认的事件处理程序通过子类化事件调度器和添加事件处理程序作为一个方法:

    class MyWindow(pyglet.window.Window):
        def on_resize(self, width, height):
            pass
    

    Stacking event handlers(堆积事件处理程序)

    It is often convenient to attach more than one event handler for an event. EventDispatcher allows you to stack event handlers upon one another, rather than replacing them outright. The event will propogate from the top of the stack to the bottom, but can be stopped by any handler along the way.

    常方便连接多个事件处理程序的事件。EventDispatcher允许堆栈在另一个事件处理程序,而不是取代它们。事件将从堆栈的顶部繁殖,但可以停在任何处理程序。

    To push an event handler onto the stack, use the push_handlers() method:

    把一个事件处理程序压入堆栈,使用push_handlers()方法:

    def on_key_press(symbol, modifiers):
        if symbol == key.SPACE:
            fire_laser()
    
    window.push_handlers(on_key_press)
    

    One use for pushing handlers instead of setting them is to handle different parameterisations of events in different functions. In the above example, if the spacebar is pressed, the laser will be fired. After the event handler returns control is passed to the next handler on the stack, which on a Window is a function that checks for the ESC key and sets the has_exit attribute if it is pressed. By pushing the event handler instead of setting it, the application keeps the default behaviour while adding additional functionality.

    他们使用推动处理程序,而不是设置一个参数化来处理不同的事件在不同的功能。在上面的例子中,如果空格键被按下,激光将被解雇。在事件处理程序返回控制权传递给下一个处理程序堆栈,这在一个窗口是一个函数,检查ESC键和设置has_exit属性是否被按下。通过将事件处理程序设置,应用程序将默认行为而添加额外的功能。

    You can prevent the remaining event handlers in the stack from receiving the event by returning a true value. The following event handler, when pushed onto the window, will prevent the escape key from exiting the program:

    你可以防止剩余的事件处理程序堆栈接收事件通过返回一个真正的价值。下面的事件处理程序,当推到窗边,将防止escape键退出程序:

    def on_key_press(symbol, modifiers):
        if symbol == key.ESCAPE:
            return True
    
    window.push_handlers(on_key_press)
    

    You can push more than one event handler at a time, which is especially useful when coupled with the pop_handlers()function. In the following example, when the game starts some additional event handlers are pushed onto the stack. When the game ends (perhaps returning to some menu screen) the handlers are popped off in one go:

    你可以把多个事件处理程序时,这是特别有用,当加上pop_handlers()函数。在接下来的例子中,当游戏开始一些附加事件处理程序被压入堆栈。当比赛结束时(也许回到一些菜单屏幕)的处理程序将被弹出:

    def start_game():
        def on_key_press(symbol, modifiers):
            print 'Key pressed in game'
            return True
    
        def on_mouse_press(x, y, button, modifiers):
            print 'Mouse button pressed in game'
            return True
    
        window.push_handlers(on_key_press, on_mouse_press)
    
    def end_game():
        window.pop_handlers()
    

    Note that you do not specify which handlers to pop off the stack – the entire top “level” (consisting of all handlers specified in a single call to push_handlers()) is popped.

    请注意,您没有指定处理程序将从堆栈中弹出,整个顶部“水平”(包括所有处理程序中指定一个调用push_handlers ())。

    You can apply the same pattern in an object-oriented fashion by grouping related event handlers in a single class. In the following example, a GameEventHandler class is defined. An instance of that class can be pushed on and popped off of a window:

    您可以应用同样的模式在面向对象的方式分组相关的事件处理程序在一个类。在接下来的例子中,一个GameEventHandler类定义。这类的实例可以推动和弹出窗口:

    class GameEventHandler(object):
        def on_key_press(self, symbol, modifiers):
            print 'Key pressed in game'
            return True
    
        def on_mouse_press(self, x, y, button, modifiers):
            print 'Mouse button pressed in game'
            return True
    
    game_handlers = GameEventHandler()
    
    def start_game()
        window.push_handlers(game_handlers)
    
    def stop_game()
        window.pop_handlers()
    

    Creating your own event dispatcher(创建自己的事件调度器)

    pyglet provides the Window, Player, and other event dispatchers, but exposes a public interface for creating and dispatching your own events.

    pyglet提供了窗口、球员和其他事件调度程序,但公开了一个公共接口用于创建和分派自己的事件。

    The steps for creating an event dispatcher are:

    创建一个事件调度器的步骤:

    子类EventDispatcher

    • Call the register_event_type() class method on your subclass for each event your subclass will recognise.

    调用register_event_type()类方法在你的每个事件你子类的子类会承认。

    • Call dispatch_event() to create and dispatch an event as needed.

    调用dispatch_event()来创建和分派事件。

    In the following example, a hypothetical GUI widget provides several events:

    在接下来的例子中,一个假设的GUI窗口小部件提供了一些事件:

    class ClankingWidget(pyglet.event.EventDispatcher):
        def clank(self):
            self.dispatch_event('on_clank')
    
        def click(self, clicks):
            self.dispatch_event('on_clicked', clicks)
    
        def on_clank(self):
            print 'Default clank handler.'
    
    ClankingWidget.register_event_type('on_clank')
    ClankingWidget.register_event_type('on_clicked')
    

    Event handlers can then be attached as described in the preceding sections:

    事件处理程序可以连接所述在前面的部分:

    widget = ClankingWidget()
    
    @widget.event
    def on_clank():
        pass
    
    @widget.event
    def on_clicked(clicks):
        pass
    
    def override_on_clicked(clicks):
        pass
    
    widget.push_handlers(on_clicked=override_on_clicked)
    

    The EventDispatcher takes care of propogating the event to all attached handlers or ignoring it if there are no handlers for that event.

    EventDispatcher负责根据所有附加事件处理程序或忽视它如果没有事件处理程序。

    There is zero instance overhead on objects that have no event handlers attached (the event stack is created only when required). This makes EventDispatcher suitable for use even on light-weight objects that may not always have handlers. For example, Player is an EventDispatcher even though potentially hundreds of these objects may be created and destroyed each second, and most will not need an event handler.

    零实例对象的开销,没有附加事件处理程序创建事件堆栈(只在需要时)。这使得EventDispatcher适合即使在使用轻量级的对象并不总是处理程序。例如,玩家一个EventDispatcher虽然可能数以百计的这些对象可能每秒创建和销毁,最不需要一个事件处理程序。

    Implementing the Observer pattern(实现观察者模式)

    The Observer design pattern, also known as Publisher/Subscriber, is a simple way to decouple software components. It is used extensively in many large software projects; for example, Java’s AWT and Swing GUI toolkits and the Python logging module; and is fundamental to any Model-View-Controller architecture.

    观察者设计模式,也称为发布者/订阅者,分离软件组件是一个简单的方法。它被广泛使用在许多大型软件项目;例如,Java的AWT和Swing GUI工具包和Python日志记录模块;,是任何模型-视图-控制器体系结构的基础。

    EventDispatcher can be used to easily add observerable components to your application. The following example recreates the <cite>ClockTimer</cite> example from <cite>Design Patterns</cite> (pages 300-301), though without needing the bulky Attach, Detach and Notifymethods:

    EventDispatcher可以用来轻松observerable组件添加到您的应用程序。下面的例子再现了ClockTimer设计模式的例子(页300 - 301),尽管无需笨重的附加,分离并通知方法:

    # The subject
    class ClockTimer(pyglet.event.EventDispatcher):
        def tick(self):
            self.dispatch_event('on_update')
    ClockTimer.register_event_type('on_update')
    
    # Abstract observer class
    class Observer(object):
        def __init__(self, subject):
            subject.push_handlers(self)
    
    # Concrete observer
    class DigitalClock(Observer):
        def on_update(self):
            pass
    
    # Concrete observer
    class AnalogClock(Observer):
        def on_update(self):
            pass
    
    timer = ClockTimer()
    digital_clock = DigitalClock(timer)
    analog_clock = AnalogClock(timer)
    

    The two clock objects will be notified whenever the timer is “ticked”, though neither the timer nor the clocks needed prior knowledge of the other. During object construction any relationships between subjects and observers can be created.

    两个时钟对象将通知每当定时器是“标记”,虽然所需的时钟计时器和先验知识。在对象构造任何可以创建主题和观察者之间的关系。

    相关文章

      网友评论

          本文标题:059-python库pyglet(四)

          本文链接:https://www.haomeiwen.com/subject/icvgwqtx.html