Alternative way to print Arabic text in qt - c++

I'm trying to print an HTML web page that contains Arabic text in Qt. Everything prints fine, but the Arabic text doesn't print properly.
First I tried this:
#include "mainwindow.h"
#include "ui_mainwindow.
#include <QtPrintSupport/QPrinter>
#include <QString>
#include <QtPrintSupport/QPrintDialog>
#include <QTextDocument>
#include <QFile>
#include <QDir>
#include <QFileDialog>
#include <QTextCodec>
#include <QtWebKitWidgets/QWebPage>
#include <QtWebKitWidgets/QWebView>
#include <QtWebKitWidgets/QWebFrame>
QString htmlItem(QString Item)
{
QString r="";
r.append( "<td>"
"<p align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:'Tahoma'; font-size:9pt; font-weight:600;\">");
r.append(Item);
r.append("</span></p></td>");
return r;
}
QString htmlRow(QString MFC,QString MFT,QString D,QString N)
{
QString ret ="" ;
ret.append("<tr>");
ret.append(htmlItem(MFC));
ret.append(htmlItem(MFT));
ret.append(htmlItem(D));
ret.append(htmlItem(N));
ret.append("</tr>");
return ret;
}
QString htmlTable(QString rows)
{
QString ret = "";
ret.append("<table border=\"1\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;\" align=\"center\" width=\"90%\" cellspacing=\"0\" cellpadding=\"4\">"
"<tbody>");
ret.append(rows);
ret.append("</tbody></table>");
return ret ;
}
QString htmlClientName(QString name)
{
QString retu="<p align=\"center\" style=\" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\""
"font-family:'Tahoma'; font-size:16pt; font-weight:600;\">";
retu.append(name);
retu.append("</span></p>");
return retu;
}
QString htmlClientPage(QString Table,QString Name)
{
QString r = "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">"
"<!-- saved from url=(0045)file:///C:/Users/MG/Desktop/Untitled%201.html "
"-->"
"<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><meta name=\"qrichtext\" content=\"1\"><title>QTextEdit Example</title><style "
"type=\"text/css\">"
"p, li { white-space: pre-wrap; }"
"</style></head><body style=\" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-"
"style:normal;\"";
r.append(htmlClientName(Name));
r.append(htmlTable(Table));
r.append("</body></html>");
return r;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString cD="";
cD.append(htmlRow("m","n","b","v"));
cD.append(htmlRow("hgfh","n","b","gggg"));
cD.append(htmlRow("m","vvvv","bbbbbbb","v"));
cD.append(htmlRow("m","ssssss","b","sssssssss"));
QString data = htmlClientPage(htmlTable(cD), "???? ???? ");
ui->textEdit->setText(data);
#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG)
QPrinter printer(QPrinter::HighResolution);
QPrintDialog *dlg = new QPrintDialog(&printer, this);
if (ui->textEdit->textCursor().hasSelection())
dlg->addEnabledOption(QAbstractPrintDialog::PrintSelection);
dlg->setWindowTitle(tr("Print Document"));
if (dlg->exec() == QDialog::Accepted)
ui->textEdit->print(&printer);
delete dlg;
#endif
}
The output printed file was like this:
I searched for how to solve this problem and ended up with sum bugs in Qt when printing Arabic text. And I tried some other Qwidgets like QwebView and QwebPage and ended up with more problems.
Now I'm asking if there is an alternative way to use Qt printing like Windows API or something else to solve this problem.
I use
SDK : Qt 5.2.1 with Qt Creator 3.0.1
Operating System : Microsoft Windows 8
Edit: I need to mention that Qt prints Arabic text to PDF well.
Edit: I'm pretty sure that the problem is not the encoding. I searched for this problem and I found these bugs in Qt:
https://bugreports.qt-project.org/browse/QTBUG-4452?page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel
I think the problem is related to this one.

This:
QString str = QString::fromLocal8Bit(data.toLocal8Bit());
doesn't make sense to me. I am not sure if it will work, but try the following:
ui->textEdit->setText(htmlArabicPage);
and tell me what happens.
Also if you have this:
htmlClientPage(htmlTable(cD),"محمد جمال ");
in your source code, you should be very careful. If you want to create a Unicode literal in C++11 then you should do:
u8"محمد جمال "
where the text is encoded in UTF-8.
Otherwise, you should try if "محمد جمال " is being interpreted well. Try this:
#include <QString>
#include <QDebug>
int main()
{
qDebug() << QString::fromUtf8("محمد جمال ");
qDebug() << QString::fromLocal8Bit("محمد جمال ");
return 0;
}
The bug you posted is from the previous version of Qt and it has been closed.

Related

How to add css stylesheet to a QWebEngineView?

I'm trying to follow this Qt example for adding CSS stylesheet to a QWebEngineView, however, I'm getting this error:
use of undefined type 'QWebEngineScriptCollection'
at the line ui.webEngineView->page()->scripts().insert(script);
What I'm missing? Testing using qt 6.4 Visual Studio 2022, the project can be reproduced by simply adding a QWebEngineView to the ui, and
#include "stdafx.h"
#include "MainWindow.h"
#include <QWebEngineScript>
void MainWindow::insertStyleSheet(const QString& name, const QString& source, bool immediately)
{
QWebEngineScript script;
QString s = QString::fromLatin1("(function() {"\
" css = document.createElement('style');"\
" css.type = 'text/css';"\
" css.id = '%1';"\
" document.head.appendChild(css);"\
" css.innerText = '%2';"\
"})()").arg(name).arg(source.simplified());
if (immediately)
ui.webEngineView->page()->runJavaScript(s, QWebEngineScript::ApplicationWorld);
script.setName(name);
script.setSourceCode(s);
script.setInjectionPoint(QWebEngineScript::DocumentReady);
script.setRunsOnSubFrames(true);
script.setWorldId(QWebEngineScript::ApplicationWorld);
ui.webEngineView->page()->scripts().insert(script);
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
Fixed it. The correct include is:
#include <QtWebEngineCore/qwebenginescriptcollection.h>

QSyntaxHighlighter does not create QTextFragments

I'm working on a syntax highlighter with Qt and I wanted to add unit tests on it to check if formats are well applied.
But I don't manage to get the block divided by formats. I use QTextBlock and QTextFragment but it's not working while the doc of QTextFragment says :
A text fragment describes a piece of text that is stored with a single character format.
Here is the code in a runnable main.cpp file :
#include <QApplication>
#include <QTextEdit>
#include <QSyntaxHighlighter>
#include <QRegularExpression>
#include <QDebug>
class Highlighter : public QSyntaxHighlighter
{
public:
Highlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
{}
protected:
void highlightBlock(const QString& text) override
{
QTextCharFormat classFormat;
classFormat.setFontWeight(QFont::Bold);
QRegularExpression pattern { "\\bclass\\b" };
QRegularExpressionMatchIterator matchIterator = pattern.globalMatch(text);
while (matchIterator.hasNext())
{
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), classFormat);
}
// ==== TESTS ==== //
qDebug() << "--------------------------------";
QTextDocument *doc = document();
QTextBlock currentBlock = doc->firstBlock();
while (currentBlock.isValid()) {
qDebug() << "BLOCK" << currentBlock.text();
QTextBlockFormat blockFormat = currentBlock.blockFormat();
QTextCharFormat charFormat = currentBlock.charFormat();
QFont font = charFormat.font();
// each QTextBlock holds multiple fragments of text, so iterate over it:
QTextBlock::iterator it;
for (it = currentBlock.begin(); !(it.atEnd()); ++it) {
QTextFragment currentFragment = it.fragment();
if (currentFragment.isValid()) {
// a text fragment also has a char format with font:
QTextCharFormat fragmentCharFormat = currentFragment.charFormat();
QFont fragmentFont = fragmentCharFormat.font();
qDebug() << "FRAGMENT" << currentFragment.text();
}
}
currentBlock = currentBlock.next();
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
auto *textEdit = new QTextEdit;
auto *highlighter = new Highlighter(textEdit->document());
Q_UNUSED(highlighter);
textEdit->setText("a class for test");
textEdit->show();
return a.exec();
}
And it outputs only one block "a class for test" and one format "a class for test" while the class keyword is in bold.
Thanks for your help !
Ok I found this from the documentation of QSyntaxHighlighter::setFormat :
Note that the document itself remains unmodified by the format set through this function.
The formats applied by the syntax highlighter are not stored in QTextBlock::charFormat but in the additional formats :
QVector<QTextLayout::FormatRange> formats = textEdit->textCursor().block().layout()->formats();

QT Creator will only convert the first word from text Edit to plain text

This is a notes program, you write in the textEdit and it saves it using fstream. I am trying to figure out how to load back ALL the words previously typed on the textEdit, right now only the first word loads back. I think it has something to do with the white spaces.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <fstream>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Setup code
ui->textEdit->setReadOnly(true);
ui->textEdit->append("Select one of the buttons on the left to pick a log");
}
MainWindow::~MainWindow()
{
delete ui;
}
string buttons;
string lastSavedText[] =
{
" ",
" "
};
QString qLastSavedTextHome, qLastSavedTextWork;
This is the first button
void MainWindow::on_homeButton_clicked()
{
// Preparing text edit
ui->textEdit->setReadOnly(false);
ui->textEdit->clear();
ui->textEdit->setOverwriteMode(true);
buttons = "Home";
// Loading previously saved text
ifstream home;
home.open("home.apl");
home >> lastSavedText[0];
home.close();
qLastSavedTextHome = QString::fromStdString(lastSavedText[0]);
ui->textEdit->setPlainText(qLastSavedTextHome);
}
This next button isn't fully developed yet:
void MainWindow::on_workButton_clicked()
{
// Preparing text edit
ui->textEdit->setReadOnly(false);
ui->textEdit->clear();
buttons = "Work";
// Converts textEdit to string
QString textEditText = ui->textEdit->toPlainText();
string plainText = textEditText.toStdString();
}
This is where I convert the textEdit to a string and save the textEdit to a stream:
void MainWindow::on_saveButton_clicked()
{
// Converts textEdit to string
QString textEditText = ui->textEdit->toPlainText();
lastSavedText[0] = textEditText.toStdString();
// Saving files
ofstream home;
home.open("home.apl");
home << lastSavedText[0];
home.close();
}
You are reading only one word in your code:
ifstream home;
home.open("home.apl");
home >> lastSavedText[0]; // Here!!!
home.close();
I'd suggest that you use QFile for reading and writing to file and it'll be more easier to do.
Here's an example:
QFile file { "home.apl" };
if ( !file.open(QIODevice::ReadOnly | QIODevice::Text) )
{
qDebug() << "Could not open file!";
return;
}
const auto& lastSavedText = file.readAll();
file.close();
ui->textEdit->setPlainText( lastSavedText );
You should use Qt features as much you can. You can directly use QString instead of std::string and you won't have to do those conversions.

" parameter count mismatch" QT c++

when i tried my code fir the first time
it was
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QMessageBox"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPixmap pix("C:/Users/AMR.EngAmr/Downloads/1561136.jpg");
ui->label_pic->setPixmap(pix);
if(!connOpen())
ui->label_9->setText("فشل الاتصال بقاعدة البيانات");
else
ui->label_9->setText("تم الاتصال بقاعدة البيانات ");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString Name,period,group,Weight,Notes,Notes2,Notes3,pressure;
Name=ui->lineEdit_name->text();
period=ui->lineEdit_2->text();
group=ui->lineEdit_group->text();
Weight=ui->lineEdit_weight->text();
Notes2=ui->lineEdit_notes2->text();
pressure=ui->lineEdit_presure->text();
Notes=ui->lineEdit_notes->text();
Notes3=ui->lineEdit_notes3->text();
if(!connOpen()){
qDebug()<<"Faield to open the database";
return;
}
connOpen();
QSqlQuery qry;
qry.prepare("insert into Patients (Name,period,group,Weight,Notes2,pressure,Notes,Notes3 ) values('"+Name+"','"+period+"''"+group+"','"+Weight+"','"+Notes2+"','"+pressure+"','"+Notes+"''"+Notes3+"')");
if(qry.exec())
{
QMessageBox::information(this,tr("Save"),tr("Saved"));
connClose();
}
else
{
QMessageBox::information(this,tr("error::"),qry.lastError().text());
}
}
and i got error No query Unable to fetch row
and i tried a solution and my code was
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QMessageBox"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPixmap pix("C:/Users/AMR.EngAmr/Downloads/1561136.jpg");
ui->label_pic->setPixmap(pix);
if(!connOpen())
ui->label_9->setText("فشل الاتصال بقاعدة البيانات");
else
ui->label_9->setText("تم الاتصال بقاعدة البيانات ");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString Name,period,group,Weight,Notes,Notes2,Notes3,pressure;
Name=ui->lineEdit_name->text();
period=ui->lineEdit_2->text();
group=ui->lineEdit_group->text();
Weight=ui->lineEdit_weight->text();
Notes2=ui->lineEdit_notes2->text();
pressure=ui->lineEdit_presure->text();
Notes=ui->lineEdit_notes->text();
Notes3=ui->lineEdit_notes3->text();
if(!connOpen()){
qDebug()<<"Faield to open the database";
return;
}
connOpen();
QSqlQuery qry;
qry.prepare("insert into Patients (:Name,:period,:group,:Weight,:Notes2,:pressure,:Notes,:Notes3 ) values('"+Name+"','"+period+"''"+group+"','"+Weight+"','"+Notes2+"','"+pressure+"','"+Notes+"''"+Notes3+"')");
qry.bindValue(":Name", Name);
qry.bindValue(":period", period);
qry.bindValue(":group", group);
qry.bindValue(":Weight", Weight);
qry.bindValue(":Notes2", Notes2);
qry.bindValue(":pressure", pressure);
qry.bindValue(":Notes", Notes);
qry.bindValue(":Note3", Notes3);
if(qry.exec())
{
QMessageBox::information(this,tr("Save"),tr("Saved"));
connClose();
}
else
{
QMessageBox::information(this,tr("error::"),qry.lastError().text());
}
}
and i got the error
parameter count mismatch
what is the problem i have to finish it in two days
Looks like you're mixing up your value binding. When you use that, you don't put the values into the query (the very purpose of binding values is avoid that!). This might work, if the column names are correct:
qry.prepare("insert into Patients "
"(Name,period,group,Weight,Notes2,pressure,Notes,Notes3) "
"values(:Name,:period,:group,:Weight,:Notes2,:pressure,:Notes,:Notes3)");
(Note about splitting strings like that, which you probably are not familiar with: in C and C++ writing "foo" "bar" is same as "foobar".)
Also, documentation is your friend. Qt has mostly quite good documentation, and in this case it seems to exactly cover what you are asking.

QT - creating layout from .ui files

I have code like below. I have some data in database and I need to create view structure to display it. I don't have big experience in Qt programming, I've made more things in PHP, HTML and CSS. I need to do something like in HTML - when you have a box (for example div) without extra style and you put inside some data this div tag will display all data's inside. But with following code I've got only a part of datas from widgets loaded from file. Behavior of GridLayout in MainWindow is similar to div style="max-width: 200px; max-height: 200px; overflow:hidden". And also Layout elements from children's file has the same behavior...
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "databasemanager.h"
#include "ycexception.h"
#include <QDebug>
#include <QSqlQuery>
#include <QtUiTools>
#include <QLabel>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
createStructureFromDb();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::createStructureFromDb() {
try {
dbManager = new DatabaseManager();
}
catch(YCException e) {
//TODO: show dialog with message
qDebug() << e.what();
exit(-1);
}
QSqlQuery groupsQuery = dbManager->getGroups();
while(groupsQuery.next()) {
Group group;
group.setIdGroup(groupsQuery.value(0).toInt());
group.setName(groupsQuery.value(1).toString());
QUiLoader loader;
QFile file(":/forms/group.ui");
file.open(QFile::ReadOnly);
QWidget *formWidget = loader.load(&file);
file.close();
(formWidget->findChild<QLabel*>("groupName"))->setText(group.getName());
ui->gridLayout->addWidget(formWidget);
QVBoxLayout* groupItems = formWidget->findChild<QVBoxLayout*>("groupItems");
QSqlQuery cardsQuery = dbManager->getGroupCards(group.getIdGroup());
while(cardsQuery.next()) {
Card card;
card.setIdCard(cardsQuery.value(0).toInt());
card.setContent(cardsQuery.value(1).toString());
card.setDueDate(cardsQuery.value(2).toString());
card.setIdGroup(cardsQuery.value(3).toInt());
group.addCard(card);
QFile file(":/forms/card.ui");
QWidget *cardWidget = loader.load(&file);
file.close();
(cardWidget->findChild<QLabel*>("contentLabel"))->setText(card.getContent());
(cardWidget->findChild<QLabel*>("dueDateLabel"))->setText(card.getDueDate());
groupItems->addWidget(cardWidget);
}
groups.insert(group.getIdGroup(), group);
}
ui->label->setText("really long textreally long textreally long textreally long textreally long textreally long textreally long textreally long textreally long textreally long textreally long text");
this->layout()->activate();
}
overflow:hidden is all but explicit for persons like me that have only a very little knowledge of web technologies (but I can google it). But, saying that you want scrollbars is a lot more expressive... I used this page to understand what you want.
So, for what you want: GridLayout is not like html's div. If you want the content of a widget to be scrolled, you have to put the widget in a QScrollArea, and put that scroll area in the cell of the GridLayout that first contained your widget.
More specifically:
overflow:visible : not possible
overflow:hidden : default behavior
overflow:scroll : use QScrollArea
overflow:auto : use QScrollArea
overflow:inherit : possible, but you need to write quite a bit of code to do this. Also, useless in a well-designed interface