Question

I am interested in creating a text object type (inheriting QTextObjectInterface) that behaves like a code area:

  • distinctive background
  • border
  • fixed-width font
  • editable content
  • the instances need to be identifiable to code, so that content inside them may be extracted (separate code from surrounding content)
  • saving / loading (from regular html files)
  • syntax highlighting would be a plus, but is not really required

The other areas of the document would need to behave the usual way (font properties editable, colors editable, etc).


Qt provides an example for implementing custom text objects with QTextEdit. This looks like the hard way, since new text object can't make use of the existing infrastructure inside QTextEdit / QTextDocument.

QTextObject is

a base class for different kinds of objects that can group parts of a QTextDocument together

so inheriting it may be a choice, but neither its source files in Qt SDK package nor Google searches revealed helpful information.

QTextFrame inherits QTextObject so, again, it may be a feasible base class if some hints about this path are to be found.


In an simple HTML file all this (except syntax highlighting) would be easy. QTextEdit takes html as input and is able to export html, but the structure is lost in the process.

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

QWebView is read-only, by the way. It advertises that:

Parts of HTML documents can be editable for example through the contenteditable attribute on HTML elements.


There may be other platforms where this is readily available, but the text editor needs to be used inside Qt Creator as a plug-in, so using Qt framework makes sense.

Bottom line: how does one implement code areas in a QTextEdit widget?


Later edits:

  • using Qt sdk from trunk (identifies itself as 4.8.4)
  • Qt Creator from trunk (Qt Creator 2.6.81)
Was it helpful?

Solution

I have found out that implementing this is possible using QTextEdit / QTextDocument.The most simple implementation that I can think of is presented in this answer for the reference of future seeker.

Notice that saving/loading needs to be customised as regular .toHtml() will not preserve the information needed.

Inserting a code block is simple:

QTextFrame * frame;

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

notice the two variables that you can save in the class:

QTextFrameFormat code_block_format_;
QList<const QTextFrame*> code_blocks_;

We need the format for frame to be consistent and distinctive. It mat be initialised in constructor to something like:

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 );

We need the list so we can tell if a certain frame is a code box or not. Since all objects inheriting QTextObject need to be created by QTextDocument::createObject() we can't simply subclass the QTextFrame (actually I think we can, but not sure yet).

Now separating the code content from the rest may be done the usual way:

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 ) */

but notice that this is over-simplified for the sake of brevity. One needs to take into account nested frames.

If you are interested in a full implementation check out the git repository (work in progress, November 2012).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top