Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 保持GUI的独立性_C++_User Interface_Signals Slots - Fatal编程技术网

C++ 保持GUI的独立性

C++ 保持GUI的独立性,c++,user-interface,signals-slots,C++,User Interface,Signals Slots,我有一个程序,其中包括一个命令行界面,允许用户输入字符串,然后通过网络发送。问题是,我不确定如何将GUI中深层生成的事件连接到网络接口。例如,假设我的GUI类层次结构如下所示: public: sig::csignal<void, string> msgEntered; GUI->MainWindow->CommandLineInterface->EntryField 每个GUI对象都包含一些其他GUI对象,所有内容都是私有的。现在entryField对象生成一个事件/信号

我有一个程序,其中包括一个命令行界面,允许用户输入字符串,然后通过网络发送。问题是,我不确定如何将GUI中深层生成的事件连接到网络接口。例如,假设我的GUI类层次结构如下所示:

public:
    sig::csignal<void, string> msgEntered;
GUI->MainWindow->CommandLineInterface->EntryField

每个GUI对象都包含一些其他GUI对象,所有内容都是私有的。现在entryField对象生成一个事件/信号,表明已输入消息。目前,我正在向上传递类层次结构的信号,因此CLI类的外观如下所示:

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

gui.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));
gui.mainWindow.cli.entryField.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));
现在看来这是一个非常糟糕的解决方案。每次我向GUI添加一些东西时,我都必须通过类层次结构将其连接起来。我确实认为有几种方法可以解决这个问题。我可以公开所有对象,这将允许我在主循环中执行此操作:

gui.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));
gui.mainWindow.cli.entryField.msgEntered.connect(sigc::mem_fun(networkInterface, &NetworkInterface::sendMSG));
但这与封装的思想背道而驰。我还可以通过GUI传递对网络接口的引用,但我希望GUI代码尽可能独立

我觉得我错过了一些重要的东西。有没有干净的方法可以做到这一点


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

由于这是一个一般性的问题,我将尝试回答它,即使我“只是”一个Java程序员。:)

我更喜欢在程序的两侧使用接口(抽象类或C++中的任何对应机制)。一方面是包含业务逻辑的程序核心。它可以生成GUI类可以接收的事件,例如(例如)stringReceived。另一方面,core实现了一个“UI侦听器”接口,其中包含“stringEntered”等方法

通过这种方式,UI与业务逻辑完全解耦。通过实现适当的接口,您甚至可以在核心和UI之间引入网络层

[编辑]在我的应用程序的初学者类中,几乎总是有这样的代码:

Core core = new Core(); /* Core implements GUIListener */
GUI gui = new GUI(); /* GUI implements CoreListener */
core.addCoreListener(gui);
gui.addGUIListener(core);
[/Edit]

尝试设计模式。链接包括到目前为止的示例代码


您缺少的基本内容是,如果引用被转换为对象实现的接口(抽象类),那么您可以传递引用而不违反封装。

在我看来,CLI应该独立于GUI。在MVC架构中,它应该扮演模型的角色


我会使用一个控制器来管理EntryField和CLI:每次EntryField发生变化时,CLI都会被调用,所有这些都由控制器管理。

根本问题是,您将GUI视为一个单片应用程序,只有GUI通过比平常更大的电线连接到逻辑的其余部分

您需要重新考虑GUI与后端服务器的交互方式。通常,这意味着您的GUI成为一个独立的应用程序,它几乎不做任何事情,并且与服务器对话,而GUI内部(即您的信号和事件)与服务器的处理逻辑之间没有任何直接耦合。也就是说,当您单击某个按钮时,您可能希望它执行某些操作,在这种情况下,您需要调用服务器,但几乎所有其他事件都只需要更改GUI内的状态,而不对服务器执行任何操作—直到您准备就绪,或者用户需要一些响应,或者您有足够的空闲时间在后台进行调用

诀窍是为服务器定义一个完全独立于GUI的界面。以后您应该能够在不修改服务器的情况下更改GUI


这意味着您将无法自动发送事件,您需要手动将它们连接起来

如果没有一些全球性的酒吧/酒吧中心,你就无法避免在层次结构上传递一些东西。即使将侦听器抽象为通用接口或控制器,也必须以某种方式将控制器附加到UI事件

对于发布/订阅中心,您添加了另一层间接寻址,但仍然存在重复-入口字段仍然显示“发布消息就绪事件”,侦听器/控制器/网络接口显示“侦听消息就绪事件”,因此双方都需要知道一个公共事件ID,如果您不打算在两个地方硬编码,那么它需要被传递到两个文件中(尽管作为全局文件,它不是作为参数传递的;这本身并没有什么好处)

我已经使用了所有四种方法——直接耦合、控制器、侦听器和发布订阅——在每个后续方法中,您都会稍微放松耦合,但即使只是发布事件的id,也无法避免重复

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


但是,如果您不需要独立地改变系统的各个部分,那么可能就不值得担心了

您可以使用将任何GUI解耦,并轻松地与消息通信。还可以查看。

Core不应该实现CoreListener,GUI不应该实现Guilitener吗?如果没有,我就不想维护您的代码:PNot,因为核心需要响应GUI事件,而GUI需要响应