你能让我轻松理解动态、抽象的事件对象吗?

发布于 2024-07-11 16:14:56 字数 673 浏览 6 评论 0原文

我使用 MFC 编写了 C++ 事件驱动应用程序作为 GUI 按钮,并使用 onmousedown 等 HTML 事件来触发网页中的一些 Javascript。 当您使用界面并且事件是硬编码的时,事件驱动编程的想法是直观的。

我知道如何在 C 中使用函数指针,并且了解 Windows 如何使用它们来运行事件循环。 我可以编写代码来动态调用不同的函数。

我的问题是,从编译时转移到运行时。 我在这里谈论任何语言,但如果您需要一种语言,请选择 Javascript 或 PHP,因为我现在最常使用它们。 我完全不知道如何使用自己的事件对象来完成某件事。 这不是我理解的概念。 由于我不使用它们,我不知道它们的实际用途是什么。

例如,我想如果我想制作一个自定义回合制游戏,我可能会使用事件对象来表示某些只需要“发生”的游戏片段能力的效果。

有人可以给我一个自定义事件的简单使用吗? 或者它在哪些情况下有用或实用? 它在很大程度上取决于语言和环境以及事件的处理方式吗? Javascript 答案会很好,但我读了很多语言。

抱歉,我只是在这方面有所欠缺,需要一些实用的、高级的(中级?)的见解。 这就像 C 中的指针。我“得到”指针以及它们如何成为你的朋友。 但有一段时间我没有这样做,而且我认识的许多人仍然没有这样做。 一旦你掌握了它就很简单,我只是无法通过这种方式获得自定义的动态事件。

I've written C++ event-driven apps using MFC for GUI buttons, and I use HTML events like onmousedown to trigger some Javascript in a webpage. The idea of event-driven programming is intuitive when you are using the interface and events are hard-coded.

I know how to use a function pointer in C, and I see how Windows uses them to run an event loop. I can write code to dynamically call a different function.

My problem is, moving away from compile-time and into runtime. I'm talking any language here, but if you need a language, choose Javascript, or PHP as I use them most these days. I don't have a grasp at all of how I might use my own event object to get something done. It's just not a concept I get. And since I don't use them, I don't know what their practical use might be.

For example, I suppose that if I wanted to make a custom turn-based game, that I might use event objects to represent an effect of some game-piece ability that just needs to "happen."

Can someone give me a simple use of custom events? Or situations where it is useful or practical? Does it depend largely on the language and environment and how events are handled? A Javascript answer would be good, but I read many languages.

Sorry I am just deficient in this regard and need some practical, advanced (intermediate?) insight. It's like pointers in C. I "get" pointers and how they are your friend. But there was a time where I didn't, and many people I know still don't. It's simple once you get it, I just don't get custom, dynamic events that way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

不及他 2024-07-18 16:14:56

当我们谈论面向事件的编程时,我们通常谈论的是 观察者设计模式。 观察者设计模式的目标之一是实现对象之间的松散耦合

如果没有一个好的例子,这可能没有多大意义,而且肯定有很多好的例子; 我怀疑我的会是其中最好的,但我仍然会努力。 想象两个物体。 一个对象想知道另一个对象何时发生了什么事,这样它就可以自己做一些事情——也许家里的狗罗弗想在爸爸下班回家时在门口迎接他。 您可以通过多种方法来编写该场景,对吗?

  • 确保爸爸有对 Rover 的引用,当他回家时,调用 Rover 的greetDatAtTheDoor() 方法,或者

  • 给 Rover 一个关于爸爸的参考,
    监听爸爸的 onArriveHome 事件,
    当它触发时,请致电
    内部greetDadAtTheDoor()。

从表面上看,两者之间似乎没有太大区别,但实际上,爸爸对 Rover 的一些实现深深地烙印在他身上; 如果 Rover 的实现由于某种原因必须更改,我们就必须在两个地方进行更改:一次在 Rover 中,然后在 Dad 中再次进行更改。 也许没什么大不了的,但仍然不理想。

现在想象一下妈妈也想问候爸爸。 还有那只猫,比格斯沃思先生,他不太喜欢爸爸,想要确保他不在身边,所以他宁愿出去。 邻居乔想知道爸爸什么时候回家,这样他就可以因为爸爸欠他的二十块钱而烦扰他。 我们如何解释所有这些情况以及不可避免地会出现的其他情况? 将妈妈的greetHusband()方法、猫的getOutNow()方法、狗的greetDadAtTheDoor()方法和Joe的goGetMyMoney()方法的引用放入爸爸的类定义中会很快把爸爸的事情搞砸——而且没有充分的理由,因为所有的爸爸自己真正需要做的,就是回家。 妈妈、狗、猫和邻居只想在发生这种情况时得到通知,这样他们就可以执行内部实现所需的任何操作。

语言以不同的方式处理这些东西的细节,但是当你开始谷歌搜索时你会看到,该模式通常涉及事件“调度程序”上有一个数组或类似数组的结构(在本例中,爸爸-- 即,其他人都感兴趣的对象),以及“订阅者”(例如,妈妈、猫、罗弗和乔)都通过在调度程序上调用公开公开的方法并传入对自己的引用来“注册” ——最终以某种形式出现在爸爸的“订阅者”数组中的参考文献。 然后,当爸爸回家时,他“调度”一个事件——“我回来了!” 比方说,事件本质上是一个函数,循环遍历每个订阅者并使用他们自己的一些可公开访问的方法调用它们——只是这个方法的名字爸爸不知道,也不必知道,因为 那么

因为我这些天碰巧主要编写 ActionScript,所以它在我的世界中可能看起来是这样的——比如说,正如我的 Mom 类中声明的那样:

var dad:Dad = new Dad();
dad.addEventListener(DadEvent.ARRIVED_HOME, greetHusbandAtDoor);

private function greetHusbandAtDoor(event:DadEvent):void
{
   // Go greet my husband
}

,在爸爸中,所有当我回到家时,我必须做的是:

dispatchEvent(new DadEvent(DadEvent.ARRIVED_HOME));

...并且因为 Flash 为我处理事件分派和通知详细信息(同样,每个人的做法都有点不同,但在内部,Flash 遵循我描述的概念模型),我爸爸回到家,每个家庭成员都会自动执行其指定的操作。

希望这能解释一些事情——事件思维是什么样的,松散耦合意味着什么,为什么它很重要,等等。 祝你好运!

When we talk about event-oriented programming, we're usually talking about one or more implementations of the observer design pattern. And one goal of the observer design pattern is to achieve loose coupling between objects.

That probably doesn't mean much without a good example, and there are certainly lots of good ones out there; I doubt mine will be the best of them, but I'll take a whack at it nonetheless. Imagine two objects. One object wants to know when something happens with the other object, so it can do something itself -- maybe the family dog, Rover, wants to greet Dad at the door when he gets home from work. There are a couple of ways you might program that scenario, right?

  • Make sure Dad has an reference to Rover, and when he comes home, call Rover's greetDatAtTheDoor() method, or

  • Give Rover a reference to dad,
    listen for Dad's onArriveHome event,
    and when it fires, call
    greetDadAtTheDoor() internally.

On the surface, there might not seem to be much difference between the two, but actually, Dad has some of Rover's implementation burned into him; if Rover's implementation had to change for some reason, we'd have to make changes in two places: once in Rover, and then again in Dad. Not a huge deal, maybe, but still, not ideal.

Now imagine Mom wants to greet Dad as well. And the cat, Mr. Bigglesworth, who doesn't like Dad very much, wants to make sure he's not around, so he'd rather go outside. And a neighbor, Joe, wants to know when Dad gets home, so he can bug him about that twenty bucks Dad owes him. How do we account for all those scenarios, and the additional ones that'll inevitably crop up? Placing references to Mom's greetHusband() method, the cat's getOutNow() method, the dog's greetDadAtTheDoor() method, and Joe's goGetMyMoney() method into Dad's class definition would mess things up fast for Dad -- and for no good reason, since all Dad really needs to do, himself, is come home. Mom, the dog, the cat, and the neighbor just want to be notified when that happens, so they can do whatever their internal implementations require.

Languages handle the specifics of this stuff in different ways, but as you'll see when you start Googling around, the pattern usually involves there being an array, or array-like structure, on the event "dispatcher" (in this case, Dad -- i.e., the object everyone else is interested in), and the "subscribers" (e.g., Mom, the cat, Rover, and Joe) all "register" by calling a publicly exposed method on the dispatcher and passing in references to themselves -- references that end up, in some form, in Dad's array of "subscribers." Then, when Dad comes home, he "dispatches" an event -- the "I'm home!" event, say -- which is essentially a function that loops over each of his subscribers and invokes them with some publicly accessible method of their own -- only it's a method whose name Dad doesn't know, doesn't have to know, because the listener provided it when he/she/it passed it in.

Since I happen to code mostly ActionScript these days, here's how it might look in my world -- say, as declared from within my Mom class:

var dad:Dad = new Dad();
dad.addEventListener(DadEvent.ARRIVED_HOME, greetHusbandAtDoor);

private function greetHusbandAtDoor(event:DadEvent):void
{
   // Go greet my husband
}

In Dad, then, all I have to do, when I come home, is:

dispatchEvent(new DadEvent(DadEvent.ARRIVED_HOME));

... and because Flash handles the event-dispatching and notification details for me (again, everyone does it a bit differently, but internally, Flash follows the conceptual model I've described), my Dad comes home, and each family member does what it signed up to do automatically.

Hopefully that explains things a bit -- what event-thinking looks like, what loose coupling means, why it's important, and so on. Best of luck!

何其悲哀 2024-07-18 16:14:56

在编译语言中,您可以编写自己的事件循环。 在运行时语言中,它已经由主机环境实现,程序员仅获得事件系统的抽象接口。 你永远不会看到事件循环。

使用事件构建功能有两个方面。 第一个是定义事件触发的条件。 在浏览器的 JavaScript 中,没有一个 mousedown 事件。 事实上,页面上的每个元素都有一个。 在这种情况下,它们中的任何一个何时触发的条件取决于鼠标光标的位置以及鼠标按钮是否刚刚从上状态切换到下状态。 这种情况可能会导致触发多个事件。 (在浏览器中,有一个与此相关的称为事件冒泡的东西。但这超出了本文的范围)。

另一方面是事件处理程序。 无论是否有处理程序,事件都会发生。 提供处理程序由您决定。 在 javascript 中,函数是一等值。 它们是在运行时定义的,而不是在编译时定义的。 因此不需要指针或跳转表。 您在运行时创建一个新函数,并将其分配给主机环境在特定事件触发时查找的特殊属性。

因此,在堆栈溢出时,每个向下箭头的 onclick 事件都会有一个事件处理程序,它将箭头变成红色,递减一个数字,检查其他一些变量并有条件地显示通知。 然后,当处理程序返回时,它将线程的控制权返回给浏览器,用户可以再次与浏览器交互。 (处理事件时所有交互都会停止,因此最好尽快完成)。 这是使用 jquery 库的示例。

jQuery("a .downarrow")
.click(function(e){ e.target.style.color="red" /* ... do other things */ });

或者在原始 JavaScript(版本 1.6)中可能就是

Array.prototype.slice.apply(document.getElementsByTagName("a"))
.filter(function(o){ return !!(/downarrow/).exec(o.className)})
.forEach(function(o){ 
    o.onclick= function(e){ 
        e.target.style.color="red" /* ...do other things * / 
    }
 });

这么简单。 您执行此类操作的主要原因是它允许异步交互。 GUI 应用程序不会按部就班地直线发展。 它必须动态响应用户的输入。 事件是一种伪造多线程应用程序外观的方法。 它可以让用户看到许多事情同时发生而不会互相干扰。

您可以使用库来定义自定义事件。 这可能会对某些特定领域的事件进行编码。 例如:您有一个国际象棋游戏正在考虑下一步行动。 搜索移动的过程已超时。 国际象棋游戏可以触发 onComputerMove 事件。 您可以使用一个函数来处理该事件,该函数获取移动的规范,更新棋盘的视觉表示,并向用户弹出一条消息,然后退出。 然后,当玩家移动时,您可以触发 onPlayerMove 事件,该事件的作用大致相同。

In a compiled language, you write your own event loop. In a runtime language, it's implemented by the host environment already, and the programmer only gets an abstracted interface into the events system. You never see the event loop.

There are two facets to building functionality with events. The first is defining the conditions under which an event will fire. In javascript in a browser, there isn't a single mousedown event. There's, in fact, one for every element on the page. In this case, the condition for when any of them will fire is based both on the location of the mouse cursor, and whether the mouse button has just switched from the upstate to the downstate. This condition may cause multiple events to fire. (In the browser, there's something called event bubbling that's related to this. but that's out of scope here).

The other facet is the event handler. An event happens regardless of whether there's a handler for it or not. Providing the handler is up to you. In javascript, functions are first class values. They get defined at runtime, not at compile-time. So there's no need for pointers or jump tables. You create a new function at run time, and you assign it to a special property that the host environment looks up when a particular event fires.

so on stack overflow, there will be an event handler on each of the down arrow's onclick events, which turns the arrow red, decrements a number, checks some other variable and conditionally shows a notification. Then when the handler returns- it returns control of the thread to the browser, and hallelujah the user can interact with the browser again. (all interactions cease while an event is handled, so you'd better make it quick). Here's an example using the jquery library.

jQuery("a .downarrow")
.click(function(e){ e.target.style.color="red" /* ... do other things */ });

or in raw JavaScript (version 1.6) it may be

Array.prototype.slice.apply(document.getElementsByTagName("a"))
.filter(function(o){ return !!(/downarrow/).exec(o.className)})
.forEach(function(o){ 
    o.onclick= function(e){ 
        e.target.style.color="red" /* ...do other things * / 
    }
 });

It really is that simple. The main reason you would do something like this is it allows asynchronous interaction. A GUI application doesn't progress in a straight line, step by step. It has to respond dynamically to the user's input. Events are a way to kind of fake the appearance of a multithreaded application. It can look to the user that many things are happening simultaneously without interrupting each other.

You could use a library to define a custom event. This would perhaps encode some domain-specific event. For example: you have a chess game that is thinking about its next move. the process for searching for the move runs out of time. The chess game could fire an onComputerMove event. You could handle that event with a function that grabs the specifications for the move, and updates the visual representation of the chessboard, and pops up a message for the user, and exits. Then when the player moves you can fire an onPlayerMove event, which does much of the same thing.

二智少女 2024-07-18 16:14:56

事件最美妙的事情是减少两个模块或类之间的双向显式耦合。

假设我有两个类:Baby 和 Mommy


在没有事件的情况下,我粗略地看到两种允许妈妈喂养婴儿的方法:

  • 妈妈每半小时对 Baby 调用 baby.pokeBelly() 方法了解是否必须调用 baby.fillWith(milk)
    问题在于,妈妈的线程必须在婴儿在 while 循环中等待一整天
  • 婴儿知道其关联的妈妈并调用 mommy.feed(me) 方法,该方法在依次调用 baby.fillWith(milk)
    问题是让一个简单的婴儿去请正确的妈妈来填饱肚子。
    婴儿不会这样做,因为他们应该保持简单。

通过事件,您可以将 Mommy.OnBabyCries(baby) 绑定到其婴儿的 baby.Cry 事件:

void Mommy.OnBabyCries(baby) { 
      婴儿.fillWith(牛奶) 
  } 
  

之后,如果宝宝想吃东西,它所要做的就是引发它的 Cry 事件。

这个逻辑保留在妈妈身上,甚至后来保留在任何保姆身上,而宝宝会保持快乐,而不必担心。

The most wonderful thing about events is that is reduce bidirectional explicit coupling between two modules or classes.

So let say I have two classes: Baby and Mommy


Without events, I roughly see two methods to allow a Mommy to feed a Baby:

  • mommy calls the baby.pokeBelly() method on the Baby each half hour to know if you have to call baby.fillWith(milk).
    The problem is that Mommy's thread have to wait all day after the baby in a while loop
  • Baby know its associated Mommy and call a mommy.feed(me) method, which in turn calls baby.fillWith(milk).
    The problem is then that ask a simple baby to ask the right mommy to fill its belly.
    Babies don't do that as they should stay simple.

With events, you could bind a Mommy.OnBabyCries(baby) to its babie's baby.Cry event:

void Mommy.OnBabyCries(baby) {
    baby.fillWith(milk)
}

After this, if baby wants to eat, all it has to do is raise its Cry event.

The logic stays in the Mommy, or even later in any Babysitter, and Baby stays happy, without having to worry.

握住我的手 2024-07-18 16:14:56

我不知道我是否完全理解你的问题,但是带有事件的类就像带有按钮的 GUI 一样。 把它想象成一个同人......在每个有活动的班级里,都有一个小人,有一个虚拟按钮可供按下。 他不知道按钮会做什么,但他知道何时按下它。 现在想想一个相关的类,里面有另一个小人。 那个人知道,当他听到按下按钮的消息时,他应该做某事。

任何时候你想让第二个人知道第一个人所做的事情,你就可以连接第一类和第二类之间的总机(订阅该事件)。 当第一个人按下按钮(触发事件)时,第二个人会做他知道他应该做的任何事情......

我不知道这是否有帮助,或者我只是在酸之旅中想着小小人物我的程序...

I don't know if I totally understand your question but a class with an event is just like an GUI with a button. Just think about it like a homonculus...Inside every class with an event there's a little person with a virtual button to press. He doesn't know what the button will do, but he knows when to press it. Now think of a related class with another little person in it. That person knows that when he hears a message that a button was pressed, he's supposed to do something.

Anytime you want the second guy to know about something the first guy did, you connect the switchboard between the first class and the second class (Subscribe to the event). When the first guy presses the button (fires the event), the second guy does whatever he knows he's supposed to do...

I don't know if this helps or I'm just on an acid trip thinking of little tiny people in my programs...

他夏了夏天 2024-07-18 16:14:56

在 StackOverflow,当您投反对票时,您的声誉就会下降,并且向下箭头会变成红色。

通常,您编写一个 onclick,更新其中的所有元素,并尽量不要忘记每次页面布局更改时更改它。

相反,您可以声明 onVoteDown 事件,在 onclick 中触发它并订阅此事件:

  • 您的声誉 div
  • 您的箭头 img
  • 将您的投票发送到服务器的 XmlHTTPRequest

At StackOverflow, when you vote down, your reputation falls and your down arrow turns red.

Usually, you write a single onclick, update all elements in it, and try not to forget to change it every time when page layout changes.

Instead, you may declare onVoteDown event, fire it in onclick and subscribe to this event:

  • your reputation div
  • your arrow img
  • your XmlHTTPRequest that sends your vote to the server.
德意的啸 2024-07-18 16:14:56

我不完全确定您正在寻找什么样的答案,所以如果这不是很接近的话,我深表歉意。 ;)


通过自定义,您是指自定义操作自定义触发器,还是真正的自定义事件

例如:自定义操作将响应预定义事件(例如,鼠标单击)、自定义触发器 将通过脚本伪造鼠标单击,而自定义事件将是未由语言定义或不易获得的侦听器。

如果您正在寻找自定义事件,我真的帮不了您。 不过,我认为 JavaScript 对它们的支持并不多。


要定义操作...

事件通常是通过对象的预定义属性建立的,例如window.onload。 默认情况下,它们都等于 undefinednull。 因此,要使用它们,您必须将它们设置为函数的值。

您可以使用“匿名”函数:

window.onload = function (eventObject) {
    /* ... */
};

或者将它们设置为函数引用(不一样,但类似于指针):

function handleOnload(eventObject) {
    /* ... */
}

window.onload = handleOnload; /* note the lack of parenthesis */

当触发事件时,调用该函数。 因此,无论哪种设置,当页面加载完成时,您放置的代码而不是 /* ... */ 将被执行。

还有更正式的方法可用于创建事件。 W3C 定义了 addEventListener,而 IE 使用 attachEvent更多信息

有大量参考资料可用于了解可用事件列表。 这里有 2 个应该为您提供良好的基础:


浏览器通常处理事件的触发——无论是浏览器事件(onload) 或用户事件 (onclick)。 属性和功能旨在做出响应。

触发您自己的事件并不是最容易完成的事情。 要完全定义 Event 对象需要一些工作 - 并且因浏览器而异

不过,如果您不需要 Event 对象,您可以简单地调用该事件:

window.onload();

I'm not entirely sure what sort of answer you're looking for, so I apologize if this isn't anything close. ;)


By custom, do you mean custom actions, custom triggers, or truly custom events?

E.g.: A custom action would respond to a pre-defined event (say, a mouse click), a custom trigger would be faking a mouse click via script, and a custom event would be a listener that's not defined by the language or isn't readily available.

If you're looking for custom events, I can't really help you. Though, I don't think there's much support for them in JavaScript.


To define an Action...

Events are normally established via pre-defined properties of an object, say window.onload. By default, they are all equal to undefined or null. So, to put them to use, you have to set them to the value of a function.

You can use an "anonymous" function:

window.onload = function (eventObject) {
    /* ... */
};

Or set them to a function reference (not the same, but similar to a pointer):

function handleOnload(eventObject) {
    /* ... */
}

window.onload = handleOnload; /* note the lack of parenthesis */

When the event is triggered, the function is called. So, in either setup, when the page finishes loading, the code you place instead of /* ... */ will be executed.

There's also more formal methods available for creating events. W3C defines addEventListener while IE uses attachEvent. More info.

There are plenty of references available for learning the list of available events. Here's 2 that should give you a good base:


The browser usually handles the triggering of events -- either for browser events (onload) or user events (onclick). The property and function are meant to respond.

Triggering your own event isn't the easiest thing to accomplish. To completely define an Event object takes some work -- and varies between browsers.

Though, if you don't need the Event object, you can simply call the event:

window.onload();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文