我正在使用Qt开发应用程序,该应用程序高度利用JSON语言来通信,存储和加载不同类型的数据。我经常需要一个类似于Firebug JSON资源管理器的简单查看器来查看此数据。我已经有一个名为QJson的JSON解析器和序列化器。 (更新:我还在代码审查上发布了我的QJson类。)

我认为此代码段可能是公共感兴趣的,并且有一些未解决的问题(请参见下文)可以由您解决。如果问题得到解决或代码将在另一点得到改进,我个人将感到很高兴,但是我并不是真的需要它。因此,是否要查看/测试/改进代码并做出贡献取决于您(当然)。

功能/预览

QJsonView是一个QWidget,因此您可以将其嵌入任何其他小部件中。您可以将值设置为JSON序列化的字符串或分层QVariant。它使用HTML执行语法高亮显示,并使用QLabel显示此HTML。

示例用法如下所示:

QString data = "{"
                   "\"test\" :  [\"this\", \"is\", \"a\", "
                                 "{\"test\" : [\"with\", \"nested\", \"items\"]}],"
                   "\"types\" : [1337, 13.37, true, null]"
               "}";
QJsonView *jsonView = new QJsonView(this);
jsonView->setJsonValue(data);



预览:初始视图


您可以通过单击[+]符号来扩展JSON对象或数组(分别为QVariantMap或QVariantList)。这也可以从您的代码中完成。然后,这些条目将一个接一个地显示,如果它们是对象或数组,则可以再次展开。当前不支持从代码内部扩展嵌套元素。 br />
jsonView->expand();



预览:具有悬停效果的扩展视图


从上下文菜单中,用户可以复制JSON序列化到剪贴板的表示形式。如果对字符串执行此操作,则不会序列化而是将其复制为1:1。


预览:上下文菜单:复制到剪贴板


当显示为独立的QWidget时,它看起来像这样(此处:完全扩展):


预览:窗口化的,完全扩展的


已知问题/可能的改进

以下事情没有很好地实施,但是我没有时间和/或动力去做得更好:


通过QJsonView将字体系列设置为monospaced
自定义绘画事件期望字体大小固定。
间距期望字体大小固定。
使用悬停效果时,将操纵调色板并重置为父窗口小部件的面板。发生两个问题:(1)如果没有这样的父窗口小部件,请启动。 (2)如果您分配了一个自定义调色板,则当鼠标离开窗口小部件时,它将重置为父调色板。

qjsonview.h:

jsonView->setHoverEffects(true);


qjsonview.cpp:

#ifndef QJSONVIEW_H
#define QJSONVIEW_H

#include <QWidget>
#include <QVariant>
#include <QLabel>

/**
  Widget to display JSON or QVariant data.
  This widget will display any JSON-encoded string or a hierarchically nested QVariant tree in an expandable way.
  Per default, the whole data gets displayed in one single (non-wrapped) line, which can be expanded using a button
  if the JSON / QVariant data is of type JSON-array (QVariantList) or JSON-object (QVariantMap).
*/
class QJsonView : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(bool hoverEffects READ hoverEffects WRITE setHoverEffects);
    Q_PROPERTY(bool expandable READ isExpandable);
    Q_PROPERTY(bool expanded READ isExpanded WRITE setExpanded);


public:
    /**
      Constructor for QJsonView, taking the parent widget as a single argument.
    */
    explicit QJsonView(QWidget *parent = 0);

    /**
      Static and public helper function returning the HTML code which will be used to visualize the data (by applying syntax highlighting rules).
      This function is kept public since you may want to use this to layout some other QVariant data the same way like QJsonView does.
    */
    static QString variantToHtml(QVariant data);


signals:
    /**
      Emitted whenever this widget or one of its children has been expanded or collapsed.
      (The signal gets propagated to the root QJsonView object.)
    */
    void resized();


public slots:
    /**
      Set the value to be displayed to a QVariant value. The only supported QVariant-types are Invalid, Bool, Int, LongLong, List, Map. Any other types are untested!
    */
    void setValue(QVariant value);

    /**
      Set the value to be displayed to a JSON serialized string, which will be decoded before being viewed.
    */
    void setJsonValue(QString json);

    /**
      Enables or disables hover effects.
    */
    void setHoverEffects(bool enabled = true);

    /**
      Returns true if hover effects are enabled.
    */
    bool hoverEffects();

    /**
      Returns true if this QJsonView is expandable.
      This is the case for JSON-objects and JSON-arrays having at least one entry.
    */
    bool isExpandable();

    /**
      Returns true if this QJsonView is currently expanded.
    */
    bool isExpanded();

    /**
      Expands or collapses this view (convenient slot for expand() or collapse(), depending on the argument).
    */
    void setExpanded(bool expanded);

    /**
      Expands this view if it is expandable and not expanded.
    */
    void expand();

    /**
      Collapses this view if it is expanded.
    */
    void collapse();


protected:
    /**
      \reimp
    */
    void mousePressEvent(QMouseEvent *);
    /**
      \reimp
    */
    void paintEvent(QPaintEvent *);
    /**
      \reimp
    */
    void contextMenuEvent(QContextMenuEvent *);
    /**
      \reimp
    */
    void enterEvent(QEvent *);
    /**
      \reimp
    */
    void leaveEvent(QEvent *);

    /**
      Called by a child in order to inform this widget that the mouse cursor is now over the child instead of this widget.
    */
    void childEntered();

    /**
      Called by a child in order to inform this widget that the mouse cursor isn't over the child anymore.
    */
    void childLeaved();




private:
    // value to be displayed, as a QVariant
    QVariant v;
    // if this is no container type, this points to the QLabel representing the single value
    QLabel *lblSingle;
    // if this is a container type, these point to child widgets
    QList<QWidget*> childWidgets;
    // true if this is a container type and is currently in expanded view
    bool expanded;
    // true if hover effects are enabled
    bool hoverEffectsEnabled;

    // apply hover effect
    void hover();
    // revert hover effect
    void unhover();
};

#endif // QJSONVIEW_H


评论

通过Qt5,QJson模块被嵌入框架中。我从Qt模型视图的角度制作了一个treemodel。 github.com/dridk/QJsonmodel

JSON不是语言:)

您打算将哪个版本的c ++用于代码?

#1 楼

到目前为止,我只看到一些小建议。 。

根据您的C ++版本,有一些语法糖可以简化isExpandable中的地图迭代器;阅读有关isExpanded的文章。

否则,我看不到任何刺眼的事物。

#2 楼

我看到其他一些小问题:

此代码:


if(data.type() == QVariant::String || data.type() == QVariant::ByteArray)
    return "<span style=\"color: #006000\">\"" + Qt::escape(data.toString()) + "\"</span>";
else if(data.type() == QVariant::Int || data.type() == QVariant::LongLong)
    return "<span style=\"color: #800000\">" + Qt::escape(data.toString()) + "</span>";
else if(data.type() == QVariant::Double)
    return "<span style=\"color: #800080\">" + Qt::escape(data.toString()) + "</span>";
else if(data.type() == QVariant::Bool || data.isNull() || !data.isValid())



应该是switch(data.type())的用法default:部分的(拆分QVariant::Bool;它与null和invalid完全不同)。

但是,这段代码有很多重复。三个THEN子句之间的唯一区别是颜色以及是否引用了它们。它们的开始和结束都相同。也许使用一些类似于"<span style=\"color: %1\">%2%3%2</span>"的字符串格式化字符串


if(!first)
     ...
first = false;



尽量不要将条件语句放入循环内。这使得处理器难以流水线化。相反,请继续输入错误的信息作为后缀,然后在循环关闭后删除或修复最后一个信息。 (将", "更改为“]”,这很容易,因为您知道它在哪里)。同样,它应该使用之前的格式字符串来减少重复数据的数量。


if(i != map.begin())



同样,将字符串添加为后缀,然后删除多余的字符串。