保持 GUI 分开 [英] Keeping the GUI separate

查看:20
本文介绍了保持 GUI 分开的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个程序(除其他外)有一个命令行界面,让用户输入字符串,然后通过网络发送.问题是我不确定如何将在 GUI 内部生成的事件连接到网络接口.例如,假设我的 GUI 类层次结构如下所示:

I have a program that (amongst other things) has a command line interface that lets the user enter strings, which will then be sent over the network. The problem is that I'm not sure how to connect the events, which are generated deep inside the GUI, to the network interface. Suppose for instance that my GUI class hierarchy looks like this:

GUI -> MainWindow -> CommandLineInterface -> EntryField

GUI -> MainWindow -> CommandLineInterface -> EntryField

每个 GUI 对象都包含一些其他 GUI 对象,并且一切都是私有的.现在 entryField 对象生成一个事件/信号,表明已输入消息.目前我正在将信号向上传递到类层次结构,因此 CLI 类看起来像这样:

Each GUI object holds some other GUI objects and everything is private. Now the entryField object generates an event/signal that a message has been entered. At the moment I'm passing the signal up the class hierarchy so the CLI class would look something like this:

public:
    sig::csignal<void, string> msgEntered;

在 c'tor 中:

entryField.msgEntered.connect(sigc::mem_fun(this, &CLI::passUp));

passUp 函数只是再次发出信号供所属类 (MainWindow) 连接,直到我最终可以在主循环中执行此操作:

The passUp function just emits the signal again for the owning class (MainWindow) to connect to until I can finally do this in the main loop:

gui.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));

现在这似乎是一个非常糟糕的解决方案.每次我向 GUI 添加一些东西时,我都必须通过类层次结构将它连接起来.我确实看到了几种解决方法.我可以公开所有对象,这将允许我在主循环中执行此操作:

Now this seems like a real bad solution. Every time I add something to the GUI I have to wire it up all through the class hierarchy. I do see several ways around this. I could make all objects public, which would allow me to just do this in the main loop:

gui.mainWindow.cli.entryField.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));

但这与封装的想法背道而驰.我也可以在整个 GUI 中传递对网络接口的引用,但我希望尽可能独立地保留 GUI 代码.

But that would go against the idea of encapsulation. I could also pass a reference to the network interface all over the GUI, but I would like to keep the GUI code as seperate as possible.

我感觉这里缺少一些重要的东西.有没有干净的方法来做到这一点?

It feels like I'm missing something essential here. Is there a clean way to do this?

注意:我使用的是 GTK+/gtkmm/LibSigC++,但我没有这样标记它,因为我在使用 Qt 时遇到了几乎相同的问题.这确实是一个普遍的问题.

Note: I'm using GTK+/gtkmm/LibSigC++, but I'm not tagging it as such because I've had pretty much the same problem with Qt. It's really a general question.

推荐答案

如果没有一些全球发布/订阅中心,您将无法避免在层次结构中向上或向下传递某些内容.即使您将侦听器抽象为通用接口或控制器,您仍然必须以某种方式将控制器附加到 UI 事件.

Short of having some global pub/sub hub, you aren't going to get away from passing something up or down the hierarchy. Even if you abstract the listener to a generic interface or a controller, you still have to attach the controller to the UI event somehow.

使用发布/订阅集线器添加另一层间接,但仍然存在重复 - entryField 仍显示发布消息就绪事件",而侦听器/控制器/网络接口显示侦听消息就绪事件",因此有一个双方都需要知道的公共事件 ID,如果您不打算在两个地方对其进行硬编码,则需要将其传递到两个文件中(尽管作为全局,它不会作为参数传递;其中本身没有什么大的优势).

With a pub/sub hub you add another layer of indirection, but there's still a duplication - the entryField still says 'publish message ready event' and the listener/controller/network interface says 'listen for message ready event', so there's a common event ID that both sides need to know about, and if you're not going to hard-code that in two places then it needs to be passed into both files (though as global it's not passed as an argument; which in itself isn't any great advantage).

我已经使用了所有四种方法 - 直接耦合、控制器、监听器和发布订阅 - 在每个后继者中你都稍微放松了耦合,但你永远不会摆脱一些重复,即使它只是已发布事件的 ID.

I've used all four approaches - direct coupling, controller, listener and pub-sub - and in each successor you loosen the coupling a bit, but you don't ever get away from having some duplication, even if it's only the id of the published event.

这真的归结为差异.如果您发现需要切换到接口的不同实现,那么将具体接口抽象为控制器是值得的.如果您发现需要其他逻辑来观察状态,请将其更改为观察者.如果您需要在进程之间解耦它,或者想要插入更通用的架构,pub/sub 可以工作,但它引入了一种全局状态形式,并且不适合编译时检查.

It really comes down to variance. If you find you need to switch to a different implementation of the interface, then abstracting the concrete interface as a controller is worthwhile. If you find you need to have other logic observing the state, change it to an observer. If you need to decouple it between processes, or want to plug into a more general architecture, pub/sub can work, but it introduces a form of global state, and isn't as amenable to compile-time checking.

但是,如果您不需要独立改变系统的各个部分,则可能不值得担心.

But if you don't need to vary the parts of the system independently it's probably not worth worrying about.

这篇关于保持 GUI 分开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆