【问题标题】:including somedialog.h into other parts of the project makes ui_somedialog.h invisible to compiler将 somedialog.h 包含到项目的其他部分使 ui_somedialog.h 对编译器不可见
【发布时间】:2020-01-16 15:50:34
【问题描述】:

我正在尝试在项目中以不同方式使用自定义 Qt 对话框。有两种情况会出现同样的问题。

1.我将对话框作为库包含在主项目中。 该库是一个更大的 subdirs 项目的一部分,该项目还包含将使用它的主应用程序。这是项目树:

AppProject
|_AppProject.pro
|_MyApp
  |_myapp.pro
  |_main.cpp
  |_mainwindow.h
  |_mainwindow.cpp
  |_mainwindow.ui
|_GUILib
  |_guilib.pro
  |_guilib_decl.h
  |_somedialog.h
  |_somedialog.cpp
  |_somedialog.ui

这里的源文件:

main.cppmainwindow.hmainwindow.cpp
guilib_decl.hsomedialog.hsomedialog.cpp
somedialog.ui

AppProject 是一个普通的子目录项目,包括 MyApp 和 GUILib:

TEMPLATE = subdirs

SUBDIRS += MyApp \
           GUILib

MyApp.depends = GUILib

MyApp 是一个普通的应用模板:

QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = MyApp
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

CONFIG += c++14

DEPENDPATH += ../GUILib

INCLUDEPATH += ../GUILib

LIBS += -L../GUILib -lGUILib  

HEADERS += mainwindow.h \

SOURCES += main.cpp \
           mainwindow.cpp \

FORMS +=   mainwindow.ui \

这是 lib 项目文件:

QT += core widgets gui

TARGET = GUILib
TEMPLATE = lib

CONFIG += c++14
CONFIG -= debug_and_release

DEFINES += QT_DEPRECATED_WARNINGS
DEFINES += GUILIB_LIBRARY


HEADERS += \
    guilib_decl.h \
    somedialog.h

SOURCES += \
    guilib.cpp \
    somedialog.cpp

FORMS += \
    somedialog.ui

该库可以自己构建(没问题,找到了ui_somedialog.h),但是如果我将somedialog.h 包含到mainwindow.h 中,那么编译器会吐出以下错误消息:

ui_somedialog.h: 没有这样的文件或目录

2。我将对话框作为非库包含在测试中。

这里的项目树如下所示:

AppProject
    |_AppProject.pro
    |_MyApp
      |_myapp.pro
      |_main.cpp
      |_mainwindow.h
      |_mainwindow.cpp
      |_mainwindow.ui
      |_somedialog.h
      |_somedialog.cpp
      |_somedialog.ui
    |_Tests
      |_tests.pro
      |_main.cpp
      |_tst_somedialog.cpp

它仍然是一个子目录项目,但这次其中一个是一个Test项目,对话框只是应用程序的一个普通部分(非lib)。

用于测试的项目文件如下所示:

QT += testlib
QT += widgets gui

TARGET = Tests
TEMPLATE = app

CONFIG += c++14
CONFIG += testcase 
CONFIG -= debug_and_release

INCLUDEPATH += ../MyApp

SOURCES += main.cpp \
    tst_somedialog.cpp \

不幸的是,对话框是否是库似乎并不重要,编译器在两种情况下都会显示相同的错误消息。最有趣的部分是,ui 文件在它应该在的位置(uic 完成了它的工作),所以理论上编译器应该在这两种情况下都找到它,但由于某种原因它没有。是否有一些我不知道的秘密使它起作用?为什么当我尝试在其他地方使用 ui_somedialog.h 时编译器看不到它?

谢谢。

编辑:修改为包含场景 2。

EDIT2:为场景 1 添加了源文件。

【问题讨论】:

  • 带对话框的库?这是一个好方法吗..?
  • 这只是一个概念。老实说,当我尝试在单元测试中使用对话框时,也发生了同样的问题。 ui_somedialog.h 如果没有在测试中使用,则找到,但另一方面,如果将其包含在测试中,则会出现相同的问题。我想如果我将要测试的对话框变成一个库(以及所有其他 gui 元素),问题就可以解决,但显然不是。这些问题似乎以某种方式相关。我想如果我找到了解决方案,测试问题也可以用同样的方式解决。
  • 我们需要查看 somedialog.cpp 和 .h 中的代码才能说出问题所在。
  • 为场景一添加了代码示例。它会产生帖子中提到的错误。
  • @pusrob 我已经给了你答案,不要从生成的代码继承,使用我在那里介绍的方法(私有成员指针)。这样您就不会暴露您的库“内部”,并减少为您的库导出的标头数量。

标签: c++ qt dialog shared-libraries qmake


【解决方案1】:

最好的选择是将所有 gui 保留在主应用程序中,但由于这并不总是一种选择,请进一步阅读。

首先我想提一下发生这种情况的原因,这是因为GUILib/GeneratedFiles(或配置Qt工具以放置uic生成的文件的任何路径)不在INCLUDEPATH中MyApp,一个快速的技巧是将路径添加到INCLUDEPATH,但这会使事情变得更加复杂,比如如果你想部署你的库,你需要确保这些工具被配置为在同一个文件中创建文件所有平台上的路径,因此不推荐解决方案。

一个更好的解决方案是创建一个使用PIMPL 包装对话框的类,并且基本上从所有外部源中,您只包含包含 PIMPL“接口”的标题。

注意:使用QObject,父级负责删除它的子级,因此为避免重复删除,请勿使用std::unique_ptr,以防您为对话框设置父级。

乐: 或者第三个选项(实际上这只是 PIMPL,所以从技术上讲它仍然是第二个选项)是避免将生成的文件 (ui_somedialog.h) 包含到 somedialog.h 中(您在使用您的库),请参阅文档here,了解如何将 uic 生成的代码用于 C++ 代码(查看 Using a Pointer Member Variable)。

//somedialog.h

#include <QWidget>
//notice there is no include for ui_somedialog.h
namespace Ui {
// forward reference for the generated class
    class SomeDialog;
}

class SomeDialog : public QWidget
~SomeDialog();
//...
private:
//member pointer to the generated class
    Ui::SomeDialog* ui;
}

//somedialog.cpp

#include "somedialog.h"
//here we have the include for ui_somedialog.h
#include "ui_somedialog.h"

SomeDialog::SomeDialog(QWidget *parent) :
QWidget(parent), ui(new Ui::SomeDialog)
{
    ui->setupUi(this);
}

SomeDialog::~SomeDialog()
{
    delete ui;
}

这是一种类似 PIMPL 的方法,您只需前向引用内部类并将接口导出到它。

有一种方法可以设置您希望 Qt 工具为您生成代码的方法,但我现在找不到它,对我来说,当前的工具似乎总是使用这种成员指针方法。

【讨论】:

  • 所以我们应该忘记库并将所有内容放在一个 blob 中。这就是1980年代的事情。然后你在谈论 PIMPL,而他从未问过任何相关的事情。并且 std::unique_ptr 的使用也完全超出了问题的范围。基本上,你的回答什么也没说,他的问题也没有解决。此外,他的 INCLUDEPATH 设置正确。
  • @fonZ 我有几点要辩护:1)我们应该使用库,但我仍然认为将 gui 保存在一个地方是一个很好的设计理念,而不是分散在所有库中 2)如果他不导出生成的代码,则此 INCLUDEPATH 设置正确 3) PIMPL 是一种非常好的方法,用于防止内部构件从库中“泄漏” 4) 在与 pimpl 示例的链接中使用了 unique_ptr,我只是提醒了他认为 QObject 有自己的内存管理方式,并且会干扰智能指针。
  • 1) 您应该始终努力编写模块化的代码。最好的例子是 Qt 本身。 2)如果您编译一个库,则包含生成的代码。如果不是,那么它是由使用它的应用程序生成的。 3) Qt 有它自己的 PIMPL 成语。 4) Qt 使用原始指针,使用 std::unique_ptr 很可能会破坏一些东西,因为 Qt 从来没有为此而构建,你将不得不在任何地方转换你的智能指针。其次,Qt使用父子的方式来管理内存,删除父,子也将被删除。你看 Qt 就好像它只是普通的 C++。
  • 您的答案不是答案,这就是我否决它的原因。让我改写一下,因为我觉得这变成了一场文字游戏。 1)不,你说把它们放在一起。 2)我说 OR 并且在您的库中包含生成的代码以避免每次都必须重新生成绝对没有错。 3)Qt有自己的PIMPL成语实现,所以在不知道怎么用的情况下,在Qt中盲目使用成语是错误的。 4)你的例子是错误的。底线是问题仍未得到解答,而且讨论不相关的主题毫无意义。
猜你喜欢
  • 2021-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
  • 1970-01-01
  • 2012-05-25
  • 1970-01-01
相关资源
最近更新 更多