Getting formatting of empty lines - qt

I am a bit confused about how the QTextBlock::iterator works:
The documentation shows clear examples of how to use it, on normal text:
QTextBlock::iterator it;
for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
QTextFragment currentFragment = it.fragment();
if (currentFragment.isValid())
processFragment(currentFragment);
}
I encounter problems on empty lines of text. On those lines,
it = currentBlock.begin();
if(it.atEnd())
// returns true !
I still need to be able to read formatting (char and block)
Should I check the block at end ? Is there any other way to test blocks with nothing except the new line ?
My current solution: check the last iterator as well, separate from the "for" loop, and also test if it is the last block in the document (if I try to get the fragment of the last block in the document, the program crashes).
It seems that I am working against the documentation... How should I get the formatting of empty lines ?
Edit:
My old solution:
QTextBlock currentBlock = document()->findBlock(selStart);
QTextBlock lastBlock = document()->lastBlock();
while (currentBlock.isValid())
{
QTextBlock::iterator it = currentBlock.begin();
if(currentBlock != lastBlock && it.atEnd())
{
QTextFragment currentFragment = it.fragment();
if (currentFragment.isValid())
{
QTextCharFormat f = currentFragment.charFormat();
// do something
}
}
else
{
for (; !(it.atEnd()); ++it)
{
QTextFragment currentFragment = it.fragment();
if (currentFragment.isValid())
{
// do stuff
QTextCharFormat f = currentFragment.charFormat();
// do stuff
}
}
}
}
New solution based from answer from Tarod eliminates one test (but seems to have less consistent behavior)
QTextBlock currentBlock = document()->findBlock(selStart);
QTextBlock lastBlock = document()->lastBlock();
while (currentBlock.isValid())
{
QTextBlock::iterator it = currentBlock.begin();
if(currentBlock != lastBlock && it.atEnd())
{
QTextCharFormat f = currentBlock.charFormat();
// do something
}
else
{
for (; !(it.atEnd()); ++it)
{
QTextFragment currentFragment = it.fragment();
if (currentFragment.isValid())
{
// do stuff
QTextCharFormat f = currentFragment.charFormat();
// do stuff
}
}
}
}
I still need to check against last block and avoid using it if empty, sometimes it crashes.

I think the problem is you're just iterating over a QTextBlock and reading the contents of its text fragments. In this case, for an empty QTextBlock, as you proved, currentBlock.begin() == it.atEnd() because the QTextBlock has not any text fragments.
You should iterate over all the document text blocks, get the required information and, if you need to, iterate over each one to read the sequence of text fragments.
In the following example the block #3 it's an empty line (\n\n). You won't see the line qDebug() << "I am a QTextBlock with text!" printed although we still have information about this text block thanks to QTextBlockFormat and QTextCharFormat.
main.cpp
#include <QApplication>
#include "graphicstextitem_3.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GraphicsTextItem_3 g3;
g3.show();
return a.exec();
}
graphicstextitem_3.h
#ifndef GRAPHICSTEXTITEM_3_H
#define GRAPHICSTEXTITEM_3_H
#include <QMainWindow>
class QGraphicsScene;
class QGraphicsView;
class QGraphicsTextItem;
class GraphicsTextItem_3 : public QMainWindow
{
Q_OBJECT
public:
explicit GraphicsTextItem_3(QMainWindow *parent = 0);
private:
QGraphicsScene *scene;
QGraphicsView *view;
QGraphicsTextItem *item;
signals:
public slots:
};
#endif // GRAPHICSTEXTITEM_3_H
graphicstextitem_3.cpp
#include "graphicstextitem_3.h"
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsTextItem>
#include <QTextCursor>
#include <QTextDocument>
#include <QTextBlock>
#include <QDebug>
GraphicsTextItem_3::GraphicsTextItem_3(QMainWindow *parent) : QMainWindow(parent)
{
scene = new QGraphicsScene(this);
view = new QGraphicsView(scene);
item = new QGraphicsTextItem("Block 0\n Block 1\n Block 2\n\n Block 4");
item->setTextInteractionFlags(Qt::TextEditorInteraction);
QFont f = item->font();
f.setPointSize(30);
item->setFont(f);
QTextDocument* doc = item->document();
for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next())
{
QTextBlockFormat block_format = it.blockFormat();
QTextCharFormat char_format = it.charFormat();
qDebug() << "*** Block number: " << it.blockNumber()
<< " with text: " << it.text();
qDebug() << "* Block format info: "
<< " leftMargin: " << block_format.leftMargin()
<< " rightMargin: " << block_format.rightMargin()
<< " topMargin: " << block_format.topMargin()
<< " bottomMargin: " << block_format.bottomMargin()
<< " lineHeight: " << block_format.lineHeight();
qDebug() << "* Char format info: "
<< " pointSize: " << char_format.font().pointSize()
<< " fontFamily: " << char_format.font().family();
QTextBlock::iterator tb_it = it.begin();
if (tb_it.atEnd())
{
qDebug() << "it.begin() == tb_it.atEnd()";
/* The application crashes if we get the fragment */
// tb_it.fragment();
}
for (tb_it = it.begin(); !(tb_it.atEnd()); ++tb_it) {
QTextFragment currentFragment = tb_it.fragment();
if (currentFragment.isValid())
{
qDebug() << "I am a QTextBlock with text!"
<< " Out of here empty QTextBlock!"
<< " You - shall not - pass!";
}
}
}
scene->addItem(item);
view->setFixedSize(640, 480);
this->setCentralWidget(view);
}

Here is the pseudo code (which works for me). In short, when the method atEnd() returns TRUE, then you append a new line.
QTextEdit * pwTextEdit = whatever your source;
QTextDocument * poDocument = pwTextEdit->document();
QTextBlock oTextBlock = poDocument->begin();
while (oTextBlock.isValid())
{
QTextBlock::iterator oTextBlockIterator(oTextBlock.begin());
while (TRUE)
{
if (oTextBlockIterator.atEnd())
{
// Append your '\n' here
break;
}
QTextFragment oTextFragment = oTextBlockIterator.fragment();
QString sText = oTextFragment.text();
// Process the text from sText
oTextBlockIterator++;
}
oTextBlock = oTextBlock.next();
}

Related

Qt QCompleter do not pop out

Problem description
  I want to be able to recognize the corresponding Chinese person name and complete the prompt by entering a short Chinese phonetic alphabet.
  For example, I have a map (("lvbu", "吕布"), ("lvbuwei", "吕不韦")) , then enter "lv" or "bu",The completer should pop up "吕布" and "吕不韦", but it seems that the stringlist must contain the content currently being entered to complete the prompt. The completer cannot recognize the mapping relationship.
  How can I solve it? I can hardly find a solution on the Internet because it involves Chinese.
My code
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "Pinyin2Hanzi/myPinyin.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QString N = "吕布 吕不韦 南宫问天";
QStringList Names = N.split(" ");
// qDebug() << Names;
ui->comboBox->addItem("");
ui->comboBox->addItems(Names);
ui->comboBox->lineEdit()->setClearButtonEnabled(true);
CreateCompleter(Names, ui->comboBox->lineEdit());
ui->comboBox->setMaxCount(ui->comboBox->count()); //这行代码可以防止按回车键自动往combobox里addItem
}
MainWindow::~MainWindow()
{
delete ui;
}
std::map<std::string, std::vector<QString>> pinyin2NameMap; // This is a private variable
// 把所有人名按照拼音分类并存入map中
void MainWindow::PreparePinyinData(const QStringList &names)
{
for (auto & name : names)
{
QString outFristPy,outFullPy;
getComPingyinForStr(name, outFristPy, outFullPy);
// QString pinyin = GetPinyin(name);
QString pinyin = outFullPy;
// qDebug() <<"FristPy:" << outFristPy << "FullPy:" << outFullPy;
// qDebug() <<"pinyin:" << pinyin;
// QString fist, last;
// myNameSplit(name, last, fist); // 自动切分 [姓、名]
// last = getNamePingyin(last, true); // 获取 [姓] 的拼音
// fist = getNamePingyin(fist, false);// 获取 [名] 的拼音
// qDebug() << name + " : " + last + " " + fist << endl;
pinyin2NameMap[pinyin.toStdString()].push_back(name);
}
}
// 根据输入的拼音进行匹配并获取提示列表
QStringList MainWindow::GetMatchByPinyin(const QString &pinyin)
{
QStringList result;
if("" == pinyin.trimmed()){
return QStringList();
}
for (const auto & iter : pinyin2NameMap){
if (iter.first.find(pinyin.toStdString()) != std::string::npos){
auto vec = iter.second;
for(const auto & name : vec){
result.append(name);
}
}
}
return result;
}
// 创建QCompleter并设置自动补全模型
void MainWindow::CreateCompleter(const QStringList &names, QLineEdit *lineEdit)
{
PreparePinyinData(names);
QStringListModel *model = new QStringListModel(names);
QCompleter *completer = new QCompleter(model, lineEdit);
completer->setCaseSensitivity(Qt::CaseInsensitive);
completer->setFilterMode(Qt::MatchContains);
completer->setCompletionMode(QCompleter::PopupCompletion);
lineEdit->setCompleter(completer);
connect(lineEdit, &QLineEdit::textEdited, [this,completer,lineEdit, model](const QString &text)
{
QStringList matchList = GetMatchByPinyin(text);
qDebug() << "listmodel:" << matchList;
// QString N = "lv不bu 可lvbuwei nan够gongwentian";
// QStringList matchList = N.split(" ");
model->setStringList(matchList);
completer->setModel(model);
completer->complete();
});
}

QSqlTableModel: Where can I get whether a row is marked as removed

If I call removeRows on records which were read from the database a ! will be displayed in the first column of the tableView.
The only thing which I would like to achieve is that this row will not be displayed in the view. I tried it with QSortFilterProxyModel but I don't know where I can get the flag which is used to display the ! in the first column. Is there a way to set a filter in QSortFilterProxyModel that it only contains the rows which don't have this flag?
From where does the view take the information, that the removed row is marked with a "!" ? This information might be hidden somewhere in the model, but I cannot find out where.
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
m_ui(new Ui::MainWindow),
m_model(new QSqlTableModel(this)),
m_proxyModel(new QSortFilterProxyModel(this))
{
m_ui->setupUi(this);
m_model->setTable("test");
m_model->setEditStrategy(QSqlTableModel::OnManualSubmit);
m_model->select();
m_proxyModel->setSourceModel(m_model);
m_ui->tableView->setModel(m_proxyModel);
qDebug() << "Select : Row count:" << m_model->rowCount();
connect(m_ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &MainWindow::on_selectionChanged);
}
MainWindow::~MainWindow()
{
delete m_ui;
}
void MainWindow::on_pushButtonNewRecord_clicked()
{
qDebug() << "New Record";
m_record = m_model->record();
m_record.setValue("firstname", "john");
m_record.setValue("lastname", "doe");
m_record.setValue("email", "john.doe#email.com");
m_model->insertRecord(-1, m_record);
qDebug() << "New Record : Row count:" << m_model->rowCount();
}
void MainWindow::on_pushButtonRemoveRow_clicked()
{
qDebug() << "Remove Row";
if (m_row >= 0) {
m_proxyModel->removeRow(m_row);
qDebug() << "Remove Record: Row count:" << m_model->rowCount();
}
for (int i = 0; i < m_model->rowCount(); i++) {
qDebug() << "\n";
qDebug() << "Remove Row: index :" << m_model->index(i, 0);
qDebug() << "Remove Row: isValid:" << m_model->index(i, 0).isValid();
qDebug() << "Remove Row: isDirty:" << m_model->isDirty(m_model->index(i, 0));
qDebug() << "Remove Row: flags :" << m_model->index(i, 0).flags();
qDebug() << "Remove Row: data :" << m_model->index(i, 0).data(Qt::DisplayRole);
qDebug() << "Remove Row: heaader:" << m_model->headerData(i, Qt::Vertical);
QVariant verticalHeader = m_model->headerData(i, Qt::Vertical);
if (verticalHeader == "!") {
qDebug() << "Deleted";
}
//qDebug() << m_model->record(i);
}
}
void MainWindow::on_pushButtonSubmit_clicked()
{
qDebug() << "Submit";
m_model->submitAll();
m_model->select();
}
void MainWindow::on_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
Q_UNUSED(deselected)
if (!selected.isEmpty()) {
m_row = selected.indexes().first().row();
}
}
You have to implement a QSortFilterProxyModel that filters the rows that are Dirty and whose vertical header text is "!", You must also call the invalidate() method to force the application of the filter.
dirtyfilterproxymodel.h
#ifndef DIRTYFILTERPROXYMODEL_H
#define DIRTYFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
#include <QSqlTableModel>
class DirtyFilterProxyModel : public QSortFilterProxyModel
{
public:
using QSortFilterProxyModel::QSortFilterProxyModel;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if(QSqlTableModel *source_model = qobject_cast<QSqlTableModel *>(sourceModel())){
QModelIndex ix = source_model->index(source_row, 0, source_parent);
QString row_header_item = source_model->headerData(source_row, Qt::Vertical, Qt::DisplayRole).toString();
return !(source_model->isDirty(ix) && row_header_item == QLatin1String("!"));
}
return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
}
};
#endif // DIRTYFILTERPROXYMODEL_H
mainwindow.h
// ...
class DirtyFilterProxyModel;
// ...
class MainWindow : public QMainWindow
{
// ...
private:
Ui::MainWindow *m_ui;
DirtyFilterProxyModel *m_proxyModel;
// ...
mainwindow.cpp
#include "dirtyfilterproxymodel.h"
// ...
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
m_ui(new Ui::MainWindow),
m_model(new QSqlTableModel(this)),
m_proxyModel(new DirtyFilterProxyModel(this))
{
// ...
}
void MainWindow::on_pushButtonNewRecord_clicked()
{
// ...
m_model->insertRecord(-1, m_record);
m_proxyModel->invalidate();
}
// ...
void MainWindow::on_pushButtonRemoveRow_clicked()
{ if (m_row >= 0) {
m_proxyModel->removeRow(m_row);
m_proxyModel->invalidate();
}
}

Different color for different word in QML TextArea without RichText

I am trying to make a code editor and want to change color of keywords in TextArea after user types a keyword. I read that textFormat:Text.StyledText could change color without changing the whole text to Html but adding tags to the text is not changing the color. Here I used bold tag for code
Code -
TextArea{
Layout.alignment: Qt.AlignTop
id:ta
selectByMouse: true
selectByKeyboard: true
Layout.fillWidth:true
Layout.fillHeight: true
font.pointSize: 12
textMargin: 16
font.family:"courier new"
persistentSelection: true
textFormat: Text.StyledText
onActiveFocusChanged: {
menu_trig=0
}
onTextChanged: {
// check text
console.log(ta.text.slice(0,ta.text.length-3))
if(ta.text.slice(ta.text.length-3,ta.text.length)=="def")
{
ta_text.text=ta.text.substring(0,ta.text.length-3)+"<b>def</b>"}
}
Keys.onPressed: {
if(codeChange==0)
{codeChange=1
mainWindow.title=title.toString()+" *"}
}
Component.onCompleted: forceActiveFocus()
// color:"orange"}
You have to use a QSyntaxHighlighter and because it seems to me you are trying to make it an editor for python I have implemented based on this post.
syntaxhighlighter.h
#ifndef SYNTAXHIGHLIGHTER_H
#define SYNTAXHIGHLIGHTER_H
#include <QRegularExpression>
#include <QSyntaxHighlighter>
class QQuickTextDocument;
class HighlightingRule
{
public:
HighlightingRule(const QString &patternStr, int n, const QTextCharFormat &matchingFormat);
QString originalRuleStr;
QRegularExpression pattern;
int nth;
QTextCharFormat format;
};
class PythonSyntaxHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
PythonSyntaxHighlighter(QTextDocument *parent);
const QTextCharFormat getTextCharFormat(const QString &colorName, const QString &style = QString());
void initializeRules();
bool matchMultiline(const QString &text, const QRegularExpression &delimiter, const int inState, const QTextCharFormat &style);
protected:
void highlightBlock(const QString &text);
private:
QStringList keywords;
QStringList operators;
QStringList braces;
QHash<QString, QTextCharFormat> basicStyles;
QList<HighlightingRule> rules;
QRegularExpression triSingleQuote;
QRegularExpression triDoubleQuote;
};
class SyntaxHighlighterHelper: public QObject
{
Q_OBJECT
Q_PROPERTY(QQuickTextDocument *quickdocument READ quickdocument WRITE setQuickdocument NOTIFY quickdocumentChanged)
public:
SyntaxHighlighterHelper(QObject *parent=nullptr):
QObject(parent),
m_quickdocument(nullptr)
{}
QQuickTextDocument *quickdocument() const;
void setQuickdocument(QQuickTextDocument *quickdocument);
signals:
void quickdocumentChanged();
private:
QQuickTextDocument *m_quickdocument;
};
#endif // SYNTAXHIGHLIGHTER_H
syntaxhighlighter.cpp
#include "syntaxhighlighter.h"
#include <QQuickTextDocument>
HighlightingRule::HighlightingRule(const QString &patternStr, int n, const QTextCharFormat &matchingFormat)
{
originalRuleStr = patternStr;
pattern = QRegularExpression(patternStr);
nth = n;
format = matchingFormat;
}
PythonSyntaxHighlighter::PythonSyntaxHighlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{
keywords = QStringList() << "and" << "assert" << "break" << "class" << "continue" << "def" <<
"del" << "elif" << "else" << "except" << "exec" << "finally" <<
"for" << "from" << "global" << "if" << "import" << "in" <<
"is" << "lambda" << "not" << "or" << "pass" << "print" <<
"raise" << "return" << "try" << "while" << "yield" <<
"None" << "True" << "False";
operators = QStringList() << "=" <<
// Comparison
"==" << "!=" << "<" << "<=" << ">" << ">=" <<
// Arithmetic
"\\+" << "-" << "\\*" << "/" << "//" << "%" << "\\*\\*" <<
// In-place
"\\+=" << "-=" << "\\*=" << "/=" << "%=" <<
// Bitwise
"\\^" << "\\|" << "&" << "~" << ">>" << "<<";
braces = QStringList() << "{" << "}" << "\\(" << "\\)" << "\\[" << "]";
basicStyles.insert("keyword", getTextCharFormat("blue"));
basicStyles.insert("operator", getTextCharFormat("red"));
basicStyles.insert("brace", getTextCharFormat("darkGray"));
basicStyles.insert("defclass", getTextCharFormat("black", "bold"));
basicStyles.insert("brace", getTextCharFormat("darkGray"));
basicStyles.insert("string", getTextCharFormat("magenta"));
basicStyles.insert("string2", getTextCharFormat("darkMagenta"));
basicStyles.insert("comment", getTextCharFormat("darkGreen", "italic"));
basicStyles.insert("self", getTextCharFormat("black", "italic"));
basicStyles.insert("numbers", getTextCharFormat("brown"));
triSingleQuote.setPattern("'''");
triDoubleQuote.setPattern("\"\"\"");
initializeRules();
}
void PythonSyntaxHighlighter::initializeRules()
{
for(const QString & currKeyword: keywords)
{
rules.append(HighlightingRule(QString("\\b%1\\b").arg(currKeyword), 0, basicStyles.value("keyword")));
}
for(const QString & currOperator: operators)
{
rules.append(HighlightingRule(QString("%1").arg(currOperator), 0, basicStyles.value("operator")));
}
for(const QString &currBrace: braces)
{
rules.append(HighlightingRule(QString("%1").arg(currBrace), 0, basicStyles.value("brace")));
}
// 'self'
rules.append(HighlightingRule("\\bself\\b", 0, basicStyles.value("self")));
// Double-quoted string, possibly containing escape sequences
// FF: originally in python : r'"[^"\\]*(\\.[^"\\]*)*"'
rules.append(HighlightingRule("\"[^\"\\\\]*(\\\\.[^\"\\\\]*)*\"", 0, basicStyles.value("string")));
// Single-quoted string, possibly containing escape sequences
// FF: originally in python : r"'[^'\\]*(\\.[^'\\]*)*'"
rules.append(HighlightingRule("'[^'\\\\]*(\\\\.[^'\\\\]*)*'", 0, basicStyles.value("string")));
// 'def' followed by an identifier
// FF: originally: r'\bdef\b\s*(\w+)'
rules.append(HighlightingRule("\\bdef\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
// 'class' followed by an identifier
// FF: originally: r'\bclass\b\s*(\w+)'
rules.append(HighlightingRule("\\bclass\\b\\s*(\\w+)", 1, basicStyles.value("defclass")));
// From '#' until a newline
// FF: originally: r'#[^\\n]*'
rules.append(HighlightingRule("#[^\\n]*", 0, basicStyles.value("comment")));
// Numeric literals
rules.append(HighlightingRule("\\b[+-]?[0-9]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+[lL]?\b'
rules.append(HighlightingRule("\\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?0[xX][0-9A-Fa-f]+[lL]?\b'
rules.append(HighlightingRule("\\b[+-]?[0-9]+(?:\\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\\b", 0, basicStyles.value("numbers"))); // r'\b[+-]?[0-9]+(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?\b'
}
void PythonSyntaxHighlighter::highlightBlock(const QString &text)
{
for(const HighlightingRule &rule: rules) {
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext()) {
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
setCurrentBlockState(0);
bool isInMultilne = matchMultiline(text, triSingleQuote, 1, basicStyles.value("string2"));
if (!isInMultilne)
isInMultilne = matchMultiline(text, triDoubleQuote, 2, basicStyles.value("string2"));
}
bool PythonSyntaxHighlighter::matchMultiline(const QString &text, const QRegularExpression &delimiter, const int inState, const QTextCharFormat &style)
{
QRegularExpressionMatch match;
int startIndex = 0;
if (previousBlockState() != 1)
startIndex = text.indexOf(delimiter);
while (startIndex >= 0) {
QRegularExpressionMatch match = delimiter.match(text, startIndex);
int endIndex = match.capturedStart();
int commentLength = 0;
if (endIndex == -1) {
setCurrentBlockState(1);
commentLength = text.length() - startIndex;
} else {
commentLength = endIndex - startIndex
+ match.capturedLength();
}
setFormat(startIndex, commentLength, style);
startIndex = text.indexOf(delimiter, startIndex + commentLength);
}
return currentBlockState() == inState;
}
const QTextCharFormat PythonSyntaxHighlighter::getTextCharFormat(const QString &colorName, const QString &style)
{
QTextCharFormat charFormat;
QColor color(colorName);
charFormat.setForeground(color);
if (style.contains("bold", Qt::CaseInsensitive))
charFormat.setFontWeight(QFont::Bold);
if (style.contains("italic", Qt::CaseInsensitive))
charFormat.setFontItalic(true);
return charFormat;
}
QQuickTextDocument *SyntaxHighlighterHelper::quickdocument() const
{
return m_quickdocument;
}
void SyntaxHighlighterHelper::setQuickdocument(QQuickTextDocument *quickdocument)
{
m_quickdocument = quickdocument;
if(m_quickdocument){
new PythonSyntaxHighlighter(m_quickdocument->textDocument());
}
}
main.cpp
// ...
qmlRegisterType<SyntaxHighlighterHelper>("Foo", 1, 0, "SyntaxHighlighterHelper");
// ...
main.qml
// ...
import Foo 1.0
// ...
SyntaxHighlighterHelper{
quickdocument: ta.textDocument
}
TextArea{
id:ta
anchors.fill: parent
selectByMouse: true
selectByKeyboard: true
font.pointSize: 12
textMargin: 16
font.family:"courier new"
persistentSelection: true
textFormat: Text.StyledText
tabStopDistance: 4*fontMetrics.advanceWidth(" ")
FontMetrics {
id: fontMetrics
font.family: ta.font
}
}
// ...
The example can be found here.

QT communicate through QProcess with Notepad.exe

I would like to start notepad.exe from QT and then for example write "Hello Notepad" to the input-area of Notepad from QT!
What I managed to do, is starting notepad from QT. But what ever I try I can't fill in the text in the Notepad-textedit area.
.h-File:
#ifndef MATLABPROCESS
#define MATLABPROCESS
#include "QObject"
#include <QProcess>
#include <QDebug>
class MatlabProcess : public QObject{
Q_OBJECT
public:
// enum State {IDLE, ERRORX, WRITING};
//State myState;
QProcess* myProcess;
explicit MatlabProcess (QObject* parent = 0) : QObject(parent) {
myProcess = new QProcess(this);
// myState = IDLE;
QObject::connect(myProcess, SIGNAL(readyReadStandardOutput()), SLOT(writing_stream()));
}
Q_INVOKABLE bool startMatlab(){
// QString program = "\"C:/Program Files (x86)/MATLAB/R2012a/bin/matlab.exe\"";
QString program = "\"C:/FlorianK/notepad.exe\"";
myProcess->start(program);
if (!myProcess->waitForStarted(-1)) return false;
qDebug() << "program started";
return true;
}
Q_INVOKABLE bool stopMatlab(){
//TODO
return false;
}
Q_INVOKABLE bool writeSomething(){
QByteArray script = "Hello Notepad\n";
qDebug() << myProcess->write(script);
qDebug() << myProcess->waitForFinished();
QByteArray result = myProcess->readAll();
qDebug() << "result: " + result;
}
private slots:
void writing_stream() {
if (!myProcess) return;
QTextStream out(stdout);
out << myProcess->readAllStandardOutput() << endl;
}
};
#endif // MATLABPROCESS
Because I want to do this stuff from qml, I registered this class in main.cpp
qmlRegisterType<MatlabProcess>("com.myself", 1, 0, "MatlabProcess");
From qml I call startMatlab() and than writeSomething(). The qt-output for "writesomething" will be
14
than 30seconds will happen nothing and program freezes than following lines will be printed in Qt-output
false
"result: "
The Notepad-text-area stays empty.

how to pick two points from viewer in PCL

I would like to pick two points from pointcloud and return coordinates of the two points. In order to get down to the problem, I have used the PointPickingEvent of PCL, and written a class containing pointcloud, visualizer, and a vector to store selected points. My code:
#include <pcl/point_cloud.h>
#include <pcl/PCLPointCloud2.h>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/common/io.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/vtk_lib_io.h>
#include <pcl/visualization/pcl_visualizer.h>
using namespace pcl;
using namespace std;
class pickPoints {
public:
pickPoints::pickPoints () {
viewer.reset (new pcl::visualization::PCLVisualizer ("Viewer", true));
viewer->registerPointPickingCallback (&pickPoints::pickCallback, *this);
}
~pickPoints () {}
void setInputCloud (PointCloud<PointXYZ>::Ptr cloud)
{
cloudTemp = cloud;
}
vector<float> getpoints() {
return p;
}
void simpleViewer ()
{
// Visualizer
viewer->addPointCloud<pcl::PointXYZ>(cloudTemp, "Cloud");
viewer->resetCameraViewpoint ("Cloud");
viewer->spin();
}
protected:
void pickCallback (const pcl::visualization::PointPickingEvent& event, void*)
{
if (event.getPointIndex () == -1)
return;
PointXYZ picked_point1,picked_point2;
event.getPoints(picked_point1.x,picked_point1.y,picked_point1.z,
picked_point2.x,picked_point2.y,picked_point2.z);
p.push_back(picked_point1.x); // store points
p.push_back(picked_point1.y);
p.push_back(picked_point1.z);
p.push_back(picked_point2.x);
p.push_back(picked_point2.y);
p.push_back(picked_point2.z);
//cout<<"first selected point: "<<p[0]<<" "<<p[1]<<" "<<p[2]<<endl;
//cout<<"second selected point: "<<p[3]<<" "<<p[4]<<" "<<p[5]<<endl;
}
private:
// Point cloud data
PointCloud<pcl::PointXYZ>::Ptr cloudTemp;
// The visualizer
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer;
// The picked point
vector<float> p;
};
int main()
{
//LOAD;
PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ> ());
pcl::PolygonMesh mesh;
pcl::io::loadPolygonFilePLY("test.ply", mesh);
pcl::fromPCLPointCloud2(mesh.cloud, *cloud);
pickPoints pickViewer;
pickViewer.setInputCloud(cloud); // A pointer to a cloud
pickViewer.simpleViewer();
vector<float> pointSelected;
pointSelected= pickViewer.getpoints();
cout<<pointSelected[0]<<" "<<pointSelected[1]<<" "<<pointSelected[2]<<endl;
cout<<pointSelected[3]<<" "<<pointSelected[4]<<" "<<pointSelected[5]<<endl;
cin.get();
return 0;
}
But when the code was debugged, I got nothing. Also I know that when picking points with the left button, the SHIFT button should be pressed. Thank you in advance for any help!
I found that the getPoints() method does not work as I expected. However, getPoint() worked well. Here is code to print out the selected points and store them is a vector:
std::vector<pcl::PointXYZ> selectedPoints;
void pointPickingEventOccurred(const pcl::visualization::PointPickingEvent& event, void* viewer_void)
{
float x, y, z;
if (event.getPointIndex() == -1)
{
return;
}
event.getPoint(x, y, z);
std::cout << "Point coordinate ( " << x << ", " << y << ", " << z << ")" << std::endl;
selectedPoints.push_back(pcl::PointXYZ(x, y, z));
}
void displayCloud(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, const std::string& window_name)
{
if (cloud->size() < 1)
{
std::cout << window_name << " display failure. Cloud contains no points\n";
return;
}
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer(window_name));
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZI> point_cloud_color_handler(cloud, "intensity");
viewer->addPointCloud< pcl::PointXYZI >(cloud, point_cloud_color_handler, "id");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "id");
viewer->registerKeyboardCallback(keyboardEventOccurred, (void*)viewer.get());
viewer->registerPointPickingCallback(pointPickingEventOccurred, (void*)&viewer);
while (!viewer->wasStopped() && !close_window){
viewer->spinOnce(50);
}
close_window = false;
viewer->close();
}
You can also find distances between the points pretty easily once they are selected.
if (selectedPoints.size() > 1)
{
float distance = pcl::euclideanDistance(selectedPoints[0], selectedPoints[1]);
std::cout << "Distance is " << distance << std::endl;
}
The selectedPoints vector can be emptied with a keyboardEvent if you want to start over picking points.

Resources