using custom QMetaType with QDataStream - c++

I'm trying to load and store a custom QMetaType using QDataStream object. Here is an example:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QString test1("/test1/");
const QString path1(QDir::homePath()+test1);
qDebug() << "path1 variable is " << path1;
QDir apphome(path1);
qDebug() << "apphome path is " << apphome.absolutePath();
if (!apphome.mkdir(path1)) { qDebug() << "mkdir returned false. directory already exists?"; }
if(!apphome.setCurrent(path1)) { qDebug() << "did not set current directory"; }
qDebug() << "apphome path is " << apphome.absolutePath();
Basic basic1;
Basic basic2;
basic1.value = 14;
QFile file1("file1name");
if (!file1.open(QIODevice::WriteOnly)) { qDebug() << "file1 not open."; }
QDataStream dataStream1(&file1);
QVariant qvar1;
qvar1.setValue(basic1);
dataStream1 << (quint32)12345;
dataStream1 << qvar1;
file1.close();
file1.open(QIODevice::ReadOnly);
QDataStream dataStream2(&file1);
quint32 magic;
QVariant qvar2;
dataStream1 >> magic;
qDebug() << "magic number is " << magic;
dataStream2 >> qvar2;
file1.close();
basic2 = qvar2.value<Basic>();
qDebug() << "14 = " << basic1.value << " = " << basic2.value << ".";
//MainWindow w;
//w.show();
return a.exec();
}
The magic number comes back, but there is a message QVariant::save: unable to save type 'Basic' (type id: 1026). and then of course QVariant::load: unable to load type 1026. and then 14 = 14 = 0. The Basic class is just from the QMetaType documentation:
struct Basic
{
Basic();
Basic(const Basic &basic);
~Basic();
int value;
};
Q_DECLARE_METATYPE(Basic)
// basic.cpp
#include "basic.h"
Basic::Basic() {}
Basic::Basic(const Basic &basic)
{
value = basic.value;
}
Basic::~Basic(){}
I'm running out of ideas, does anyone know what is causing the problem? The version of Qt is 5.10.1.

Because compiler can't read your mind, you need describe how serialization is possible, e.g.
struct Basic
{
Basic();
Basic(const Basic &basic);
~Basic();
int value;
friend QDataStream & operator << (QDataStream &arch, const Basic& object)
{
arch << object.value;
return arch;
}
friend QDataStream & operator >> (QDataStream &arch, Basic& object)
{
arch >> object.value;
return arch;
}
};
Q_DECLARE_METATYPE(Basic);
in main()
qRegisterMetaType<Basic>("Basic");
qRegisterMetaTypeStreamOperators<Basic>("Basic");
before save\load operation would happen. Q_DECLARE_METATYPE is required to store type with QVariant, those two are required to register object's "big three" to manage it as resource and its serialization methods. Output:
path1 variable is "C:/Users/Yaroslav/test1/"
apphome path is "C:/Users/Yaroslav/test1"
mkdir returned false. directory already exists?
apphome path is "C:/Users/Yaroslav/test1"
magic number is 12345
14 = 14 = 14 .
P.S. Note, if you left return a.exec(); with no window present, you get program staying in memory forever until you stop it.

Related

Qt 6.2: QMediaPlayer & QByteArray

Good day.
Has anyone tried QMediaPlayer in Qt 6.2 already?
I'm trying this code, but Media Status always remains as "NoMedia" and no any sound :).
Full test project: https://github.com/avttrue/MediaPlayerTest
#include "mainwindow.h"
#include <QDebug>
#include <QBuffer>
#include <QFile>
#include <QAudioOutput>
#include <QMediaPlayer>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QFile file("../test/Bankrobber.mp3");
if(!file.open(QIODevice::ReadOnly))
qDebug() << "File not opened";
qDebug() << "File size:" << file.size(); // File size: 11181085
QByteArray ba = file.readAll();
qDebug() << "ByteArray size:" << ba.size(); // ByteArray size: 11181085
QBuffer* buffer = new QBuffer(this);
buffer->setData(ba);
if(!buffer->open(QIODevice::ReadOnly))
qDebug() << "Buffer not opened";
qDebug() << "Buffer size:" << buffer->size(); // Buffer size: 11181085
buffer->seek(qint64(0));
auto audioOutput = new QAudioOutput(this);
auto player = new QMediaPlayer(this);
player->setAudioOutput(audioOutput);
audioOutput->setVolume(50);
player->setSourceDevice(buffer);
qDebug() << "Device:" << player->sourceDevice(); // Device: QBuffer(0x563180493020)
QObject::connect(player, &QMediaPlayer::mediaStatusChanged,
[=](QMediaPlayer::MediaStatus status)
{ qDebug() << "MediaStatus:" << player->mediaStatus() << "|" << status; });
QObject::connect(player, &QMediaPlayer::errorOccurred,
[=](QMediaPlayer::Error error)
{ qDebug() << "Error:" << player->errorString() << "|" << error; });
QObject::connect(player, &QMediaPlayer::playbackStateChanged,
[=](QMediaPlayer::PlaybackState state)
{ qDebug() << "PlaybackState:" << player->playbackState() << "|" << state; });
player->play();
qDebug() << "MediaStatus:" << player->mediaStatus(); // MediaStatus: QMediaPlayer::NoMedia
}
As the docs points out:
void QMediaPlayer::setSourceDevice(QIODevice *device, const QUrl
&sourceUrl = QUrl())
Sets the current source device.
The media data will be read from device. The sourceUrl can be provided
to resolve additional information about the media, mime type etc. The
device must be open and readable.
For macOS the device should also be seek-able.
Note: This function returns immediately after recording the specified
source of the media. It does not wait for the media to finish loading
and does not check for errors. Listen for the mediaStatusChanged() and
error() signals to be notified when the media is loaded, and if an
error occurs during loading.
(emphasis mine)
QMediaPlayer does not know how to deduce the file format so it does not load it. The solution is to point out that it is an mp3:
player->setSourceDevice(buffer, QUrl("foo.mp3"));
The function setSourceDevice() you are using isn't doing what you think?
Maybe you wanted setSource() instead?
Qt has great documentation:
https://doc.qt.io/qt-6/qmediaplayer.html#setSourceDevice
Even good examples:
player = new QMediaPlayer;
audioOutput = new QAudioOutput;
player->setAudioOutput(audioOutput);
connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
player->setSource(QUrl::fromLocalFile("/Users/me/Music/coolsong.mp3"));
audioOutput->setVolume(50);
player->play();
Ref.
https://doc.qt.io/qt-6/qmediaplayer.html#details
May be this is as variant, but i think it not good:
QTemporaryFile tfile;
if (!tfile.open())
qDebug() << "TemporaryFile not opened";
else
{
qDebug() << "TemporaryFile writed:" << tfile.write(ba);
if(tfile.size() != ba.size())
qDebug() << "TemporaryFile not complited";
else
player->setSource(QUrl::fromLocalFile(tfile.fileName()));
}

how to get latitude/longitude from geo address using Qt c++ QGeoServiceProvider?

I am trying to use the osm api via a QGeoServiceProvider and QGeoCodingManager to derive the latitude and longitude from a given physical address.
Thereby I stumbled upon this Question, which seems to do exactly what I need.
However I want to implement this in a qt gui application as a separate function and I don' t understand what is happening in the connect.
Could someone please explain or how I can modify it to get it to work in a function ?
cout << "Try service: " << "osm" << endl;
// choose provider
QGeoServiceProvider qGeoService("osm");
QGeoCodingManager *pQGeoCoder = qGeoService.geocodingManager();
if (!pQGeoCoder) {
cerr
<< "GeoCodingManager '" << "osm"
<< "' not available!" << endl;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
// build address
QGeoAddress qGeoAddr;
qGeoAddr.setCountry(QString::fromUtf8("Germany"));
qGeoAddr.setPostalCode(QString::fromUtf8("88250"));
qGeoAddr.setCity(QString::fromUtf8("Weingarten"));
qGeoAddr.setStreet(QString::fromUtf8("Heinrich-Hertz-Str. 6"));
QGeoCodeReply *pQGeoCode = pQGeoCoder->geocode(qGeoAddr);
if (!pQGeoCode) {
cerr << "GeoCoding totally failed!" << endl;
}
cout << "Searching..." << endl;
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
[&qGeoAddr, pQGeoCode](){
cout << "Reply: " << pQGeoCode->errorString().toStdString() << endl;
switch (pQGeoCode->error()) {
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: cerr << #ERROR << endl; break
CASE(NoError);
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: cerr << "Undocumented error!" << endl;
}
if (pQGeoCode->error() != QGeoCodeReply::NoError) return;
// eval. result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
cout << qGeoLocs.size() << " location(s) returned." << endl;
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(qGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
cout
<< "Lat.: " << qGeoCoord.latitude() << endl
<< "Long.: " << qGeoCoord.longitude() << endl
<< "Alt.: " << qGeoCoord.altitude() << endl;
}
});
So I just removed the QApplication part because I dont have this reference in a function. As a result i get:
Qt Version: 5.10.0
Try service: osm
Searching...
but no coordinates. I assume the connection to where the lat and lon data is acquired fails. But as I mentioned I dont understand the connect here.
Any help is appreciated
EDIT
so I tried to build a connect to catch the finished Signal as suggested.
The code now looks like this:
QGeoServiceProvider qGeoService("osm");
QGeoCodingManager *pQGeoCoder = qGeoService.geocodingManager();
if (!pQGeoCoder) {
cerr
<< "GeoCodingManager '" << "osm"
<< "' not available!" << endl;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
// build address
//QGeoAddress qGeoAddr;
qGeoAddr.setCountry(QString::fromUtf8("Germany"));
qGeoAddr.setPostalCode(QString::fromUtf8("88250"));
qGeoAddr.setCity(QString::fromUtf8("Weingarten"));
qGeoAddr.setStreet(QString::fromUtf8("Heinrich-Hertz-Str. 6"));
this->pQGeoCode = pQGeoCoder->geocode(qGeoAddr);
if (!pQGeoCode) {
cerr << "GeoCoding totally failed!" << endl;
}
cout << "Searching..." << endl;
connect(pQGeoCode,SIGNAL(finished()),this,SLOT(getlonlat()));
With the Slot:
void MainWindow::getlonlat()
{
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
cout << qGeoLocs.size() << " location(s) returned." << endl;
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(qGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
cout
<< "Lat.: " << qGeoCoord.latitude() << endl
<< "Long.: " << qGeoCoord.longitude() << endl
<< "Alt.: " << qGeoCoord.altitude() << endl;
}
}
However the finished signal doesn't get triggered. Therefore the result is the same.
EDIT
Implementing the Code from your Gui Answer:
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QGeoServiceProvider *pQGeoProvider = nullptr;
ui->setupUi(this);
qDebug() << "Qt Version:" << QT_VERSION_STR;
// main application
//QApplication app(argc, argv);
// install signal handlers
QObject::connect(this->ui->qBtnInit, &QPushButton::clicked,
[&]() {
if (pQGeoProvider) delete pQGeoProvider;
std::ostringstream out;
pQGeoProvider = init(out);
log(out.str());
});
QObject::connect(this->ui->qBtnFind, &QPushButton::clicked,
[&]() {
// init geo coder if not yet done
if (!pQGeoProvider) {
std::ostringstream out;
pQGeoProvider = init(out);
log(out.str());
if (!pQGeoProvider) return; // failed
}
// fill in request
QGeoAddress *pQGeoAddr = new QGeoAddress;
pQGeoAddr->setCountry(this->ui->qTxtCountry->text());
pQGeoAddr->setPostalCode(this->ui->qTxtZipCode->text());
pQGeoAddr->setCity(this->ui->qTxtCity->text());
pQGeoAddr->setStreet(this->ui->qTxtStreet->text());
QGeoCodeReply *pQGeoCode
= pQGeoProvider->geocodingManager()->geocode(*pQGeoAddr);
if (!pQGeoCode) {
delete pQGeoAddr;
log("GeoCoding totally failed!\n");
return;
}
{ std::ostringstream out;
out << "Sending request for:\n"
<< pQGeoAddr->country().toUtf8().data() << "; "
<< pQGeoAddr->postalCode().toUtf8().data() << "; "
<< pQGeoAddr->city().toUtf8().data() << "; "
<< pQGeoAddr->street().toUtf8().data() << "...\n";
log(out.str());
}
// install signal handler to process result later
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
[&,pQGeoAddr, pQGeoCode]() {
// process reply
std::ostringstream out;
out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
switch (pQGeoCode->error()) {
case QGeoCodeReply::NoError: {
// eval result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
out << qGeoLocs.size() << " location(s) returned.\n";
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(*pQGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
out
<< "Lat.: " << qGeoCoord.latitude() << '\n'
<< "Long.: " << qGeoCoord.longitude() << '\n'
<< "Alt.: " << qGeoCoord.altitude() << '\n';
}
} break;
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: out << "Undocumented error!\n";
}
// log result
log(out.str());
// clean-up
delete pQGeoAddr;
/* delete sender in signal handler could be lethal
* Hence, delete it later...
*/
pQGeoCode->deleteLater();
});
});
// fill in a sample request with a known address initially
this->ui->qTxtCountry->setText(QString::fromUtf8("Germany"));
this->ui->qTxtZipCode->setText(QString::fromUtf8("88250"));
this->ui->qTxtCity->setText(QString::fromUtf8("Weingarten"));
this->ui->qTxtStreet->setText(QString::fromUtf8("Danziger Str. 3"));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::log(const QString &qString)
{
this->ui->qTxtLog->setPlainText(this->ui->qTxtLog->toPlainText() + qString);
this->ui->qTxtLog->moveCursor(QTextCursor::End);
}
void MainWindow::log(const char *text)
{
log(QString::fromUtf8(text));
}
void MainWindow::log(const std::string &text)
{
log(text.c_str());
}
QGeoServiceProvider* MainWindow::init(std::ostream &out)
{
// check for available services
QStringList qGeoSrvList
= QGeoServiceProvider::availableServiceProviders();
for (QString entry : qGeoSrvList) {
out << "Try service: " << entry.toStdString() << '\n';
// choose provider
QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
if (!pQGeoProvider) {
out
<< "ERROR: GeoServiceProvider '" << entry.toStdString()
<< "' not available!\n";
continue;
}
QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
if (!pQGeoCoder) {
out
<< "ERROR: GeoCodingManager '" << entry.toStdString()
<< "' not available!\n";
delete pQGeoProvider;
continue;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
out << "Using service " << entry.toStdString() << '\n';
return pQGeoProvider; // success
}
out << "ERROR: No suitable GeoServiceProvider found!\n";
return nullptr; // all attempts failed
}
The main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
And here the Header File for the MainWindow:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
virtual ~MainWindow();
void log(const QString &qString);
void log(const char *text);
void log(const std::string &text);
QGeoServiceProvider* init(std::ostream &out);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
I transformed my older sample to a minimal application with GUI:
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QtWidgets>
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
void log(QTextEdit &qTxtLog, const QString &qString)
{
qTxtLog.setPlainText(qTxtLog.toPlainText() + qString);
qTxtLog.moveCursor(QTextCursor::End);
}
void log(QTextEdit &qTxtLog, const char *text)
{
log(qTxtLog, QString::fromUtf8(text));
}
void log(QTextEdit &qTxtLog, const std::string &text)
{
log(qTxtLog, text.c_str());
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
QWidget qWin;
QVBoxLayout qBox;
QFormLayout qForm;
QLabel qLblCountry(QString::fromUtf8("Country:"));
QLineEdit qTxtCountry;
qForm.addRow(&qLblCountry, &qTxtCountry);
QLabel qLblZipCode(QString::fromUtf8("Postal Code:"));
QLineEdit qTxtZipCode;
qForm.addRow(&qLblZipCode, &qTxtZipCode);
QLabel qLblCity(QString::fromUtf8("City:"));
QLineEdit qTxtCity;
qForm.addRow(&qLblCity, &qTxtCity);
QLabel qLblStreet(QString::fromUtf8("Street:"));
QLineEdit qTxtStreet;
qForm.addRow(&qLblStreet, &qTxtStreet);
QLabel qLblProvider(QString::fromUtf8("Provider:"));
QComboBox qLstProviders;
qForm.addRow(&qLblProvider, &qLstProviders);
qBox.addLayout(&qForm);
QPushButton qBtnFind(QString::fromUtf8("Find Coordinates"));
qBox.addWidget(&qBtnFind);
QLabel qLblLog(QString::fromUtf8("Log:"));
qBox.addWidget(&qLblLog);
QTextEdit qTxtLog;
qTxtLog.setReadOnly(true);
qBox.addWidget(&qTxtLog);
qWin.setLayout(&qBox);
qWin.show();
// initialize Geo Service Providers
std::vector<QGeoServiceProvider*> pQGeoProviders;
{ std::ostringstream out;
QStringList qGeoSrvList
= QGeoServiceProvider::availableServiceProviders();
for (QString entry : qGeoSrvList) {
out << "Try service: " << entry.toStdString() << '\n';
// choose provider
QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
if (!pQGeoProvider) {
out
<< "ERROR: GeoServiceProvider '" << entry.toStdString()
<< "' not available!\n";
continue;
}
QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
if (!pQGeoCoder) {
out
<< "ERROR: GeoCodingManager '" << entry.toStdString()
<< "' not available!\n";
delete pQGeoProvider;
continue;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
qLstProviders.addItem(entry);
pQGeoProviders.push_back(pQGeoProvider);
out << "Service " << entry.toStdString() << " available.\n";
}
log(qTxtLog, out.str());
}
if (pQGeoProviders.empty()) qBtnFind.setEnabled(false);
// install signal handlers
QObject::connect(&qBtnFind, QPushButton::clicked,
[&]() {
// get current geo service provider
QGeoServiceProvider *pQGeoProvider
= pQGeoProviders[qLstProviders.currentIndex()];
// fill in request
QGeoAddress *pQGeoAddr = new QGeoAddress;
pQGeoAddr->setCountry(qTxtCountry.text());
pQGeoAddr->setPostalCode(qTxtZipCode.text());
pQGeoAddr->setCity(qTxtCity.text());
pQGeoAddr->setStreet(qTxtStreet.text());
QGeoCodeReply *pQGeoCode
= pQGeoProvider->geocodingManager()->geocode(*pQGeoAddr);
if (!pQGeoCode) {
delete pQGeoAddr;
log(qTxtLog, "GeoCoding totally failed!\n");
return;
}
{ std::ostringstream out;
out << "Sending request for:\n"
<< pQGeoAddr->country().toUtf8().data() << "; "
<< pQGeoAddr->postalCode().toUtf8().data() << "; "
<< pQGeoAddr->city().toUtf8().data() << "; "
<< pQGeoAddr->street().toUtf8().data() << "...\n";
log(qTxtLog, out.str());
}
// install signal handler to process result later
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
[&qTxtLog, pQGeoAddr, pQGeoCode]() {
// process reply
std::ostringstream out;
out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
switch (pQGeoCode->error()) {
case QGeoCodeReply::NoError: {
// eval result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
out << qGeoLocs.size() << " location(s) returned.\n";
for (QGeoLocation &qGeoLoc : qGeoLocs) {
qGeoLoc.setAddress(*pQGeoAddr);
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
out
<< "Lat.: " << qGeoCoord.latitude() << '\n'
<< "Long.: " << qGeoCoord.longitude() << '\n'
<< "Alt.: " << qGeoCoord.altitude() << '\n';
}
} break;
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: out << "Undocumented error!\n";
}
// log result
log(qTxtLog, out.str());
// clean-up
delete pQGeoAddr;
/* delete sender in signal handler could be lethal
* Hence, delete it later...
*/
pQGeoCode->deleteLater();
});
});
// fill in a sample request with a known address initially
qTxtCountry.setText(QString::fromUtf8("Germany"));
qTxtZipCode.setText(QString::fromUtf8("88250"));
qTxtCity.setText(QString::fromUtf8("Weingarten"));
qTxtStreet.setText(QString::fromUtf8("Danziger Str. 3"));
// runtime loop
app.exec();
// done
return 0;
}
Compiled and tested in cygwin on Windows 10 (64 bit):
$ g++ --version
g++ (GCC) 6.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ qmake-qt5 testQGeoAddressGUI.pro
$ make
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_LOCATION_LIB -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_POSITIONING_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtLocation -isystem /usr/include/qt5/QtQuick -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtPositioning -isystem /usr/include/qt5/QtQml -isystem /usr/include/qt5/QtNetwork -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQGeoAddressGUI.o testQGeoAddressGUI.cc
g++ -o testQGeoAddressGUI.exe testQGeoAddressGUI.o -lQt5Widgets -lQt5Location -lQt5Quick -lQt5Gui -lQt5Positioning -lQt5Qml -lQt5Network -lQt5Core -lGL -lpthread
$ ./testQGeoAddressGUI
Qt Version: 5.9.2
Notes:
When I wrote this sample I was very carefully about scope and life-time of involved variables. (Actually, I changed some local variables to pointers and instances created with new to achieve this.) This is my hint for any reader.
In my 1st test, the application ended up in CommunicationError. I'm quite sure that our company's security policy is responsible for this. (I did the same with my older sample which I tested successfully at home – with the same result.)
A 2nd test (at home) went better. First, I tried to find the address with service provider osm which brought 0 results. Changing the service provider to esri returned one result.
I copied the output to maps.google.de:
This is actually the correct result – as I tested the (new) address of the company EKS InTec where I'm working.
The usage of lambdas in the above sample makes it a bit hard to read. Therefore, I re-visited the sample. Now, all relevant stuff has moved to a class MainWindow (hopefully, closer to the requirement of OP). The lambdas were replaced by simple methods.
// standard C++ header:
#include <iostream>
#include <sstream>
// Qt header:
#include <QtWidgets>
#include <QGeoAddress>
#include <QGeoCodingManager>
#include <QGeoCoordinate>
#include <QGeoLocation>
#include <QGeoServiceProvider>
// main window class
class MainWindow: public QWidget {
// variables:
private:
// list of service providers
std::vector<QGeoServiceProvider*> pQGeoProviders;
// Qt widgets (contents of main window)
QVBoxLayout qBox;
QFormLayout qForm;
QLabel qLblCountry;
QLineEdit qTxtCountry;
QLabel qLblZipCode;
QLineEdit qTxtZipCode;
QLabel qLblCity;
QLineEdit qTxtCity;
QLabel qLblStreet;
QLineEdit qTxtStreet;
QLabel qLblProvider;
QComboBox qLstProviders;
QPushButton qBtnFind;
QLabel qLblLog;
QTextEdit qTxtLog;
// methods:
public: // ctor/dtor
MainWindow(QWidget *pQParent = nullptr);
virtual ~MainWindow();
MainWindow(const MainWindow&) = delete;
MainWindow& operator=(const MainWindow&) = delete;
private: // internal stuff
void init(); // initializes geo service providers
void find(); // sends request
void report(); // processes reply
void log(const QString &qString)
{
qTxtLog.setPlainText(qTxtLog.toPlainText() + qString);
qTxtLog.moveCursor(QTextCursor::End);
}
void log(const char *text) { log(QString::fromUtf8(text)); }
void log(const std::string &text) { log(text.c_str()); }
};
MainWindow::MainWindow(QWidget *pQParent):
QWidget(pQParent),
qLblCountry(QString::fromUtf8("Country:")),
qLblZipCode(QString::fromUtf8("Postal Code:")),
qLblCity(QString::fromUtf8("City:")),
qLblStreet(QString::fromUtf8("Street:")),
qLblProvider(QString::fromUtf8("Provider:")),
qBtnFind(QString::fromUtf8("Find Coordinates")),
qLblLog(QString::fromUtf8("Log:"))
{
// setup child widgets
qForm.addRow(&qLblCountry, &qTxtCountry);
qForm.addRow(&qLblZipCode, &qTxtZipCode);
qForm.addRow(&qLblCity, &qTxtCity);
qForm.addRow(&qLblStreet, &qTxtStreet);
qForm.addRow(&qLblProvider, &qLstProviders);
qBox.addLayout(&qForm);
qBox.addWidget(&qBtnFind);
qBox.addWidget(&qLblLog);
qBox.addWidget(&qTxtLog);
setLayout(&qBox);
// init service provider list
init();
// install signal handlers
QObject::connect(&qBtnFind, &QPushButton::clicked,
this, &MainWindow::find);
// fill in a sample request with a known address initially
qTxtCountry.setText(QString::fromUtf8("Germany"));
qTxtZipCode.setText(QString::fromUtf8("88250"));
qTxtCity.setText(QString::fromUtf8("Weingarten"));
qTxtStreet.setText(QString::fromUtf8("Danziger Str. 3"));
}
MainWindow::~MainWindow()
{
// clean-up
for (QGeoServiceProvider *pQGeoProvider : pQGeoProviders) {
delete pQGeoProvider;
}
}
void MainWindow::init()
{
// initialize Geo Service Providers
{ std::ostringstream out;
QStringList qGeoSrvList
= QGeoServiceProvider::availableServiceProviders();
for (QString entry : qGeoSrvList) {
out << "Try service: " << entry.toStdString() << '\n';
// choose provider
QGeoServiceProvider *pQGeoProvider = new QGeoServiceProvider(entry);
if (!pQGeoProvider) {
out
<< "ERROR: GeoServiceProvider '" << entry.toStdString()
<< "' not available!\n";
continue;
}
QGeoCodingManager *pQGeoCoder = pQGeoProvider->geocodingManager();
if (!pQGeoCoder) {
out
<< "ERROR: GeoCodingManager '" << entry.toStdString()
<< "' not available!\n";
delete pQGeoProvider;
continue;
}
QLocale qLocaleC(QLocale::C, QLocale::AnyCountry);
pQGeoCoder->setLocale(qLocaleC);
qLstProviders.addItem(entry);
pQGeoProviders.push_back(pQGeoProvider);
out << "Service " << entry.toStdString() << " available.\n";
}
log(out.str());
}
if (pQGeoProviders.empty()) qBtnFind.setEnabled(false);
}
std::string format(const QGeoAddress &qGeoAddr)
{
std::ostringstream out;
out
<< qGeoAddr.country().toUtf8().data() << "; "
<< qGeoAddr.postalCode().toUtf8().data() << "; "
<< qGeoAddr.city().toUtf8().data() << "; "
<< qGeoAddr.street().toUtf8().data();
return out.str();
}
void MainWindow::find()
{
// get current geo service provider
QGeoServiceProvider *pQGeoProvider
= pQGeoProviders[qLstProviders.currentIndex()];
// fill in request
QGeoAddress qGeoAddr;
qGeoAddr.setCountry(qTxtCountry.text());
qGeoAddr.setPostalCode(qTxtZipCode.text());
qGeoAddr.setCity(qTxtCity.text());
qGeoAddr.setStreet(qTxtStreet.text());
QGeoCodeReply *pQGeoCode
= pQGeoProvider->geocodingManager()->geocode(qGeoAddr);
if (!pQGeoCode) {
log("GeoCoding totally failed!\n");
return;
}
{ std::ostringstream out;
out << "Sending request for:\n"
<< format(qGeoAddr) << "...\n";
log(out.str());
}
// install signal handler to process result later
QObject::connect(pQGeoCode, &QGeoCodeReply::finished,
this, &MainWindow::report);
/* This signal handler will delete it's own sender.
* Hence, the connection need not to be remembered
* although it has only a limited life-time.
*/
}
void MainWindow::report()
{
QGeoCodeReply *pQGeoCode
= dynamic_cast<QGeoCodeReply*>(sender());
// process reply
std::ostringstream out;
out << "Reply: " << pQGeoCode->errorString().toStdString() << '\n';
switch (pQGeoCode->error()) {
case QGeoCodeReply::NoError: {
// eval result
QList<QGeoLocation> qGeoLocs = pQGeoCode->locations();
out << qGeoLocs.size() << " location(s) returned.\n";
for (QGeoLocation &qGeoLoc : qGeoLocs) {
QGeoAddress qGeoAddr = qGeoLoc.address();
QGeoCoordinate qGeoCoord = qGeoLoc.coordinate();
out
<< "Coordinates for "
<< qGeoAddr.text().toUtf8().data() << ":\n"
<< "Lat.: " << qGeoCoord.latitude() << '\n'
<< "Long.: " << qGeoCoord.longitude() << '\n'
<< "Alt.: " << qGeoCoord.altitude() << '\n';
}
} break;
#define CASE(ERROR) \
case QGeoCodeReply::ERROR: out << #ERROR << '\n'; break
CASE(EngineNotSetError);
CASE(CommunicationError);
CASE(ParseError);
CASE(UnsupportedOptionError);
CASE(CombinationError);
CASE(UnknownError);
#undef CASE
default: out << "Undocumented error!\n";
}
// log result
log(out.str());
// clean-up
/* delete sender in signal handler could be lethal
* Hence, delete it later...
*/
pQGeoCode->deleteLater();
}
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
// main application
QApplication app(argc, argv);
// setup GUI
MainWindow win;
win.show();
// runtime loop
app.exec();
// done
return 0;
}
Note:
The look and behavior is the same like for the above example. I changed the output of reply a bit.
While preparing this sample, I realized that it is actually not necessary to set the address of the returned QGeoLocation as it is already there. IMHO, it is interesting that the returned address looks a bit different than the requested. It seems that it is returned in a (I would say) normalized form.

qt: How to send control command to POS printer?

I am creating an application which prints text through a POS printer.
The prints works fine. But for POS printer there are control commands to do certain functions like : paper cut, cashdraw open etc.. For eg:
Function: Partial cut
Code:
ASCII———-> ESC i
Hex ————-> 1B 69
Decimal—-> 27 105
When I try to send command 27 105 it just prints on paper instead of performing action.. I’m not exactly sure how to send it… Can someone suggest how to write to the socket…
#include "lanprinterui.h"
#include "ui_lanprinterui.h"
LanPrinterUI::LanPrinterUI(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::LanPrinterUI)
{
ui->setupUi(this);
m_TextInput = ui->textEdit;
m_pSocket = new QTcpSocket();
m_pSocket->connectToHost("192.168.1.20", 9100);
m_ConnectStatus = true;
QObject::connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(print()));
}
LanPrinterUI::~LanPrinterUI()
{
delete ui;
delete m_pSocket;
}
void LanPrinterUI::print()
{
const int Timeout = 5 * 1000;
if (!m_ConnectStatus)
{
m_pSocket->connectToHost("192.168.1.20", 9100);
}
if (!m_pSocket->waitForConnected(Timeout))
{
//sent error
qDebug ("error in waitForConnected()");
qDebug (qPrintable(m_pSocket->errorString()));
m_ConnectStatus = false;
return;
}
m_ConnectStatus = true;
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << m_TextInput->toPlainText();
out << '\n';
m_pSocket->write(block);
}
What you want is
out << "\n\x1Bi";
That is, you want, after the '\n' char, to send the '\x1B' char (also known as "escape") and the 'i' char. You could also have written this as:
out << '\n' << "\x1b\x69";
or:
out << '\n' << char(27) << char(105);
or:
out << '\n' << char(0x1b) << char(0x69);
(or any other valid combination)
Another, better idea, would be to put in your class:
class LanPrinterUI {
private:
static const QString PARTIAL_PAPER_CUT = "\x1bi";
static const QString CASHDRAWER_OPEN = "\x1b....";
//...
};
And then you would just:
out << '\n' << PARTIAL_PAPER_CUT;
(which would be much better than hardcoded constants)

Qt c++ save object to a file

I'm trying to save an object called f to a file, getting errors: no match for operator << in stream << f
here is the function:
void FilmWriter::saveFilm(Film& f){
QString fileName = QFileDialog::getSaveFileName(this,("Save File"));
if (fileName != "") {
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
QMessageBox::critical(this, ("Error"),("Could not open file"));// error message
} else {
QTextStream stream(&file);
stream << f;
stream.flush();
file.close();
}
}
}
Please let me know if you need any more information?
These are 2 functions in a different class filmInput
void FilmInput::getFilm(){
Film f1(titleEdit->toPlainText(),durationEdit->toPlainText().toInt() ,directorEdit->toPlainText(),
QDate::fromString(relDateEdit->toPlainText(),"dd/MM/YYYY"));;
obtainFilmData(f1);
}
void FilmInput::obtainFilmData(Film &f){
saveFilm(f);
}
QTextStream is made for storing text, not Film. You need something that can store your object. Maybe QDataStream will help you? But you'll need to serialize your Film object to something like QByteArray.Update:
Now I see that you need Film::toString() method that will give you a string representation of Film object. Then you just write stream<<f.toString(); instead of stream<<f;. Or you can implement operator<< that takes QTextStream and Film.
Example of Film::toString():
QString Film::toString()
{
return mTitle + " " + mDuration + " " + mDirector + " " + mDate.toString();
}
with the function below (which may not be 100% syntacticly correct) you can now write to your stream, Film.toString()
QString Film::toString()
{
QTextStream stream;
stream << someFilmVariable << " " << someOtherFilmVariable;
return stream.string()
}

Qt Qvariantlist conversion into javascript array unsuccessful

I'm currently create an apps in Meego using QML and JS on most of the part. and now I stumbled upon a problem.
From javascript I want to call a C++ function to read text file, parse it, and then return an array of the parsing result.
so I create a Q_INVOKABLE function called parse() and call it through javascript
function parse() {
var myArray = new Array();
myArray = parser.parse("/home/user/MyDocs/angklungtext.txt")
if(myArray === undefined){
console.log("null found");
}
for(var i = 0; i < myArray.length; i++){
console.log(myArray[i][0] + "," + myArray[i][1])
}
}
and here is the parse function in C++
QVariantList* QMLParser::parse(QString filename)
{
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug()<< dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists())
{
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
QVariantList* myList = new QList<QVariant>;
while(!stream.atEnd())
{
QString line = stream.readLine();
qDebug() << line.trimmed();
QStringList lineList = line.split(":");
myList->append(lineList);
}
file.close();
return myList;
}
sadly.
when I try to run it it giving a result like this
start debugging
"/home/user/MyDocs/angklungtext.txt"
"/home/developer"
"/home/user/MyDocs/angklungtext.txt"
"1:1000"
"4:2000"
"5:3000"
"2:4000"
null found
file:///opt/memoryreader/qml/memoryreader/myjs.js:8: TypeError: Result of expression 'myArray' [undefined] is not an object.
looks like the C++ parse function successfully parsing the file. it can read it and it can save it into the QVariantList.
but after it return the result into javascript myArray still [undefined].
is there something wrong with the conversion?
Just simplify the C++ side like this :
QVariant QMLParser::parse(QString filename)
{
QStringList myList;
qDebug() << "start debugging";
qDebug() << filename;
qDebug() << QDir::currentPath();
QDir dir;
qDebug() << dir.absoluteFilePath(filename);
QFile file(filename);
if(!file.exists()) {
qDebug() << "File: " << file.fileName() << "tidak ditemukan";
return NULL;
}
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Tidak dapat membuka file" << file.fileName() << "untuk ditulis";
return NULL;
}
QTextStream stream(&file);
while(!stream.atEnd()) {
QString line = stream.readLine();
qDebug() << line.trimmed();
myList << line.trimmed().split(":");
}
file.close();
return QVariant::fromValue(myList);
}
And it should work !
Just remember, QML must see a QVariant, even if a QList is wrapped inside it, and Qt is able to convert most of its base types to QVariant using QVariant::fromValue(T) so use it extensively.
Oh and BTW a QVariant is reference not pointer.
Haven't done this myself, so I'm just thinking out loud. But I note that you're returning a pointer to a QVariantList...which looks suspect. (Also: if you new, then who would do the delete?)
Have you tried returning it by value?