How to insert hidden text in QLabel? - qt

In a QLabel, I have some rich text with some superscript (e.g. kg m-3). If this text is copied and pasted in a plain text editor, the pasted text is kg m-3. I would like the pasted text to be kg m^-3. Is there any way to insert ^ as a hidden text in-between m and -3? I looked at some hidden text tags in rich text format but these don't seem to work in Qt.
#include <QtWidgets/QLabel>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QApplication>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QMainWindow *w = new QMainWindow;
QLabel *l = new QLabel(w);
l->setText("kg m<sup>-3</sup>");
l->setTextInteractionFlags(Qt::TextSelectableByMouse);
w->setCentralWidget(l);
w->show();
app.exec();
}

I solved this using the following line:
l->setText("kg m<html><font style="font-size:1px">^</font></html><sup>-3</sup>");
Using font-size:0px gives an error.

Without inserting the '^' character as 'hidden text' you could probably connect the signal QPlainTextEdit::textChanged() to a slot function that processes the text. To process the text i would suggest a simple RegExp.
All of this would look something like (Warning: code NOT tested):
Connect the signal to the slot function (the function to process the string has to be declared as a slot)
QObject::connect(plainTextEdit, SIGNAL(textChanged()), this, SLOT(processRichString());
Define the function for the processing as follows
void MyClass::processRichString()
{
QString strToProcess = label->toPlainText();
QRegExp rx("<sup>(.*)</sup>");
strToProcess.replace(rx, "^\\1");
label->setPlainText(strToProcess);
}

Related

How to continue text editing after formatting changes of QGraphicsTextItem?

I am trying to make changes (font changes) to a QGraphicsTextItem that is editable.
I am trying to change formatting of fragments of text, or the formatting applied at typing point (if I set text bold, the text I type after that action at cursor position would be bold).
Setting formatting for text fragments works - but I can't find a way to return the focus correctly to the item.
I can show the caret at the right position, but I can't type in the box unless I actually click in box (even though it seems hat I should be able to).
Simple sample (for some reason it crashes on closing program but I don't care about that since I am testing the text class, not the main program):
header: mytextitem.h
#include <QGraphicsTextItem>
class MyTextItem : public QGraphicsTextItem
{
Q_OBJECT
public:
MyTextItem();
~MyTextItem() {}
public slots:
void setItemBold(const int b);
};
mytextitem.cpp
#include "mytextitem.h"
#include <QTextCursor>
MyTextItem::MyTextItem()
{
setPlainText("ABCD");
setFont(QFont("Arial", 20));
setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
setTextInteractionFlags(Qt::TextEditorInteraction);
}
void MyTextItem::setItemBold(const int b)
{
int _weight = (b != 0) ? QFont::Bold : QFont::Normal;
QTextCursor _cursor = textCursor();
//int p = _cursor.position(); // this won't help
QTextCharFormat _format = _cursor.charFormat();
_format.setFontWeight(_weight);
_cursor.setCharFormat(_format);
//_cursor.setPosition(p, QTextCursor::KeepAnchor); // makes no difference on allowing me to type, but I can make the cursor move
//_cursor.movePosition(QTextCursor::NoMove, QTextCursor::KeepAnchor, 0); // makes no difference but I just thought some action might
setTextCursor(_cursor);
setFocus(Qt::MouseFocusReason);
// grabKeyboard(); // does nothing
}
main.cpp
#include <QApplication>
#include <QGraphicsView>
#include <QGridLayout>
#include <QtWidgets>
#include <QCheckBox>
#include "mytextitem.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene(-20, -20, 150, 100);
QGraphicsView view(&scene);
QWidget widget;
QGridLayout layout(&widget);
layout.addWidget(&view, 0, 0);
QCheckBox bold("Bold");
layout.addWidget(&bold, 0, 1);
MyTextItem* item = new MyTextItem();
scene.addItem(item);
QObject::connect(&bold, SIGNAL(stateChanged(int)), item, SLOT(setItemBold(int)));
view.ensureVisible(scene.sceneRect());
widget.show();
return a.exec();
}
Editing the item is possible only if clicking in the box.
Assuming that I am already in the box (editing), and I push the "Bold" checkbox, I expect to be able to continue editing - type in the box - but even though I try to
set focus (which places the blinking text cursor in the box),
set position for cursor (I can move it, or select things... that works but I want to keep current position and selection)
grab keyboard - seems to do nothing
nothing seems to return me to the box so I continue typing (with the new font setting).
How can I get the QTextCursor or anything else to allow me to keep editing the text ?
You need to focus on QGraphicsView after format change. You can't focus on QGraphicsTextItem because it isn't QWidget.

Set text direction for QLabel?

Is there a way to set the text direction for a QLabel? I've got a situation in which I have QLabel objects whose text is only punctuation, and I want that to be displayed either in RTL or LTR format. (For instance, parentheses or quotation marks need to reverse depending on the text direction.) I've tried calling QLabel::setLayoutDirection, but to no effect.
#include <QApplication>
#include <QLabel>
int main(int argc, char **argv)
{
QApplication app (argc, argv);
QLabel label(" :  «");
label.setFont( QFont("Times New Roman", 72) );
label.setLayoutDirection( Qt::RightToLeft );
// label.setLayoutDirection( Qt::LeftToRight );
label.show();
return app.exec();
}
A workaround at this point is to prepend 0x202E ("Right-to-Left Override") to the string, but that's obviously a bit clunky.
label.setAlignment(Qt::AlignRight);

How to have a QTextBrowser to display contents of a QTextEdit?

I am trying to connect QTextEdit to QTextBrowser, so the text browser widget outputs what is entered in text edit widget. As a signal I used textChanged(), and as a slot I used setText(QString). And these two don't have same parameters.
If I used QLineEdit instead of QTextEdit, in that case there is textChanged(QString) function which is compatible with the slot,but I need to make it work with QTextEdit. Here is the code:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtWidgets>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QWidget * mainWidget=new QWidget(this);
ui->setupUi(this);
QTextEdit * mainTextEdit=new QTextEdit();
QTextBrowser * textDisplay=new QTextBrowser();
connect(mainTextEdit,SIGNAL( textChanged() ),
textDisplay,SLOT( setText(QString) ) );
QHBoxLayout * Alayout=new QHBoxLayout();
Alayout->addWidget(mainTextEdit);
Alayout->addWidget(textDisplay);
mainWidget->setLayout(Alayout);
setCentralWidget(mainWidget);
}
MainWindow::~MainWindow()
{
delete ui;
}
Thankfully, the QTextEdit and QTextBrowser are views onto a QTextDocument model. So, you can simply set the editor's document on the browser. QTextBrowser::setDocument is semantically equivalent to QAbstractItemView::setModel:
textDisplay->setDocument(mainTextEdit->document());
In Qt, there are really two basic model classes: QAbstractItemModel and QTextDocument. A QTextDocument is a model in its own model-view framework. We simply set another view onto the document that the editor operates on. The editor allows modifications to the model, the browser doesn't. It's no different from using the same model on two QListViews, etc.
A QTextEditor is a view with a default model (document). You can replace that default model with one from another view, or even with one that you yourself provide. You could have multiple editors all displaying the same QTextDocument document and allowing editing of it, in parallel. You can also have multiple browsers doing the same.
Complete example:
#include <QApplication>
#include <QTextEdit>
#include <QTextBrowser>
#include <QHBoxLayout>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget window;
QHBoxLayout layout(&window);
QTextEdit edit;
QTextBrowser browser;
layout.addWidget(&edit);
layout.addWidget(&browser);
browser.setDocument(edit.document());
window.show();
return a.exec();
}
I would do it in the following way:
Declare the pointers to the text edit and text browser widgets as member variables in the class,
Create a slot onTextChanged() in MainWindow class that will be called as soon as the text edit is changed and setup the connection as:
connect(mainTextEdit, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
Implement the onTextChanged() slot in the following way:
MainWindow::onTextChanged()
{
QString text = mainTextEdit->toPlainText();
textDisplay->setPlainText(text);
}

QTextBrowser - how to identify image from mouse click position

I'm using a QTextBrowser to display rich text including a number of images, each of them specified with a HTML <img> tag and added as resources using QTextDocument::addResource().
What I'd like to be able to do is, in a context menu handler (i.e. with a mouse click position available), identify the image that the click was over. It's possible to tell whether the click is over an image, because cursorForPosition(event->pos()).block().text() returns a string starting with Unicode 0xFFFC. Unfortunately the same string is returned for every image in the view.
It's possible to get all of the formats in use with QTextDocument::allFormats(), identify which of those are image formats, and get their image resource name. Unfortunately there seems to be no way to get their actual display position or bounding rectangle.
From the documentation:
Inline images are represented by an object replacement character (0xFFFC in Unicode) which has an associated QTextImageFormat. The image format specifies a name with setName() that is used to locate the image.
You can use charFormat().toImageFormat().name() on the cursor to extract the image's URL. Below is a self-contained example. There are two noteworthy details:
The cursor will sometimes point one character prior to the image. Thus the workaround; it seems necessary for both Qt 4.8.5 and 5.1.1.
The pop-up menus should be shown asynchronously so as not to block the rest of the application. The example code provided in the documentation is a source of bad user experience and should be considered an evil abomination. All widgets can automatically delete themselves when they get closed, so the menus won't leak. A QPointer is used only to demonstrate this fact. It tracks the menu's lifetime and nulls itself when the menu deletes itself.
#include <QApplication>
#include <QTextBrowser>
#include <QImage>
#include <QPainter>
#include <QMenu>
#include <QContextMenuEvent>
#include <QTextBlock>
#include <QPointer>
#include <QDebug>
class Browser : public QTextBrowser
{
QPointer<QMenu> m_menu;
protected:
void contextMenuEvent(QContextMenuEvent *ev) {
Q_ASSERT(m_menu.isNull()); // make sure the menus aren't leaking
m_menu = createStandardContextMenu();
QTextCursor cur = cursorForPosition(ev->pos());
QTextCharFormat fmt = cur.charFormat();
qDebug() << "position in block" << cur.positionInBlock()
<< "object type" << cur.charFormat().objectType();
if (fmt.objectType() == QTextFormat::NoObject) {
// workaround, sometimes the cursor will point one object to the left of the image
cur.movePosition(QTextCursor::NextCharacter);
fmt = cur.charFormat();
}
if (fmt.isImageFormat()) {
QTextImageFormat ifmt = fmt.toImageFormat();
m_menu->addAction(QString("Image URL: %1").arg(ifmt.name()));
}
m_menu->move(ev->globalPos());
m_menu->setAttribute(Qt::WA_DeleteOnClose); // the menu won't leak
m_menu->show(); // show the menu asynchronously so as not to block the application
}
};
void addImage(QTextDocument * doc, const QString & url) {
QImage img(100, 100, QImage::Format_ARGB32_Premultiplied);
img.fill(Qt::white);
QPainter p(&img);
p.drawRect(0, 0, 99, 99);
p.drawText(img.rect(), url);
doc->addResource(QTextDocument::ImageResource, QUrl(url), img);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextDocument doc;
Browser browser;
doc.setHtml("<img src=\"data://image1\"/><br/><img src=\"data://image2\"/>");
addImage(&doc, "data://image1");
addImage(&doc, "data://image2");
browser.show();
browser.setDocument(&doc);
return a.exec();
}

How to find global position of text cursor?

I would like to execute a QMenu object at the position of text cursor in a QPlainTextEdit. My problem is that QTextCursor is only define by its position in the Text (index of the character).
How can I find global position of the QTextCursor? Should I use an other object than QTextCursor in order to find the position of the text cursor where I want to open my QMenu?
Thank you by advance.
I've never tried myself, but doesn't QPlainTextEdit::cursorRect() work? It should give you position of the cursor in viewport coordinates. You can then get the viewport using viewport() and map the local position to global using viewport()->mapToGlobal().
I have found similar query to your in some online forum and here's someone suggested the output as
Note: Reference from http://www.unix.com/unix-linux-applications/81388-read-position-mouse-cursor.html, Author of below posting is daggilli, registered user of UNIX online forums. Credit of below posting in its complete form goes to daggilli.
This is the complete code for a Qt application I threw together in about ten minutes (called crosshair) which displays the current mouse coordinates in a window. You might be able to pull enough out of it to be useful. This is Qt 3.1, but Qt 4 is not a great deal different. You will need the Qt development libraries, not just the runtimes. The code comprises two files, crosshair.h and crosshair.cpp.
crosshair.h:
Code:
#ifndef CROSSHAIR_H
#define CROSSHAIR_H
#include <qwidget.h>
#include <qstring.h>
#include <qlabel.h>
#include <qevent.h>
class Crosshair : public QLabel
{
Q_OBJECT
public:
Crosshair(QWidget *parent=0);
protected:
void mousePressEvent(QMouseEvent *);
private:
QTimer *timer;
private slots:
void timerfire();
};
#endif
crosshair.cpp:
Code:
#include <qapplication.h>
#include <qpushbutton.h>
#include <qtimer.h>
#include <qcursor.h>
#include <iostream>
#include "crosshair.h"
using namespace std;
int main(int argc,char **argv)
{
QApplication a(argc,argv);
Crosshair mousepos;
a.setMainWidget(&mousepos);
mousepos.show();
return a.exec();
}
Crosshair::Crosshair(QWidget *parent) : QLabel(parent)
{
setIndent(20);
resize(100,30);
move(1200,200);
setText("0,0");
timer=new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(timerfire()));
timer->start(50,false);
}
void Crosshair::mousePressEvent(QMouseEvent *)
{
qApp->quit();
}
void Crosshair::timerfire()
{
QPoint p=QCursor::pos();
this->setText(QString().sprintf("%d,%d",p.x(),p.y()));
}
To build this, put both files in a directory called crosshair. cd to that directory and type
Code:
qmake -project
qmake
make
This does nothing more complex than inherit from a QLabel, set a timer to run 20x a second, grab the current cursor coordinates and write them into the label's text. Clicking in the window closes it. I use it for fixing up alignment bugs in JavaScript when I'm laying out objects.
You could open a file in the Crosshair class's constructor to store your data, and use gettimeofday(2) to get a timestamp. Nothing says Qt has to run in GUI mode (you can tell it explicitly not to in the QApplication constructor).
Qt from Trolltech: http://doc.trolltech.com

Resources