qtextedit - resize to fit - c++

I have a QTextEdit which act as "displayer" (editable to false). The text it displays is wordwrapped. Now I do wish to set the height of this textbox so that the text fits exactly (while also respecting a maximum height).
Basically the widget (in the same vertical layout) below the layout should get as much space as possible.
How can this be achieved most easily?

I found a pretty stable, easy solution using QFontMetrics!
from PyQt4 import QtGui
text = ("The answer is QFontMetrics\n."
"\n"
"The layout system messes with the width that QTextEdit thinks it\n"
"needs to be. Instead, let's ignore the GUI entirely by using\n"
"QFontMetrics. This can tell us the size of our text\n"
"given a certain font, regardless of the GUI it which that text will be displayed.")
app = QtGui.QApplication([])
textEdit = QtGui.QPlainTextEdit()
textEdit.setPlainText(text)
textEdit.setLineWrapMode(True) # not necessary, but proves the example
font = textEdit.document().defaultFont() # or another font if you change it
fontMetrics = QtGui.QFontMetrics(font) # a QFontMetrics based on our font
textSize = fontMetrics.size(0, text)
textWidth = textSize.width() + 30 # constant may need to be tweaked
textHeight = textSize.height() + 30 # constant may need to be tweaked
textEdit.setMinimumSize(textWidth, textHeight) # good if you want to insert this into a layout
textEdit.resize(textWidth, textHeight) # good if you want this to be standalone
textEdit.show()
app.exec_()
(Forgive me, I know your question is about C++, and I'm using Python, but in Qt they're pretty much the same thing anyway).

Unless there is something particular to the capabilities of a QTextEdit that you need, a QLabel with word wrap turned on will do exactly what you want.

Current size of the underlying text can be available via
QTextEdit::document()->size();
and I believe that using this we could resize the widget accordingly.
#include <QTextEdit>
#include <QApplication>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextEdit te ("blah blah blah blah blah blah blah blah blah blah blah blah");
te.show();
cout << te.document()->size().height() << endl;
cout << te.document()->size().width() << endl;
cout << te.size().height() << endl;
cout << te.size().width() << endl;
// and you can resize then how do you like, e.g. :
te.resize(te.document()->size().width(),
te.document()->size().height() + 10);
return a.exec();
}

In my case, I put my QLabel inside a QScrollArea. And if you are keen, you combine both and make your own widget.

Speaking of Python, I actually found .setFixedWidth( your_width_integer ) and .setFixedSize( your_width, your_height ) quite useful. Not sure if C has similar widget attributes.

Related

How do I address the screen on a linux terminal?

I am teaching myself C++ and currently run the latest Fedora.
On a Windows command prompt you can address the screen location.
I am led to the believe that a Linux command terminal works, effectively, like characters printed to a piece of paper. i.e. You can't go "up" from where you are.
However, when you install in Linux, there is a progress bar (in text) which doesn't appear to print a new line each time with the increase of progress.
Also, take for example raspbi-config in which you can tab/arrow up and down a "menu" and select "OK" and "Cancel" etc.
How does one achieve this?
Can this then be used to do simple text graphics applications in Linux like one can do under Windows?
Any help would be appreciated.
Uberlinc.
Coding in C++.
General non-gui apps which simply "cout" to the stdout.
Only found one or two examples which show a progress bar that prints out to the same line, but are not clear to me.
On a basic level, there are two things that enable these kinds of things on a Linux (or other POSIX) terminal: ASCII control characters and ANSI escape codes.
For a simple progress bar, it's enough to know how wide the screen is and to have a way to get back to the beginning of the current terminal line. This can be one by reading the environment variable $COLUMNS with getenv and by printing the ASCII control character \r. A very bare-bones and unbeautified example is
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
int main() {
// Default screen width
int width = 80;
// Get screenwidth from environment
char const *envwidth = getenv("COLUMNS");
if(envwidth != nullptr) {
std::istringstream(envwidth) >> width;
}
// save some space for numeric display
width -= 10;
for(int i = 1; i < width; ++i) {
std::cout
<< '\r' // go back to start of line
<< std::string(i, '.') // progress bar
<< std::string(width - i, ' ') // padding
<< "| " << i << '/' << width // numeric display
<< std::flush; // make the progress bar instantly visible
// pretend to work
usleep(100000);
}
}
For more involved terminal "graphics,", there are ANSI escape codes. These allow you to set foreground and background color, move around on the screen at will, and a few other things, by printing special character sequences to stdout. For example,
std::cout << "\x1b[10;20HHello, world." << std::flush;
will print Hello, world. at position 10, 20 on the screen.
There is also the ncurses library that provides more high-level terminal UI functionality (windows, dialogs, that sort of thing). They use ANSI escape codes under the hood, but it's normally nicer to use that than to roll your own UI framework.

Qt 5.7 \n behavior

In a Qt 5.7 Console Application:
#include <QCoreApplication>
#include <QtDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QString s = "MDJ\nTest.\n";
qDebug() << "MDJ\nTest.\n";
qDebug() << s;
/* Prints:
MDJ
Test.
MDJ\nTest.\n
*/
return a.exec();
}
i.e. the \n works as expected in a direct debug print, but is treated as just two plain characters when debug printing a (supposedly identical content) variable.
I'm encountering similar problems in Qt 5.7 Widget Applications as well.
I've searched the documentation, stackoverflow, and Qt Centre and I've been unable to discover what I'm doing wrong.
Could somebody please point me to a solution for this?
The docs give you hints:
<< QString()
Normally, QDebug prints the string inside quotes and transforms non-printable characters to their Unicode values (\u1234).
To print non-printable characters without transformation, enable the noquote() functionality. Note that some QDebug backends might not be 8-bit clean.
vs.
<< const char*
Writes the '\0'-terminated string, s, to the stream and returns a reference to the stream. The string is never quoted nor transformed to the output, but note that some QDebug backends might not be 8-bit clean.
Solution: qDebug().noquote() << "some\nspecial\nchars\n\tincluded"

Change the size of a help window to fit the text

I want to change the size of the help window to fit the size of the text, but don't know how to proceed.
Here is my code :
QTextEdit *help = new QTextEdit(this);
help->setWindowFlags(Qt::Window);
help->setReadOnly(true);
////
QFile file(":/help.txt");
QTextStream stream ( &file );
QString line;
if (!file.open (QIODevice::ReadOnly))
{
//some error report
}
while( !stream.atEnd() ) {
line = stream.readLine();
help->append(line);
}
file.close();
help->show();
You need some layout information about your text because, in theory, it could be rendered in one really, really long line.
So, I would aim for some target width of the text while all text being wider than that will be wrapped. Now, what you need is the height for that kind of text.
My suggestion would be that you use a QTextDocument, set the width as described above, insert all the text and get the size using QTextDocument::size. That way, you get the measures and can resize your window to those (adding margin, padding etc., of course).

Increasing spaces between words,ordering words in columns

Is there possibility to easily increase spaces between words in QTextEdit?
My only idea is to set space key event to insert more whitespaces, but i would better like some setting parameters solution?
Is there way to set words in columns in text edit. What I mean:
first word wordabc abcd
second word worda egdsa
third word wordb dafdd
With this I have no idea for now.
The QTextEdit can render html, so you could use table elements to achieve what you want.
#include <QtGui/QApplication>
#include <QtGui/QTextEdit>
int main(int argc, char *argv[])
{
QString html = "<html><body><table>";
html += "<tr><td>first word</td><td>wordabc</td><td>abcd</td></tr>";
html += "<tr><td>second word</td><td>worda</td><td>egdsa</td></tr>";
html += "<tr><td>third word</td><td>wordb</td><td>dafdd</td></tr>";
html += "</table></body></html>";
QApplication app(argc, argv);
QTextEdit textEdit;
textEdit.setHtml(html);
textEdit.show();
return app.exec();
}
You could also apply styling to the table for example by adding the width attribute to the td tag to push columns apart from each other.
You can apply QTextCharFormat to your text and use QTextCharFormat::setFontWordSpacing ( qreal spacing )

QString, remove labels and content?

message.Text() is a QString.
I want to remove some text.
The text can be:
Normal: "This is a text"
With a label: "<label1>something</label1>This is a text"
First, I find if the text has the label:
!message.Text().contains("<label1>", Qt::CaseInsensitive))
So, if it has, I want to remove the first part, to have a normal text "This is a text".
I tried this:
first=message.Text().indexOf("<label1>");
last=message.Text().lastIndexOf("</label1>");
message.Text().remove(first,last);
But I got Compiler Error C2663.
I also know that the message.Text().remove(QChar('<label1'), Qt::CaseInsensitive); is another way to do it. But in my case, the part between the label is unkwnow.
It can be <label1>something</label1> or <label1>oisdioadj</label> or <label1>7</label1>....
Any idea?
Regards.
Try the following:
#include <iostream>
using std::cout; using std::endl;
#include <QString>
int main()
{
QString message = "<label1>something</label1>This is a test";
const QString labelClose = "</label1>";
const int labelCloseSize = labelClose.size();
cout << "message: " << qPrintable(message) << endl;
const int closePosition = message.lastIndexOf(labelClose);
QString justText = message.remove(0, closePosition + labelCloseSize);
cout << "just text: " << qPrintable(justText) << endl;
}
My advice here: keep things simple in your code, it will help making things simple in your head.
It seems what you want to achieve is more related to strings, than to label.
I suggest you get the text from your label, then work on it independently, then associate it back to your label:
QString text = message.text();
/* Do whatever you need to do here with text */
message.setText(text);
Also, the error you're having is probably due to the fact that you try to modify directly message.text() which is a const reference: obviously you can't modify something that is const.
I believe what you try to achieve can be done using QString::replace(). You'll have to use regular expressions for that, so if you're not familiar with it, it might be difficult.