How to load QTranslator from database? - qt

There is no way to load QTranslator from my own way.
I want to exclude .ts files from architecture of my app. I just want to load my languages from databse, whitch will be update from anywhere. And i don't want to load any files(.ts). Does exists the way somthing like this:
QTranslator::load(QStringList)??? QStringList is a language pairs.

The QTranslator::translate method is virtual - which means you can simply create your own translator that extends QTranslator and override this (and one other) method:
class MyTranslator : public QTranslator
{
public:
MyTranslator(QStringList data, QObject* parent) :
QTranslator(parent)
{
// ...
}
bool isEmpty() const override {
return false; //or use your own logic to determine if data contains translations
}
QString translate(const char *context, const char *sourceText, const char *disambiguation = nullptr, int n = -1) const override {
// Use the data to somehow find your translation
}
};

I understand your goal. Why don't you get the data from your database, save it as temporary file, load via QTranslator (regular way), then delete the temporary file?
Another option is maybe the overload for:
bool QTranslator::load(const uchar *data, int len, const QString
&directory = QString())
(from: http://doc.qt.io/qt-5/qtranslator.html#load-2 ), which would allow you to load from your own structure without temp file.

Related

How can I access functions of this abstract class?

Im currently working with an UI tool (Qt Creator 9.5.9) to create UI Interfaces. While messing with the tool i came across following problem:
The following code is from an automatically generated cpp file which is generated when creating a new project.
At the top there are a few functions which I assume can be used to access and possibly change data points.
I want to use the function SetWriteDP() to write my data to the data points.
/**
// register ids
bool registerReadIds(const QList<unsigned int> &ids);
bool registerReadIds(const QUintSet &ids);
bool registerReadIds(const QUintSet &ids, void (*func)(void*, const QUintSet &));
bool registerWriteIds(const QList<unsigned int> &ids);
bool registerWriteIds(const QUintSet &ids);
// read data point values
unsigned int GetReadDP(const unsigned int &id) const;
int GetReadDPInt(const unsigned int &id) const;
float GetReadDPFloat(const unsigned int &id) const;
QString GetReadDPString(const unsigned int &id) const;
// write data point values
void SetWriteDP(const unsigned int &id, const unsigned int &value);
void SetWriteDP(const unsigned int &id, const int &value);
void SetWriteDP(const unsigned int &id, const float &value);
void SetWriteDP(const unsigned int &id, const QString &value);
// execute sql statement
QSqlQuery execSqlQuery(const QString &query, bool &success) const;
**/
#include "hmi_api.h"
#include "widget.h"
#include "ui_arbaseform.h"
#include <iostream>
HMI_API::HMI_API(QWidget *parent) :
AbstractAPI(parent), m_ui(NULL)
{
Widget *widget = dynamic_cast<Widget *>(parent);
if(!widget) return;
m_ui = widget->ui;
QUintSet readIdsToRegister, writeIdsToRegister;
writeIdsToRegister.insert(10001);
registerReadIds(readIdsToRegister);
registerWriteIds(writeIdsToRegister);
SetWriteDP(100001, 69);
}
I tried using the function in another cpp file in different ways:
HMI_API.SetWriteDP()
HMI_API.Abstract_API.SetWriteDP()
This resulted in this error: expected unqualified-id before . token
AbstractAPI::SetWriteDP()
which resulted in this error: cannot call member function 'void DPObject::SetWriteDP(const unsigned int&, const int&, unsigned int)' without object AbstractAPI::SetWriteDP();
the i tried making a DPObject which resulted in this error: cannot declare variable 'test' to be of abstract type 'DPObject'
Im really at my wits end now how to access this function. Can someone maybe explain to me what happens after "HMI_API::HMI_API(QWidget *parent) :" and why it is possible to use the function in that block and how i can make it possible for me to use this function.
I tried reading the documentation but nowwhere in the documentation this function is ever mentioned.
The function works in the code snippet i posted but doesnt when i want to use it in another function, i know its because of some stuff regarding classes but im dont understand how to work around this in this case.
Thanks in advance!
how i can make it possible for me to use this function.
I might be wrong but from my understanding of C++ you would first have to create an object of the class, in this case that would be
HMI_API *uiName = new HMI_API(some_parent_obj);
With QWidget being your earlier created QWidget, you can then call the function using a .
uiName.SetWriteDP(x,y);
Can someone maybe explain to me what happens after "HMI_API::HMI_API(QWidget *parent) :
after "HMI_API::HMI_API(QWidget *parent)" the class makes it clear that it inherits base functionality from the classes AbstractAPI and m_ui, you can learn more about inheritance here :https://www.learncpp.com/cpp-tutorial/basic-inheritance-in-c/
Afterwards im not sure but it looks like it just creates some basic functionality so you can call the functions using the class.
I found an answer to my problem which in hindsight might have been obvious but i dont know how i should have known.
I was able to use the functions by declaring a new function like this:
void HMI_API::myFunction(int arg1){
my code with the functions i wanted to use
}
I really hope this will help someone that might had some understanding problems as well.

How to use QKeySequence or QKeySequenceEdit from QML?

Is it possible to use a QKeySequence or QKeySequenceEdit in QML? I only see the documentation for C++ https://doc.qt.io/qt-5/qkeysequence.html#details
To provide context, I want a QKeySequence to be input by the user of the application so that I can pass it to my C++ backend so that I can hook into native OS APIs and also serialize it to file.
I do not want to actually establish the shortcut within Qt.
I created a new object that wraps the QKeySequence::toString and makes it available from QML so I wouldn't have to re-implement a massive switch-case in QML.
#ifndef QMLUTIL_H
#define QMLUTIL_H
#include <QObject>
#include <QKeySequence>
// A singleton object to implement C++ functions that can be called from QML
class QmlUtil : public QObject{
Q_OBJECT
public:
Q_INVOKABLE bool isKeyUnknown(const int key) {
// weird key codes that appear when modifiers
// are pressed without accompanying standard keys
constexpr int NO_KEY_LOW = 16777248;
constexpr int NO_KEY_HIGH = 16777251;
if (NO_KEY_LOW <= key && key <= NO_KEY_HIGH) {
return true;
}
if (key == Qt::Key_unknown) {
return true;
}
return false;
}
Q_INVOKABLE QString keyToString(const int key, const int modifiers){
if (!isKeyUnknown(key)) {
return QKeySequence(key | modifiers).toString();
} else {
// Change to "Ctrl+[garbage]" to "Ctrl+_"
QString modifierOnlyString = QKeySequence(Qt::Key_Underscore | modifiers).toString();
// Change "Ctrl+_" to "Ctrl+..."
modifierOnlyString.replace("_", "...");
return modifierOnlyString;
}
}
};
To expose this in QML, you have to say engine.rootContext()->setContextProperty("qmlUtil", new QmlUtil()); in your main.cpp where you are setting up your QQmlEngine.
Then you can type qmlUtil.keyToString(event.key, event.modifiers) in QML to turn a keyboard event to a string.
You can combine that with the solution here https://stackoverflow.com/a/64839234/353407 replacing the individual cases with a single function call to qmlUtil.keyToString
You can set a string to the sequence property from Shortcut, see Qt docs.
For example if you want to chain Ctrl+M and Ctrl+T, you specify the following:
Shortcut {
sequence: "cltr+m,ctrl+t"
onActivated: console.log("you activated turbo mode")
}
It's even possible to assign multiple keyboard shortcuts to the same action, using the sequences (plural) property: Qt docs

using getOpenFileName in a handler

I have implemented the getOPenFileName in a handler in qt (in a when_pushbutton_clicked more specifically). How can I save the produced string in a QString in main rather than inside the handler?
You can use a signal connection to save in a QString variable the path of your file name.
const QString fileName = QFileDialog::getOpenFileName(0, tr("Select the file"), getLastDirectory(), "Txt Files (*.txt)");
if (fileName.isEmpty()) {
// No file was selected
return;
}
// then emit the signal
emit fileWasSelected(fileName);
In your main function you cant handle the event in the main class by a simple connection:
QObject::connect(yourClass, &YourClass::fileWasSelected, [&](const QString& filename) {
// Now, do what you want with your path
}):
Another way, its to save the file in a private variable, and set up a getter:
class MyClass {
....
public:
inline QString path() const { return _path; }
private:
QString _path;
}
And then access to the variable from the main.

Qt tr() translation with static members and namespaces

I'm working on translation our Qt GUI project.
*.ts file is generated successfully.
I filled *.ts file with translations using Qt Linguist.
But at runtime, translation with namespaces and static members does not work.
Other translations (when tr() method calls in class, that are inherited from QObject) works ok.
I have the following code (translation does not work):
Example with namespaces:
// example with namespaces
// declaration in header
namespace Error
{
namespace RadionetworkInput
{
QString alreadyInUse = QT_TR_NOOP("already in use");
char requestFailed[] = QT_TR_NOOP("request failed");
}
}
Usage in cpp:
// usage in cpp code0
QString error0 = Error::RadionetworkInput::alreadyInUse;
QString error1 = tr(Error::RadionetworkInput::requestFailed);
Example with static members:
// example with static members
// declaration in header
namespace Error
{
class RadionetworkInput
{
public:
static const QString alreadyInUse;
static const char requestFailed[];
}
QString Error::RadionetworkInput::alreadyInUse = QT_TR_NOOP("already in use");
char Error::RadionetworkInput::requestFailed[] = QT_TR_NOOP("request failed");
}
Usage in cpp code
// usage in cpp code
QString error0 = Error::RadionetworkInput::alreadyInUse;
QString error1 = tr(Error::RadionetworkInput::requestFailed);
Example, with working translation:
class ViewNetwork : public QObject
{
Q_OBJECT
public:
explicit ViewNetwork(QString name = tr("New Radionetwork"));
};
Usage in code:
ViewNetwork::ViewNetwork(QString name)
{
QString dummy = name;
}
Using QObject::tr() instead QT_TR_NOOP() macro does not help.
Problem is your understanding how it works. With static members variables they are initialized before main function starts.
This means two thing:
they are initialized before QApplication object is created and before yuo load translation files! (I'm surprised that this didn't lead to a crash)
value is calculated only once (not updated if translation changes)!
What you should do? Just change static variable to functions:
// example with namespaces
// declaration in header
namespace Error
{
namespace RadionetworkInput
{
QString alreadyInUse() { return QT_TR_NOOP("already in use"); }
QString requestFailed() { return QT_TR_NOOP("request failed"); }
}
}
and
// example with static members
// declaration in header
namespace Error
{
class RadionetworkInput
{
public:
static QString alreadyInUse();
static QString requestFailed();
}
QString Error::RadionetworkInput::alreadyInUse() { return QT_TR_NOOP("already in use"); }
QString Error::RadionetworkInput::requestFailed() { return QT_TR_NOOP("request failed"); }
}
Returning translation as char[] is pointless, co I've corrected that also (I don't know why you did it).

Qt Dynamic translation of dialog windows

I am creating a Qt application and I added dynamic translation (I followed the example at http://www.qtcentre.org/wiki/index.php?title=Dynamic_translation_in_Qt4_applications) with a QCombobox which lists different languages. It works well but the problem is that I don't see how to translate dynamically the text in the dialog windows (for example YES and NO buttons).
In the main.cpp, before executing the app, I have :
QTranslator qtTranslator;
qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
a.installTranslator(&qtTranslator);
which translate the dialog Windows in the user system language but I would like to do it dynamically like the rest of my app.
Here are the code of the example :
application.h :
#ifndef APPLICATION_H
#include <QApplication>
#include <QHash>
#include <QStringList>
class QDir;
class QTranslator;
typedef QHash<QString, QTranslator*> Translators;
class Application : public QApplication
{
Q_OBJECT
public:
explicit Application(int& argc, char* argv[]);
~Application();
static void loadTranslations(const QString& dir);
static void loadTranslations(const QDir& dir);
static const QStringList availableLanguages();
public slots:
static void setLanguage(const QString& locale);
private:
static QTranslator* current;
static Translators translators;
//static QTranslator* qtTranslator;//test to translate dialog windows
};
#endif // APPLICATION_H
application.cpp :
#include <QDir>
#include <QFileInfo>
#include <QTranslator>
#include <QLibraryInfo>
#include "application.h"
QTranslator* Application::current = 0;
//QTranslator* Application::qtTranslator = 0;//test to translate dialog windows
Translators Application::translators;
Application::Application(int& argc, char* argv[])
: QApplication(argc, argv)
{
}
Application::~Application()
{
}
void Application::loadTranslations(const QString& dir)
{
loadTranslations(QDir(dir));
QString locale = QLocale::system().name().section('_', 0, 0);
QString language=locale+ "_" + locale;
if(!QFile::exists(":Localization/Localization/"+language+".qm"))//if system language is not available, load english version
setLanguage("en_en");
else
setLanguage(language);
}
void Application::loadTranslations(const QDir& dir)
{
// <language>_<country>.qm
QString filter = "*_*.qm";
QDir::Filters filters = QDir::Files | QDir::Readable;
QDir::SortFlags sort = QDir::Name;
QFileInfoList entries = dir.entryInfoList(QStringList() << filter, filters, sort);
foreach (QFileInfo file, entries)
{
// pick country and language out of the file name
QStringList parts = file.baseName().split("_");
QString language = parts.at(parts.count() - 2);
QString country = parts.at(parts.count() - 1);
// construct and load translator
QTranslator* translator = new QTranslator(instance());
if (translator->load(file.absoluteFilePath()))
{
QString locale = language + "_" + country;
translators.insert(locale, translator);
}
}
}
const QStringList Application::availableLanguages()
{
// the content won't get copied thanks to implicit sharing and constness
return QStringList(translators.keys());
}
void Application::setLanguage(const QString& locale)
{
//test to translate dialog windows
/*
QTranslator qtTranslator;
QString qTLocale=locale.mid(0,2);
qtTranslator->load("qt_"+ qTLocale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
installTranslator(qtTranslator);
//*/
// remove previous
if (current)
{
removeTranslator(current);
}
// install new
current = translators.value(locale, 0);
if (current)
{
installTranslator(current);
}
}
I added the lines commented with "//test to translate dialog Windows" to try the dynamic translation of the dialog Windows but it doesn't work (no error at compilation but the application isn't launched with error message "the program stopped suddenly", I am on Qt Creator). Thanks!
So I finally got this to work after having the same problems. There are two things which were wrong in my case:
Name of the qt translation file:
QTranslator qtTranslator;
qtTranslator.load("qt_de"); // worked in older qt versions
qtTranslator.load("qtbase_de"); // works for qt5.2
a.installTranslator(&qtTranslator);
Have the correct parent for the QMessageBox. This is obvious after you think about it but pretty easy to miss.
QMessageBox::information(someChildOfMainWindow, ...);
For the latter, if you happen to be in a class which is a QObject but not a QWidget you can also use the following code to access your MainWindow from anywhere:
QMainWindow* mw = 0;
foreach(QWidget* widget, QApplication::topLevelWidgets()) {
if(widget->objectName() == "<your-main-window-class-name-here>") {
mw = qobject_cast<QMainWindow>(widget);
}
}
Ok Sébastian Lange, so finally I created the box and didn't use the static ones (
QMessageBox::question(..) for example)
QMessageBox quitMessageBox;
quitMessageBox.setWindowTitle(tr("Quit"));
quitMessageBox.setWindowIcon(QIcon("myIcon.jpg"));
quitMessageBox.setIcon(QMessageBox::Question);
quitMessageBox.setText(tr("Quit the application?"));
quitMessageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
quitMessageBox.setDefaultButton(QMessageBox::No);
quitMessageBox.button(QMessageBox::Yes)->setText(tr("Yes"));
quitMessageBox.button(QMessageBox::No)->setText(tr("No"));
And then
quitMessageBox.exec();
Like that it's ok. Thanks again!
When providing buttons for the dialog use
tr("Yes")
as for default dialogs, the created .ts-language file (to be edited via QtLinguist) should have default translations included.
The tr() marks the given argument to be translated. This concludes to if you do not know what will be written on a given label, you cannot translate it...

Resources