Set line spacing in QTextEdit - c++

I want to set the line spacing of a QTextEdit.
It's no problem to get that information with
QFontMetrics::lineSpacing();
But how to set that?
I tried with StyleSheets, but that didn't work:
this->setStyleSheet("QTextEdit{ height: 200%; }");
or
this->setStyleSheet("QTextEdit{ line-height: 200%; }");
Partial solution:
Well, I've found a solution - not the way I wanted it, but at least it's simple and it gives nearly my intended behavior, enough for my proof of concept.
On every new line there's some linespacing. But if you just type until the text is automatically wrapped to a new line you wont have line-spacing between this two lines. This hack only works with text blocks, see the code.
Just keep in mind it's brute force and a ugly hack. But it provides some kind of line-spacing to your beautiful QTextEdit. Call it everytime your text changes.
void setLineSpacing(int lineSpacing) {
int lineCount = 0;
for (QTextBlock block = this->document()->begin(); block.isValid();
block = block.next(), ++lineCount) {
QTextCursor tc = QTextCursor(block);
QTextBlockFormat fmt = block.blockFormat();
if (fmt.topMargin() != lineSpacing
|| fmt.bottomMargin() != lineSpacing) {
fmt.setTopMargin(lineSpacing);
//fmt.setBottomMargin(lineSpacing);
tc.setBlockFormat(fmt);
}
}
}

The QFontMetrics contains (per the name) static properties that come from the font file. How wide a capital "C" is, etc. lineSpacing() gets you the natural distance in single-spacing that the person who designed the font encoded into the font itself. If you actually wanted to change that (you don't)...the somewhat complicated story of how is told here:
http://fontforge.sourceforge.net/faq.html#linespace
As for the line spacing in a QTextEdit...it looks (to me) like that is seen as one of the things that falls under Qt's extensibility model for specifying text "layouts":
http://doc.qt.io/qt-4.8/richtext-layouts.html
You would supply your own layout class to the QTextDocument instead of using the default. Someone tried it here but did not post their completed code:
http://www.qtcentre.org/threads/4198-QTextEdit-with-custom-space-between-lines

I know this is an old question, but I've spent a lot of time today trying to solve this for PyQt5 5.15.2. I'm posting my solution in case it is useful to others. The solution is for Python, but should be easily transferable.
The following code will change the line height to 150% for a populated QTextEdit widget in one go. Further editing will pick up the current block format, and continue applying it. I've found it to be very slow for large documents though.
textEdit = QTextEdit()
# ... load text into widget here ...
blockFmt = QTextBlockFormat()
blockFmt.setLineHeight(150, QTextBlockFormat.ProportionalHeight)
theCursor = textEdit.textCursor()
theCursor.clearSelection()
theCursor.select(QTextCursor.Document)
theCursor.mergeBlockFormat(blockFmt)

Applying blockformat to entire document rather than each line works.
QTextBlockFormat bf = this->textCursor().blockFormat();
bf.setLineHeight(lineSpacing, QTextBlockFormat::LineDistanceHeight) ;
this->textCursor().setBlockFormat(bf);

I have translated Jadzia626's code to C++ and it works. Here is the information about setLineHeight()
qreal lineSpacing = 35;
QTextCursor textCursor = ui->textBrowser->textCursor();
QTextBlockFormat * newFormat = new QTextBlockFormat();
textCursor.clearSelection();
textCursor.select(QTextCursor::Document);
newFormat->setLineHeight(lineSpacing, QTextBlockFormat::ProportionalHeight);
textCursor.setBlockFormat(*newFormat);

Related

Oracle Apex, line break in Gantt Chart Row Label

I'm very new to Oracle Apex and currently I want to use and customize Gantt charts. What I want to achieve it to show line breaks in the row-labels. Currently every newline character gets cut out and I am not sure where this happens and how I can prevent this.
The marked text contains newline characters. Don't be confused by the <br>, I just tests if this does the trick.
I just want to show more some information in the for each row. If there is another more elegant way, it would be very nice to give a tip.
Update:
I did some research and found a very nice example on a similar topic, in this case to create a custom tooltip https://youtu.be/2rZAIR_0tNg?t=2532.
I wanted to do the same thing for the row_axis label renderer, but nothing gets visualized.
The render function I use:
function custom_row_axis_label_renderer(data_context){
var row_axis_label_elem = document.createElement("g");
$("row_axis_label_elem").addClass("custom_row_axis_label");
row_axis_label_elem.innerHTML = '<text font-size="14px">Hello World</text>';
console.log(row_axis_label_elem);
return row_axis_label_elem;
}
The rendered element kind of exists, but it's get the size 0x0 from somewhere.
Am I missing something here?
Regards,
Nik
Meanwhile I found the solution on how to build a custom renderer. The main part I didn't new is that you NEED to pass x and y coordinates to have the new label to be rendered correctly. I found a proper example the the oracle forum, but unfortunately I can't find the link anymore to give credit to the original example.
Here is my code. It creates two text elements below each other to achieve a mocked line break and it adds a yellow icon. Of course you can use the data_context object to access the actual label. Add this part in the "Function and Global Variable Declaration
" part of your page:
custom_row_axis_label_renderer = function (data_context){
var row_axis_label_elem = document.createElementNS("http://www.w3.org/2000/svg", "g");
var upper_text = document.createElementNS("http://www.w3.org/2000/svg", "text");
var lower_text = document.createElementNS("http://www.w3.org/2000/svg", "text");
var icon_node = document.createElementNS("http://www.w3.org/2000/svg", "circle");
upper_text.textContent = "Hello";
upper_text.setAttribute("dominant-baseline","text-before-edge");
upper_text.setAttribute("class","oj-gantt-row-label");
upper_text.setAttribute("font-size","14px");
upper_text.setAttribute("text-anchor","end");
upper_text.setAttribute("x","220");
upper_text.setAttribute("y","5");
lower_text.textContent = "World";
lower_text.setAttribute("dominant-baseline","text-before-edge");
lower_text.setAttribute("class","oj-gantt-row-label");
lower_text.setAttribute("font-size","14px");
lower_text.setAttribute("text-anchor","end");
lower_text.setAttribute("x","220");
lower_text.setAttribute("y","25");
icon_node.setAttribute("cx","240");
icon_node.setAttribute("cy","25");
icon_node.setAttribute("r","8");
icon_node.setAttribute("class","u-color-7");
row_axis_label_elem.appendChild(upper_text);
row_axis_label_elem.appendChild(lower_text);
row_axis_label_elem.appendChild(icon_node);
return row_axis_label_elem;
}
Also you need to set the renderer of the row-axis-label. I also made the rows and task a little bit bigger to have enough space for two lines of text in the label. Add this in the "JavaScript Initialization Code" in the attriutes of you chart:
function( options ){
options.rowAxis.label = {renderer : custom_row_axis_label_renderer};
options.rowDefaults = {height : 60};
options.taskDefaults = {height: 40};
return options;
}

How to indent multiline text behind lists in QMLs TextEdit

In QML Im using a TextEdit item for a text editor with highlighter code running behind it (QSyntaxHighlighter). When the user types a dash (-), it will be recognised by the highlighter code and formatted (like Markdown). But additionally I want the text to be indented behind the dash, when it is multiline. Just like it behaves with HTML lists.
This is how it looks like right now:
This is how I want it (the text aligns properly behind the dash):
I know this can indent the text:
QTextCursor cursor(currentBlock());
QTextBlockFormat textBlockFormat = currentBlock().blockFormat();
textBlockFormat.setIndent(1);
cursor.setBlockFormat(textBlockFormat);
An idea is to indent all the text by default and un-indent the lines with a dash or similar, but couldn't quite figure out yet how to achieve it.
Any other ideas?
Ok apparently there is also a list styling option. This is how you can change the style of a block:
QTextBlock block = textDoc->findBlockByNumber(i);
QTextCursor cursor(block);
cursor.beginEditBlock();
QTextListFormat::Style style = QTextListFormat::ListDecimal;
QTextBlockFormat blockFmt = cursor.blockFormat();
QTextListFormat listFmt;
if (cursor.currentList()) {
listFmt = cursor.currentList()->format();
} else {
listFmt.setIndent(blockFmt.indent() + 1);
blockFmt.setIndent(0);
cursor.setBlockFormat(blockFmt);
}
listFmt.setStyle(style);
cursor.createList(listFmt);
cursor.endEditBlock();
This could be used in a slot linking to the contentsChange signal from QTextDocument or in a highlighter.

How to display Red Squiggly Lines in CRichEditCtrl in MFC

I am working on implementing spellchecker in an MFC application. What I want to do is display red lines under incorrectly spelled words.
I found one example where it is done but it works only for a simple edit box because it can simply use the edit controls default font for doing calculations to draw the squiggly lines. But it does not work for a rich edit control as in rich edit control it is possible that different words can have different fonts. In this case the example I found draws lines at incorrect places.
Please let me know if someone has already done this for CRichEditCtrl? (it must handle text of any font/size that is present in the rich edit control.)
Thanks,
Sachin
CHARFORMAT2 format;
SecureZeroMemory(&format, sizeof(CHARFORMAT2));
format.cbSize = sizeof(CHARFORMAT2);
format.dwMask = CFM_UNDERLINE|CFM_UNDERLINETYPE;
format.dwEffects = CFE_UNDERLINE;
format.bUnderlineType = CFU_UNDERLINEWAVE | 0x50;
SendMessage(EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&format);
I hope this will get the underline in your text
Use the EM_SETCHARFORMAT message:
CHARFORMAT2 format;
SecureZeroMemory(&format, sizeof(CHARFORMAT2));
format.cbSize = sizeof(CHARFORMAT2);
format.dwMask = CFM_UNDERLINE|CFM_UNDERLINETYPE;
format.dwEffects = CFE_UNDERLINE;
format.bUnderlineType = CFU_UNDERLINE
window->SendMessage(EM_EXSETSEL, NULL, (LPARAM)&range);
window->SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&format);

How to format the selected text in a QTextEdit by pressing a button

I want to format a selected text in a QTextEdit by clicking a button. For axample I want to make it bold if it is not-bold, or not-bold if it is bold. Please help me with an example.
EDIT:
Actually I have found already a code - qt demo for text editor which does what I need:
void
MyTextEdit::boldText(bool isBold) //this is the SLOT for the button trigger(bool)
{
QTextCharFormat fmt;
fmt.setFontWeight(isBold ? QFont::Bold : QFont::Normal);
mergeFormatOnWordOrSelection(fmt);
}
void
MyTextEdit::mergeFormatOnWordOrSelection(const QTextCharFormat &format)
{
QTextCursor cursor = m_textEdit->textCursor();
if (!cursor.hasSelection())
cursor.select(QTextCursor::WordUnderCursor);
cursor.mergeCharFormat(format);
m_textEdit->mergeCurrentCharFormat(format);
}
But I can't understand what returnes the textCursor() method, and how the merging of properties is being done? Just some formats are being changed, some of them stay constant. How mergeCharFormat function understands what to change and what to leave as is. Please explain me just these 2 things.
Thanks.
The textCursor() returns a textCursor that contains the position of the cursor you use in the textEdit, see QTextCursor in Qt classes. So by selecting the text that is contained by the cursor start and end position, you have the text that is currently highlited.
As for the mergeCharFormat, I guess that it is used to apply a new state (bold, italic, underlined) and to keep the existing ones. Say your text is already underlined and you apply bold, you would want to keep both.
Hope this helps.

Changing text in RaphaelJS

How may I change the text in a RaphaelJS-created text node? First, I am creating a new element with a text string with Raphael, and at some later point I would like to change this text. It's easier for me if I do not have to reinitialize the element as there will be a whole host of attributes attached that will be a pain to recreate. Is there a way to do this? I've got my logic below, but it doesn't work; it's there just to provide extra insight as to what I'm trying to achieve.
Thanks
var R = Raphael("graph-o-matic", 1000, 1000);
var title = R.text( 10, 10, 'original text');
...
title.text.innerHTML = 'nifty new text here';
Try this:
title.attr({text: 'nifty new text here'});