Object order creation QT for C++ and QML - c++

I'm developing an application in Qt/QML in a Linux environment. As the application grown bigger several issues appeared.
A particular issue is related to a C++ objecttranslator referred inside the QML sources. The project builds correctly and the translator object works for almost all the items in QML. However, in some places, I get the wrong text. Consider the following example:
Text{
x: 1036; y: 108
id: incomingLabel
text: qsTr("Weather") + translator.tr; // referred object
color: "white";
font.pixelSize: 34
}
In the case I got "WeatherUndefined" as text, all appended. My guess is that when this QML text element requires the text attribute, the translator object is not yet created and that causes the tr to be undefined.
This is how I register the C++ class in QML:
Translator translator(app.data(),":/translations");
viewer.rootContext()->setContextProperty("translator", &translator);
It should be noted that the problem does not appear on Windows but only in my Linux environment.
The complete code for the translator class is:
Yes translator.tr is a read only property. The translator code is:
#include "translator.h"
#include <QDebug>
Translator::Translator(QApplication *app, const QString &source, QObject *parent) :
QObject(parent),
m_app(app),
m_source(source)
{
addTranslation("DE", "lang_de_DE.qm");
addTranslation("ES", "lang_es_ES.qm");
addTranslation("FR", "lang_fr_FR.qm");
addTranslation("IT", "lang_it_IT.qm");
}
void Translator::addTranslation(const QString &name, const QString &file)
{
if (!m_translations.contains(name))
m_translations.insert(name, file);
}
QString Translator::tr()
{
return "";
}
void Translator::setSource(const QString &source)
{
m_source = source;
}
void Translator::translate(const QString &language)
{
if (language == "EN")
removeTranslation();
if (m_translations.contains(language))
{
QString langURL = m_translations.value(language).toString();
if (m_qtTranslator.load(langURL, m_source))
{
removeTranslation();
m_app->installTranslator(&m_qtTranslator);
emit languageChanged();
}
}
}
void Translator::removeTranslation()
{
m_app->removeTranslator(&m_qtTranslator);
emit languageChanged();
}
The header file:
#ifndef TRANSLATOR_H
#define TRANSLATOR_H
#include <QObject>
#include <QVariantMap>
#include <QtWidgets/QApplication>
#include <QTranslator>
class Translator : public QObject
{
Q_OBJECT
Q_PROPERTY(QString tr READ tr NOTIFY languageChanged)
public:
explicit Translator(QApplication *app, const QString &source, QObject *parent = 0);
void addTranslation(const QString &name, const QString &file);
void setSource(const QString &source);
Q_INVOKABLE void translate(const QString &language);
QString tr();
signals:
void languageChanged();
private:
QApplication *m_app;
QString m_source;
QVariantMap m_translations;
QTranslator m_qtTranslator;
void removeTranslation();
};
#endif // TRANSLATOR_H
Any ideas? Thank you in advance.

You need to check whether the problem lies in translator or tr.
If translator is not created yet, you will get this error in the console:
ReferenceError: translator is not defined.
And you won't see Weatherundefined in your Text object.
If translator exists but not tr, then translator.tr will return undefined, so you will get this output when calling qsTr("Weather") + translator.tr:
Weatherundefined
I suggest you call some console.log() to pinpoint the problem:
Text{
x: 1036; y: 108
id: incomingLabel
text: {
console.log(translator);
console.log(translator.tr);
return qsTr("Weather") + translator.tr(); // referred object
}
color: "white";
font.pixelSize: 34
}
Also I notice that your translator object is allocated on stack, that could cause problem too.

Related

SFML crashes when closing with wxWidgets

I am using an SFML view integrated inside a wxWidgets frame. I used the code sample on the SFML website (which is quite old but I got it to work making a few tweaks) to do this. And then started fleshing out my project from that base class. However, I am at the stage now where I need to create and delete many SFML+wxWidgets windows based on user actions, however SFML crashes whenever I close its parent wxWidgets window.
I get the following error:
Cannot close SFML area when SFML is integrated in a NSView.
All the SFML+wxWidgets examples on the web I found face this error when I run it after closing. This error should not be an issue if the user only needs to close the window once, but I am managing many windows over the user session, so if it crashes once, it brings down the whole app with it.
Here is the section of the header file code for the base class combining wxWidgets and sfml, everything else is specific to my app, and not to the error:
class ChessWidgetBase : public wxControl, public sf::RenderWindow {
public:
ChessWidgetBase(wxWindow* parent, wxSize size);
virtual ~ChessWidgetBase() {};
private:
DECLARE_EVENT_TABLE()
virtual void HandleLeftDown(wxMouseEvent&) {}
virtual void HandleLeftUp(wxMouseEvent&) {}
virtual void OnUpdate() {};
void OnIdle(wxIdleEvent&);
void OnPaint(wxPaintEvent&);
void OnEraseBackground(wxEraseEvent&);
};
This code is based off this minimum reproducable example I used from the internet to make the above class:
#include <iostream>
#include <wx/wx.h>
#include <memory>
#include <SFML/Graphics.hpp>
#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif
using namespace std;
static const int kDefaultWindowWidth = 1280;
static const int kDefaultWindowHeight = 720;
static const int kCanvasMargin = 50;
struct wxSfmlCanvas : public wxControl, public sf::RenderWindow
{
wxSfmlCanvas(
wxWindow *parent = nullptr,
wxWindowID windowId = -1,
const wxPoint &position = wxDefaultPosition,
const wxSize &size = wxDefaultSize,
long style = 0) :
wxControl(parent, windowId, position, size, style)
{
createRenderWindow();
}
virtual void onUpdate(){};
void onIdle(wxIdleEvent& event)
{
// Send a paint message when control is idle, to ensure max framerate
Refresh();
}
void onPaint(wxPaintEvent& event)
{
wxPaintDC dc(this); // Prepare control to be repainted
onUpdate(); // Tick update
display(); // Draw
}
// Explicitly overriding prevents wxWidgets from drawing, which could result in flicker
void onEraseBackground(wxEraseEvent& event){}
void createRenderWindow()
{
#ifdef __WXGTK__
gtk_widget_realize(m_wxwindow);
gtk_widget_set_double_buffered(m_wxwindow, false);
GdkWindow *gdkWindow = gtk_widget_get_window((GtkWidget*)GetHandle());
XFlush(GDK_WINDOW_XDISPLAY(gdkWindow));
sf::RenderWindow::create(GDK_WINDOW_XWINDOW(gdkWindow));
#else
sf::RenderWindow::create(GetHandle());
#endif
}
void setwxWindowSize(const wxSize& size)
{
this->SetSize(size);
}
void setRenderWindowSize(const sf::Vector2u& size)
{
this->setSize(size);
}
virtual ~wxSfmlCanvas(){};
wxDECLARE_EVENT_TABLE();
};
struct Canvas : public wxSfmlCanvas
{
Canvas(
wxWindow* parent,
wxWindowID id,
wxPoint position,
wxSize size,
long style = 0) :
wxSfmlCanvas(parent, id, position, size, style)
{
}
virtual void onUpdate()
{
clear(sf::Color::Yellow);
// TODO: Do some sprite drawing or whatever
}
void onResize(wxSizeEvent& event)
{
auto size = event.GetSize();
auto newCanvasWidth = size.x - (2 * kCanvasMargin);
auto newCanvasHeight = size.y - (2 * kCanvasMargin);
// Resize Canvas window
this->setwxWindowSize({newCanvasWidth, newCanvasHeight});
this->setRenderWindowSize({(unsigned int)newCanvasWidth, (unsigned int)newCanvasHeight});
}
};
struct AppFrame : public wxFrame
{
AppFrame(const wxString& title, const wxPoint& pos, const wxSize& size) :
wxFrame(NULL, wxID_ANY, title, pos, size),
_panel(new wxPanel(this)),
_canvas(new Canvas(
_panel.get(),
wxID_ANY,
wxPoint(kCanvasMargin, kCanvasMargin),
wxSize(kDefaultWindowWidth - (2 * kCanvasMargin), kDefaultWindowHeight - (2 * kCanvasMargin))
))
{
_panel->SetBackgroundColour(*wxCYAN);
////////////////////////////////////////////////////////////////////////////////
// Probably due to some RTTI, IDE is getting confused by this dynamic call
// and doesn't understand the correct Bind overload. Causes non sequitur errors
// to display in the inspector. Suppress.
//
// Dynamic binding is cleanest here, since we don't want to hook up our resize
// handler until our dependencies (Canvas namely) have finished their initialization
////////////////////////////////////////////////////////////////////////////////
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wint-conversion"
Bind(wxEVT_SIZE, &AppFrame::onResize, this);
#pragma clang diagnostic pop
////////////////////////////////////////////////////////////////////////////////
}
void onResize(wxSizeEvent& event)
{
_canvas->onResize(event);
event.Skip();
}
unique_ptr<wxPanel> _panel;
unique_ptr<Canvas> _canvas;
};
struct App : public wxApp
{
virtual bool OnInit()
{
auto frame = new AppFrame("SFML Canvas Demo", wxPoint(100, 100),
wxSize(kDefaultWindowWidth, kDefaultWindowHeight));
frame->Show(true);
return true;
}
};
wxBEGIN_EVENT_TABLE(wxSfmlCanvas, wxControl)
EVT_IDLE(wxSfmlCanvas::onIdle)
EVT_PAINT(wxSfmlCanvas::onPaint)
EVT_ERASE_BACKGROUND(wxSfmlCanvas::onEraseBackground)
wxEND_EVENT_TABLE()
wxIMPLEMENT_APP(App);
(if you want to run it you might have to install sfml+wxwidgets)
Any ways to handle closing a window that prevents a crash with wxWidgets+SFML? Just need some ideas and a couple lines of code to show them, no need for complete examples...
To fix this error upgrade SFML to version >= 2.6.0. You cannot find this in the downloads site for SFML as it hasn't been released yet, so you must install from the Github directly over here and build it from source: https://github.com/SFML/SFML/tree/2.6.x.

Storing a std::function as a private member results in it being null when used

I am at a loss for why this isn't working. I've tried passing a function by value, by reference, and still when I go to call the function from within SetFromState, it is null.
My class:
StateIndicator::StateIndicator(QWidget *parent) {
StateIndicator(parent, StateIndicator::DefaultSelectionStrategy);
}
StateIndicator::StateIndicator(QWidget *parent,
const std::function<std::string (State)>& selectionStrategy)
:QWidget(parent),
selection_strategy_(selectionStrategy)
{
wrapped = new QLabel(this);
}
void StateIndicator::SetFromState(State state)
{
std::string resourcePath = selection_strategy_(state);
wrapped->setTextFormat(Qt::TextFormat::RichText);
char* buffer = new char[StateIndicator::label_format.length() + resourcePath .length()];
sprintf(buffer, label_format.c_str(), resourcePath .c_str());
wrapped->setText(buffer);
}
std::string TruckStateIndicator::DefaultSelectionStrategy(State state){
return ":img/Disconnected";
}
call:
StateIndicator* state = new StateIndicator(this);
ui->leftPaneLayout->insertWidget(1,state);
state->SetFromState(State::Connected);
When I use the debugger, in my constructor it shows that my selection strategy is set. But when I get to the call to SetFromState the private member selection_strategy_ is null.
However, my code works if within the SetFromState function I instead change it to:
std::function<std::string(TruckState)> strategy = &DefaultSelectionStrategy;
std::string path = strategy(state);
and assign the variable right there. It feels like something is going out of scope and causing my function pointer to become null, but I'm pretty much stuck.
Edited:
Here is the header file. I will also try to make the example minimal by removing the inheritance and trying to reproduce
#ifndef STATEINDICATOR_H
#define STATEINDICATOR_H
#include <QLabel>
#include "src/models/state.h"
class StateIndicator : public QWidget
{
public:
explicit StateIndicator(QWidget* parent);
explicit StateIndicator(QWidget* parent,
const std::function<std::string (State)>& selectionStrategy);
void SetFromState(State state);
private:
static std::string DefaultSelectionStrategy(State state);
QLabel* wrapped;
const std::function<std::string(State)> image_selection_strategy_;
inline const static std::string label_format = "<html><head/><body><p><"
"img src="%s"/>"
"</p></body></html>";
};
#endif // TRUCKSTATEINDICATOR_H
The problem was with how I was calling the overloaded constructor it seems:
StateIndicator::StateIndicator(QWidget *parent) {
StateIndicator(parent, StateIndicator::DefaultSelectionStrategy);
}
should be
StateIndicator::StateIndicator(QWidget *parent) :
StateIndicator(parent, StateIndicator::DefaultSelectionStrategy)
{
}

QT CPP How to solve ambiguous error when calling function?

I have a function for write data with using serial port.I am using the send function on several pages. I have not encountered such a problem before, but when I try to use it again on the same page, I get an error. When I try call function again I got
error: call of overloaded 'send(const char [6])' is ambiguous
here is my header file
#ifndef SETDATETIME_H
#define SETDATETIME_H
#include <QDialog>
#include <QTimer>
#include "serial.h"
namespace Ui {
class setdatetime;
}
class setdatetime : public QDialog
{
Q_OBJECT
public:
explicit setdatetime(QWidget *parent = nullptr);
~setdatetime();
void closeEvent(QCloseEvent *event);
public slots:
void curtime();
private slots:
void on_pushButton_clicked();
void on_detailSaveBtn_clicked();
private:
Ui::setdatetime *ui;
QTimer *timer;
Serial serialDateTime;
};
#endif // SETDATETIME_H
here is function I got error
void setdatetime::on_detailSaveBtn_clicked() {
QSerialPortInfo info;
QList<QSerialPortInfo> infoList = QSerialPortInfo::availablePorts();
foreach(info, infoList) QTextStream(stdout) << info.portName();
QString curport = info.portName();
if (!serialDateTime.isOpen()) {
if (serialDateTime.begin(QString(curport), 9600, 8, 0, 1, 0, false)) {
serialDateTime.send("HELLO"); // call to member function 'send' is ambiguous
serialDateTime.send(ui -> label -> text().toLatin1() + ui -> label_2 -> text().toLatin1()); //this working well
}
}
}
here is send function
bool Serial::send(QString message)
{
if (this->serialDevice->isOpen() && this->serialDevice->isWritable())
{
this->serialDevice->write(message.toStdString().c_str());
return true;
}
else
{
return false;
}
}
bool Serial::send(const QByteArray &message)
{
if (this->serialDevice->isOpen() && this->serialDevice->isWritable())
{
this->serialDevice->write(message);
return true;
}
else
{
return false;
}
}
How can I solve this issue ?
There is many meaning that warning can take. In your case, is say that your string litteral "HELLO" is a const char[6] but can be implicitly converted to a QByteArray or a QString.
The problem is that your compiler doesn't like that and prefer to know explicitly what to do.
You can either use the explicit keyword to prohibit implicit casting, or pass directly a QByteArray OR a QString explicitly converted to make your compiler know that you want to use one definition or the other.
serialDateTime.send(QByteArray::fromRawData("HELLO", 5)); // to call the QByteArray overload
serialDateTime.send(QString::fromUtf8("HELLO")); // to call the QString overload

Qt Custom Widget Failing to Build

I am attempting to make a custom widget/plugin to be interpreted by Qt Designer as a drag and drop element. Most works however I do get one error at the end of the build. Cannot convert argument 1 from 'QWidget *' to 'const GLineEdit &' I'm not too sure what this wants me to do to fix it, but not much is too sure. Here is my relevant source code:
GlineEditPlugin.cpp Snippet
QWidget *GLineEditPlugin::createWidget(QWidget *parent)
{
return new GLineEdit(parent);
}
GLineEdit.cpp
#include "glineedit.h"
GLineEdit::GLineEdit(const QString &str, const QString &color, QWidget *parent)
: QWidget(parent)
{
QVBoxLayout *layoutMain = new QVBoxLayout(this);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
m_header = new GLineEditHeader(this, str);
m_header->setStyleSheet("QLabel { color: " + color + "; }");
m_input = new GLineEditInput(this);
m_input->setStyleSheet(QString("QLineEdit { font-size: 12pt; padding-bottom: 5px; border: none; background-color: transparent; border-bottom: 2px solid %1; color: %1;}").arg(color));
layoutMain->addSpacerItem(new QSpacerItem(20, 15, QSizePolicy::Minimum, QSizePolicy::Fixed));
layoutMain->addWidget(m_input);
layoutMain->setContentsMargins(0, 0, 0, 0);
layoutMain->setSpacing(0);
connect(m_input, &GLineEditInput::focusChanged, m_header, &GLineEditHeader::zoom);
connect(m_input, &GLineEditInput::cleared, m_header, &GLineEditHeader::enableZoom);
}
GLineEdit.h
#ifndef GLINEEDIT_H
#define GLINEEDIT_H
#include "glineeditheader.h"
#include "glineeditinput.h"
#include <QWidget>
#include <QVBoxLayout>
class GLineEdit : public QWidget
{
Q_OBJECT
public:
GLineEdit(const QString &str, const QString &color, QWidget *parent = 0);
QString text() const;
QString title() const;
void setText(const QString &str);
void setTitle(const QString &str);
private:
GLineEditHeader *m_header;
GLineEditInput *m_input;
};
#endif //GLINEEDIT_H
This is not a Minimal, Complete, and Verifiable example, and you're missing to point at the line that's failing.
However, most probably your problem can be found here:
return new GLineEdit(parent);
Your class GLineEdit doesn't provide a constructor that takes a single argument of type QWidget*, only one that accepts multiple arguments. So the compiler tries to resort to the automatically created copy constructor, which looks like
GLineEdit::GLineEdit(const GLineEdit&)
Possible solutions:
Add the missing parameters to your constructor call.
Provide a constructor that accepts a pointer to a parent widget as only parameter.

QJsonValue is private?

I am learning C++ and trying to make something. But I ran into an error and I am not sure what's up. I am trying to create a simple thing that would accept an array, and turn it into JSON. But I'm getting an error
'QJsonValue::QJsonValue(const void*)' is private
within this context
file
#include "LoginDialog.h"
#include "ui_LoginDialog.h"
LoginDialog::LoginDialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::LoginDialog)
{
setWindowFlags(Qt::FramelessWindowHint);
ui->setupUi(this);
}
LoginDialog::~LoginDialog()
{
delete ui;
}
void LoginDialog::set_socket(Socket *socket)
{
socket = socket;
QJsonArray data;
data.prepend("Hello");
socket->sendData(data);
}
void LoginDialog::on_minimize_clicked()
{
setWindowState(Qt::WindowMinimized);
}
void LoginDialog::on_quit_clicked()
{
exit(1);
}
accepting function
void Socket::sendData(QJsonArray data)
{
qDebug() << data[1];
}
Your problem is here:
data.prepend("Hello");
The prepend member function takes in a QJsonValue, which happens to have many constructors. Passing in a const char* makes it ambiguous as to which one you are referring to. C++ compilers will resolve this to a bool before they would resolve it to a QString. To combat this, the author of QJsonValue did this:
private:
// avoid implicit conversions from char* to bool
inline QJsonValue(const void*) {}
In any event, you can fix this problem by being more explicit:
data.prepend(QStringLiteral("Hello")); // Qt 5
data.prepend(QLatin1String("Hello")); // Qt 4, Latin1 string
data.prepend(QString("Hello")); // Qt 4, non-Latin1 string
Look here for more information about QStringLiteral.