【问题标题】:Custom text (code) areas in QTextEditQTextEdit 中的自定义文本(代码)区域
【发布时间】:2012-11-11 03:43:07
【问题描述】:

我有兴趣创建一个行为类似于代码区域的文本对象类型(继承 QTextObjectInterface):

  • 独特的背景
  • 边框
  • 等宽字体
  • 可编辑的内容
  • 实例需要可识别代码,以便可以提取其中的内容(将代码与周围内容分开)
  • 保存/加载(从常规 html 文件)
  • 语法突出显示会是一个加分项,但实际上并不是必需的

文档的其他区域需要以通常的方式运行(字体属性可编辑、颜色可编辑等)。


Qt 提供了an example 用于使用QTextEdit 实现自定义文本对象。这看起来很难,因为新的文本对象不能利用 QTextEdit / QTextDocument 中的现有基础设施。

QTextObject

不同类型对象的基类,可以将QTextDocument 的各个部分组合在一起

因此继承它可能是一种选择,但它在 Qt SDK 包中的源文件和 Google 搜索都没有显示有用的信息。

QTextFrame 继承 QTextObject 因此,如果要找到有关此路径的一些提示,它可能是一个可行的基类。


在一个简单的 HTML 文件中,所有这些(语法高亮除外)都很容易。 QTextEdit 将 html 作为输入并能够导出 html,但在此过程中结构丢失。

<code class="code-sample">
  int i = 0;
</code>

QWebView 是只读的,顺便说一下。它宣传:

部分 HTML 文档可以通过 HTML 元素的 contenteditable 属性进行编辑。


可能还有其他平台可以轻松使用,但文本编辑器需要在 Qt Creator 中作为插件使用,因此使用 Qt 框架是有意义的。

底线:如何在QTextEdit 小部件中实现代码区域?


后期编辑:

  • 使用来自主干的 Qt sdk(将自身标识为 4.8.4)
  • 来自主干的 Qt Creator (Qt Creator 2.6.81)

【问题讨论】:

    标签: c++ qt custom-controls qtextedit qtextdocument


    【解决方案1】:

    我发现使用 QTextEdit / QTextDocument 可以实现这一点。我能想到的最简单的实现在这个答案中给出,以供未来寻求者参考。

    请注意,保存/加载需要自定义为常规 .toHtml() 不会保留所需的信息。

    插入代码块很简单:

    QTextFrame * frame;
    
    frame = cursor.insertFrame( code_block_format_ );
    connect( frame, SIGNAL( destroyed() ),
      this, SLOT( codeBlockDeleted() ) );
    code_blocks_.append( frame );
    

    注意你可以保存在类中的两个变量:

    QTextFrameFormat code_block_format_;
    QList<const QTextFrame*> code_blocks_;
    

    我们需要框架的格式保持一致和独特。它可以在构造函数中初始化为:

    code_block_format_.setBackground( QBrush( Qt::yellow ) );
    code_block_format_.setBorder( 1 );
    code_block_format_.setBorderStyle( QTextFrameFormat::BorderStyle_Inset);
    code_block_format_.setMargin( 10 );
    code_block_format_.setPadding( 4 );
    

    我们需要这个列表,以便我们可以判断某个帧是否是代码框。由于所有继承 QTextObject 的对象都需要由 QTextDocument::createObject() 创建,因此我们不能简单地将 QTextFrame 子类化(实际上我认为我们可以,但还不确定)。

    现在可以按照通常的方式将代码内容与其他内容分开:

    for ( it = frame->begin(); !(it.atEnd()); ++it ) {
      child_frame = it.currentFrame();
      child_block = it.currentBlock();
      if ( child_frame != NULL )
      {
        if ( code_blocks_.contains( frame ) )
        {
          /* ... */
        }
      }
    } /* for ( it = frame->begin(); !(it.atEnd()); ++it ) */
    

    但请注意,为简洁起见,这被过度简化了。需要考虑嵌套框架。

    如果您对完整实施感兴趣,请查看git repository(正在进行中,2012 年 11 月)。

    【讨论】:

      猜你喜欢
      • 2014-06-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-13
      相关资源
      最近更新 更多