【问题标题】:Creating class from existing Qt class从现有的 Qt 类创建类
【发布时间】:2011-07-10 12:27:24
【问题描述】:

我已经阅读了 Qt 4.7 C++ 教程,并开始了一个项目来扩展 QTreeView 的一些功能。

我正在尝试执行以下操作:

  1. 使用 QTreeView 确保程序运行良好
  2. 基于 ..\src\gui\itemviews\qtreeview.cpp、qtreeview.h 和 qtreeview_p.h 复制和粘贴新文件
  3. 在每个文件名和每个文件(包括 .pro 文件)中将“QTreeView”替换为“CustomTreeView”

我收到以下警告(使用 MSVC,命令行):

.\CustomTreeView.cpp(147) : warning C4273: 'CustomTreeView::CustomTreeView' : inconsistent dll linkage
        c:\home\jetimms\code\projects\CustomTreeViewTest\CustomTreeView.hpp(31) : see previous definition of '{ctor}'

这些警告还有很多,但它们看起来与上面相同。

另外,我有这些错误:

.\CustomTreeView.cpp(1216) : error C2248: 'NoState' : cannot access protected enumerator declared in class 'QAbstractItemView'
    c:\qt\4.7.0\include\qtgui\../../src/gui/itemviews/qabstractitemview.h(304) : see declaration of 'NoState'
    c:\qt\4.7.0\include\qtgui\../../src/gui/itemviews/qabstractitemview.h(63) : see declaration of 'QAbstractItemView'
.\CustomTreeView.cpp(1216) : error C2248: 'EditingState' : cannot access protected enumerator declared in class 'QAbstractItemView'
    c:\qt\4.7.0\include\qtgui\../../src/gui/itemviews/qabstractitemview.h(307) : see declaration of 'EditingState'
    c:\qt\4.7.0\include\qtgui\../../src/gui/itemviews/qabstractitemview.h(63) : see declaration of 'QAbstractItemView'

上面是在抱怨以下内容的等价物(在 qtreeview.h 中),除了用 CustomTreeView 替换 QTreeView 之外没有任何变化:

bool QTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos)
{
    Q_Q(QTreeView);
    // we want to handle mousePress in EditingState (persistent editors)
    if ((state != QAbstractItemView::NoState
        && state != QAbstractItemView::EditingState)
        || !viewport->rect().contains(pos))
        return true;

    int i = itemDecorationAt(pos);
    if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) {
        if (viewItems.at(i).expanded)
            collapse(i, true);
        else
            expand(i, true);
        if (!isAnimating()) {
            q->updateGeometries();
            viewport->update();
        }
        return true;
    }
    return false;
}

我已将这些新文件包含在 SOURCES 和 HEADERS 的 .pro 文件中。正如上面的警告所说,我没有包含额外版本的构造函数。

更新:20110710_0926

这是导致错误的实际代码:

bool CustomTreeViewPrivate::expandOrCollapseItemAtPos(const QPoint &pos) {
  Q_Q(CustomTreeView);
  // we want to handle mousePress in EditingState (persistent editors)
  if ((state != QAbstractItemView::NoState
        && state != QAbstractItemView::EditingState)
        || !viewport->rect().contains(pos))
    return true;

  int i = itemDecorationAt(pos);
  if ((i != -1) && itemsExpandable && hasVisibleChildren(viewItems.at(i).index)) {
    if (viewItems.at(i).expanded)
      collapse(i, true);
    else
      expand(i, true);
    if (!isAnimating()) {
      q->updateGeometries();
      viewport->update();
    }
    return true;
  }
  return false;
}

更新 20110710_1339:

当我尝试编译(像以前一样使用 qmake)用 ..\src\gui\itemviews\ 中的 qtreeview 文件替换我的自定义类时,我收到了非常相似的警告。

c:\Qt\4.7.0\src\gui\itemviews\qtreeview.cpp(187) : warning C4273: 'QTreeView::QTreeView' : inconsistent dll linkage
    c:\qt\4.7.0\src\gui\itemviews\qtreeview.h(74) : see previous definition

来自“{ctor}”

这次尝试只出现一个错误,它与 (moc_qtreeview.cpp 是即时编译的?)有关:

C:\home\jetimms\code\projects\cashflow\debug\moc_qtreeview.cpp(95) : error C2491: 'QTreeView::staticMetaObject' : definition of dllimport static data member not allowed

不确定它是否告诉我任何与警告原因相关的信息。这是代码片段:

const QMetaObject QTreeView::staticMetaObject = {
    { &QAbstractItemView::staticMetaObject, qt_meta_stringdata_QTreeView,
      qt_meta_data_QTreeView, 0 }
};

我只是觉得奇怪的是,当我尝试使用 QTreeView 文件构建时,它们本身会出错。

无论如何,警告告诉我 QTreeView 的构造函数已经定义。我的所有头文件都有保护,所以我想不出它会认为 QTreeView 被定义了两次。

更新:20110710_1612

这里是 QTreeView.h 的开头,其中包含 QTreeView 的定义。请注意,它包含 QAbstractItemView.h 并继承自它。

#include <QtGui/qabstractitemview.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
#ifndef QT_NO_TREEVIEW
class QTreeViewPrivate;
class QHeaderView;
class Q_GUI_EXPORT QTreeView : public QAbstractItemView
{
  ...

以完全相同的方式,我的自定义类继承自它。

#include <QtGui/qabstractitemview.h>
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
QT_MODULE(Gui)
#ifndef QT_NO_TREEVIEW
class CustomTreeViewPrivate;
class QHeaderView;
class Q_GUI_EXPORT CustomTreeView : public QAbstractItemView
{

更新:20110710_1757

我突然意识到我从 QTreeView 复制的代码是用于库的,我不是在构建库,只是为我的应用程序构建 .exe。我从构造函数中删除了 Q_GUI_EXPORT(就在上面),我遇到的警告消失了。

现在我在处理 moc_CustomTreeView.cpp 文件时遇到错误(总共有 3 个错误,都像这个):

debug\moc_CustomTreeView.cpp(140) : error C2027: use of undefined type 'CustomTreeViewPrivate'
        c:\home\jetimms\code\projects\cashflow\debug\../CustomTreeView.hpp(12) : see declaration of 'CustomTreeViewPrivate'
debug\moc_CustomTreeView.cpp(140) : error C2227: left of '->_q_endAnimatedOperation' must point to class/struct/union/generic type

这是有问题的代码:

    case 16: d_func()->_q_endAnimatedOperation(); break;

不确定如何处理 moc_ 文件错误。 d_func() 抓取了 CustomTreeViewPrivate 实例,但是 moc_ 文件范围看不到。

更新:20110710_1757

看了一圈了解moc_文件和Qt的开发方式,找到了这两个。 KDE Techbase Policies/Library Code Policy 这个解释了为什么 Qt 代码是按原样编写的,使用私有类等。

我还找到了以下页面,该页面解释了当你的 moc_ 代码给你类似我上面的错误时该怎么做(重新运行 qmake)Using the Meta-Object Compiler (moc)。我试过了,上面的 moc_ 错误消失了,现在我看到了这些。

顺便说一下,我把 CustomTreeView 的名字改成了 SummaryDrillDownTreeView2。

SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall QAbstractItemViewPrivate::~QAbstractItemViewPrivate(void)" (??1QAbstractItemViewPrivate@@UAE@XZ) referenced in function __unwindfunclet$??0SummaryDrillDownTreeView2Private@@QAE@XZ$0
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: __thiscall QAbstractItemViewPrivate::QAbstractItemViewPrivate(void)" (??0QAbstractItemViewPrivate@@QAE@XZ) referenced in function "public: __thiscall SummaryDrillDownTreeView2Private::SummaryDrillDownTreeView2Private(void)" (??0SummaryDrillDownTreeView2Private@@QAE@XZ)
SummaryDrillDownTreeView2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall QAbstractItemViewPrivate::_q_rowsRemoved(class QModelIndex const &,int,int)" (?_q_rowsRemoved@QAbstractItemViewPrivate@@UAEXABVQModelIndex@@HH@Z)
SummaryDrillDownTreeView2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall QAbstractItemViewPrivate::_q_columnsInserted(class QModelIndex const &,int,int)" (?_q_columnsInserted@QAbstractItemViewPrivate@@UAEXABVQModelIndex@@HH@Z)
SummaryDrillDownTreeView2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall QAbstractItemViewPrivate::_q_layoutChanged(void)" (?_q_layoutChanged@QAbstractItemViewPrivate@@UAEXXZ)
SummaryDrillDownTreeView2.obj : error LNK2001: unresolved external symbol "public: virtual void __thiscall QAbstractItemViewPrivate::selectAll(class QFlags<enum QItemSelectionModel::SelectionFlag>)" (?selectAll@QAbstractItemViewPrivate@@UAEXV?$QFlags@W4SelectionFlag@QItemSelectionModel@@@@@Z)
SummaryDrillDownTreeView2.obj : error LNK2001: unresolved external symbol "public: virtual enum QAbstractItemView::DropIndicatorPosition __thiscall QAbstractItemViewPrivate::position(class QPoint const &,class QRect const &,class QModelIndex const &)const " (?position@QAbstractItemViewPrivate@@UBE?AW4DropIndicatorPosition@QAbstractItemView@@ABVQPoint@@ABVQRect@@ABVQModelIndex@@@Z)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: void __thiscall QAbstractItemViewPrivate::doDelayedItemsLayout(int)" (?doDelayedItemsLayout@QAbstractItemViewPrivate@@QAEXH@Z) referenced in function "public: void __thiscall SummaryDrillDownTreeView2::setRowHidden(int,class QModelIndex const &,bool)" (?setRowHidden@SummaryDrillDownTreeView2@@QAEXHABVQModelIndex@@_N@Z)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: void __thiscall QAbstractItemViewPrivate::interruptDelayedItemsLayout(void)const " (?interruptDelayedItemsLayout@QAbstractItemViewPrivate@@QBEXXZ) referenced in function "public: void __thiscall SummaryDrillDownTreeView2::expandAll(void)" (?expandAll@SummaryDrillDownTreeView2@@QAEXXZ)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: virtual void __thiscall QAbstractItemViewPrivate::_q_modelDestroyed(void)" (?_q_modelDestroyed@QAbstractItemViewPrivate@@UAEXXZ) referenced in function "public: virtual void __thiscall SummaryDrillDownTreeView2Private::_q_modelDestroyed(void)" (?_q_modelDestroyed@SummaryDrillDownTreeView2Private@@UAEXXZ)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: virtual class QList<struct QPair<class QRect,class QModelIndex> > __thiscall QAbstractItemViewPrivate::draggablePaintPairs(class QList<class QModelIndex> const &,class QRect *)const " (?draggablePaintPairs@QAbstractItemViewPrivate@@UBE?AV?$QList@U?$QPair@VQRect@@VQModelIndex@@@@@@ABV?$QList@VQModelIndex@@@@PAVQRect@@@Z) referenced in function "public: virtual class QList<struct QPair<class QRect,class QModelIndex> > __thiscall SummaryDrillDownTreeView2Private::draggablePaintPairs(class QList<class QModelIndex> const &,class QRect *)const " (?draggablePaintPairs@SummaryDrillDownTreeView2Private@@UBE?AV?$QList@U?$QPair@VQRect@@VQModelIndex@@@@@@ABV?$QList@VQModelIndex@@@@PAVQRect@@@Z)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: class QStyleOptionViewItemV4 __thiscall QAbstractItemViewPrivate::viewOptionsV4(void)const " (?viewOptionsV4@QAbstractItemViewPrivate@@QBE?AVQStyleOptionViewItemV4@@XZ) referenced in function "protected: void __thiscall SummaryDrillDownTreeView2::drawTree(class QPainter *,class QRegion const &)const " (?drawTree@SummaryDrillDownTreeView2@@IBEXPAVQPainter@@ABVQRegion@@@Z)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: struct QEditorInfo __thiscall QAbstractItemViewPrivate::editorForIndex(class QModelIndex const &)const " (?editorForIndex@QAbstractItemViewPrivate@@QBE?AUQEditorInfo@@ABVQModelIndex@@@Z) referenced in function "protected: virtual void __thiscall SummaryDrillDownTreeView2::drawRow(class QPainter *,class QStyleOptionViewItem const &,class QModelIndex const &)const " (?drawRow@SummaryDrillDownTreeView2@@MBEXPAVQPainter@@ABVQStyleOptionViewItem@@ABVQModelIndex@@@Z)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: void __thiscall QFramePrivate::updateStyledFrameWidths(void)" (?updateStyledFrameWidths@QFramePrivate@@QAEXXZ) referenced in function "public: void __thiscall SummaryDrillDownTreeView2Private::initialize(void)" (?initialize@SummaryDrillDownTreeView2Private@@QAEXXZ)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: virtual void __thiscall QAbstractItemViewPrivate::_q_columnsAboutToBeRemoved(class QModelIndex const &,int,int)" (?_q_columnsAboutToBeRemoved@QAbstractItemViewPrivate@@UAEXABVQModelIndex@@HH@Z) referenced in function "public: virtual void __thiscall SummaryDrillDownTreeView2Private::_q_columnsAboutToBeRemoved(class QModelIndex const &,int,int)" (?_q_columnsAboutToBeRemoved@SummaryDrillDownTreeView2Private@@UAEXABVQModelIndex@@HH@Z)
SummaryDrillDownTreeView2.obj : error LNK2019: unresolved external symbol "public: virtual void __thiscall QAbstractItemViewPrivate::_q_columnsRemoved(class QModelIndex const &,int,int)" (?_q_columnsRemoved@QAbstractItemViewPrivate@@UAEXABVQModelIndex@@HH@Z) referenced in function "public: virtual void __thiscall SummaryDrillDownTreeView2Private::_q_columnsRemoved(class QModelIndex const &,int,int)" (?_q_columnsRemoved@SummaryDrillDownTreeView2Private@@UAEXABVQModelIndex@@HH@Z)
debug\cashflow.exe : fatal error LNK1120: 16 unresolved externals

【问题讨论】:

  • 这个问题变得杂乱无章(这是我的错,因为我现在正在尝试两种方法。)我会将涉及从 QTreeView 继承的第二种方法移到另一个问题。

标签: qt class


【解决方案1】:

您应该使用继承来创建新类,而不是复制和粘贴。以这种方式维护的代码更少,即使是很小的 Qt 升级也不太可能中断。

【讨论】:

  • 这是我一开始尝试的,但是,我希望更改的 QTreeView 的方法不是虚拟的。我认为重新定义继承的非虚拟方法是违反惯例的。
  • 在不知道您要做什么的情况下,不可能说出来。确定要树视图吗?
  • 喂。在研究了上面的示例并再次查看 QTreeView 代码后,我才意识到通过重写 QTreeView drawRow 虚函数是可行的。 好吧,它仍然留下了让它与 QSQLTableModel 一起工作的问题。我希望它提交更改等。感谢您提供示例,Bill99。它迫使我审视真正的问题。
【解决方案2】:

我真的不能说 MSVC,但这些成员被声明为受 QAbstractTreeView 保护,就像错误所说的那样。您没有粘贴与错误相关的源代码,但我猜您正试图以某种方式使用那些不符合子类使用条件的受保护成员,也许是通过做一个实例并使用它?

编辑:

if ((state != QAbstractItemView::NoState

这是导致错误的实际行。在这里,您使用的是 QAbstractView 的受保护成员,这是不允许的,因为受保护成员纯粹被允许用于子类。

如果您的类继承了 QAbstractView,则可以使用该成员。

【讨论】:

  • 我将编辑并添加代码,但它几乎是 QTreeView 头文件中包含的内容(如上所示),即我可以分辨出没有显着差异。
  • 你是对的。我确实找到了一个名为 State 的受保护枚举,它在 QAbstractItemView.h 中设置了“NoState”类型。但是,QTreeView 和我的自定义类都继承自 QAbstractItemView,所以我认为他们都可以使用这个枚举,而不仅仅是 QTreeView,因为它似乎发生在我的第二次尝试中。我会将 QTreeView.h 文件中的类声明和几个进行中的宏添加到我上面的问题中。
  • 你需要像 CustomTreeView::NoState 一样使用它,而不是 QAbstr...::NoState,后者你可以以公共方式使用它,因为你不是该类的一部分。
  • 感谢您的提示。它确实消除了这个错误。有趣的是,QTreeView.cpp 中的代码将该行上方的 NoState 简单地引用为“NoState”,我认为它与 QTreeView::NoState 相同。 (它仍然没有解释为什么使用 /src/qui/ 中的 QTreeView 文件进行编译没有发现该错误,但是哦,好吧。)这是另一个谜。
  • 哦,我看到“NoState”本身的地方是在 CustomTreeView 方法中。 CustomTreeViewPrivate 方法必须以“CustomTreeView::”为前缀。这是有道理的。 CustomTreeView 通过 Q_DECLARE_PRIVATE 宏将 CustomTreeViewPrivate 声明为友元类。查看 qtreeview.cpp 中 QAbstractItemView::NoState 和“NoState”(本身)的实例,了解我的意思。 “NoState”(单独)只出现在 QTreeView 方法中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-02
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 2018-01-05
相关资源
最近更新 更多