Access specific object from any class - qt

I am trying to access awesome object from another class. I declare this in main()
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtAwesome* awesome = new QtAwesome(&app);
awesome->initFontAwesome();
app.setWindowIcon(awesome->icon( "clipboard" ));
Login w;
w.show();
return app.exec();
}
Now how do I access awesome object from Login or any another class? Is it best to initialize a class in main() if I want to access from another class?

Declaring awesome in main() makes it scoped to the main() function, and thus only visible from with main(), or functions you explicitly pass it to from main().
The simple way to achieve what you want is to use an "external variable": Put the definition and declaration outside of the main() in your main executable file:
main.cpp:
QtAwesome * awesome = new QtAwesome(&app);
int main(int argc, char *argv[]) {
awesome->do_something();
// ...
}
The above is called the defining declaration of "awesome". In other files you want to use awesome in, use the extern storage specifier:
somerandommodule.cpp:
extern QtAwesome * awesome;
void some_function() {
awesome->do_something();
}
It's important that you have exactly one "defining declaration". The linker will make all extern awesome declarations point to this one definition.
If you are the one writing the QtAwesome class, another way of doing it is keeping the single instance in the QtAwesome class. This is roughly the "singleton pattern". This just makes it easier to tell where and when initialization is happening:
qtawesome.h:
class Awesome {
private:
static Awesome * singleton;
public:
static Awesome * getInstance() {
if(!Awesome::singleton)
Awesome::singleton = new Awesome();
return Awesome::singleton;
};
};
qtawesome.cpp:
#include "awesome.h"
Awesome* Awesome::singleton = 0;
somerandommodule.cpp:
#include "awesome.h"
void some_function() {
Awesome::getInstance()->do_something();
}

You have two options
pass a pointer or reference to awesome to the Login object, e.g. as an argument to the constructor of Login
use a singleton pattern or global variable (as suggested by S.Pinkus)
A global variable or singleton increases the coupling, i.e. the Login object becomes dependent on this specific QtAwesome object to exist.
Passing an object into places of usage enables you to use a specific QtAwesome object for each usage or use the same for multiple usages, etc.
Globally accessible objects, whether global variables or singletons, often make testing more complicated, since the need for such an object is not immediately visible and all tests within the same process access the same globally accessile object, potentially resulting in tests affecting each other in unexpected ways.

Related

How to expose global strings and ints to C++, QML, and JS

Our team is developing a Qt application which makes use of C++, QML, and JS. What is the best way to expose non-language specific strings, representing filenames and ints representing error codes, so that all languages can easily use them?
The most efficient and clean solution would be to implement those strings and ints as properties of a QObject, then create an instance of that object in main.cpp and register it as a singleton.
// before main()
YourType data;
static QObject * getData(QQmlEngine * e, QJSEngine *) {
e->setObjectOwnership(&data, QQmlEngine::CppOwnership); // just in case
return &data;
}
// in main()
qmlRegisterSingletonType<YourType>("Core", 1, 0, "Data", getData);
QQmlApplicationEngine engine;
//...
And now you have a global data for C++, and a global Data for QML. In the first case you will need to declare data as an extern in sources which need to access it, in the second case you will need to import Core 1.0 in order to access Data and its properties.

Qt Signals and slots - No matching function for call

I am learning QT and am trying to get my signals and slots working. I am having no luck.
Here is my Main
int main(int argc, char** argv) {
QApplication app(argc, argv);
FilmInput fi;
FilmWriter fw;
QObject::connect (&fi->okButton, SIGNAL( clicked() ), &fi, SLOT( okButtonClicked() )
); //Error received Base operand of '->' has non-pointer type 'FilmInput'
QObject::connect(&fi,SIGNAL(obtainFilmData(QVariant*)),&fw,SLOT(saveFilmData(QVariant*)));
//Error received No matching function for call to 'QObject::connect(Filminput*, const char*, FilmWriter*, const char*)
fi.show();
return app.exec();
}
and here is my sad attempt at signals and slots:
FilmInput.h
public:
FilmInput();
void okButtonClicked();
QPushButton* okButton;
signals:
void obtainFilmData(Film *film);
Here is FilmWriter.h
public slots:
int saveFilm(Film &f);
Here is Film Input.cpp
void FilmInput::okButtonClicked(){
Film *aFilm=new Film();
aFilm->setDirector(this->edtDirector->text());
emit obtainFilmData(aFilm);
}
Here is FilmWriter.cpp
void FilmInput::okButtonClicked(){
Film *aFilm=new Film();
aFilm->setDirector(this->edtDirector->text());
emit obtainFilmData(aFilm);
}
Please assist me in getting the signals and slots to work, I have spent hours but am no closer to getting it working. I have added the errors received in my comments above.
Regards
okButton is already a pointer, then you should remove the ampersand:
QObject::connect(fi.okButton, SIGNAL(clicked()), &fi, SLOT(okButtonClicked()));
(actually, be sure you create the button in FilmInput' constructor...)
Next, your methods signature doesn't match what you say in connect: given your functions, should be
Object::connect(&fi, SIGNAL(obtainFilmData(Film*)), &fw, SLOT(saveFilmData(Film*)));
this will work, because you are exchanging a pointer, and then Qt can make a copy of it. Otherwise, your type should be registered.
The first error is caused by &fi->okButton because -> has a higher precedence than &. See Operator Precedence. Easily fixed with (&fi)->okButton.
The second error is likely caused by one or both objects not inheriting from QObject. Signals and slots can only work between QObjects. Just a quick checklist:
Both sender and receiver must inherit from the QObject class
The Q_OBJECT macro must be used in the definition of each class
You must generate the appropriate meta-object code and compile it into your project. See Meta-Object Compiler
Also, if you're using Qt version 5.0 or higher, you should start passing function pointers to the connect methods instead of using the SIGNAL and SLOT macros. It'll provide compile-time checking of the connections.

how to translate string added dynamicaly in Qapp with Qtranslator?

i trying to created a Qt application multilanguage with Qt linguist.
I place this code in an function of my MainWindow :
translator.load(":/lang/English");
qApp->installTranslator(&translator);
ui->retranslateUi(this);
With the QTranslator declare in my MainWindow.h and all my string i want translate enclose by tr() . But with that, all QObject added dynamicaly by the code of my MainWindow.cpp, for example the title of a QTableWidget, are not translated.
If i place an other translator in my main.cpp, all my string are translate but i must created language button in my application and so i can't place translator in main.cpp.
Do you have an idea to help me?
Thx for your answers.
Gat
When you add a translation in your application using qApp->installTranslator(& aTranslator) then all the following calls to QObject::tr() (and similar functions) will look up in the translator for a translated text. So you should call retranslateUi() after qApp->installTranslator(). Actually you might event not call it there, you may reimplement QWidget::changeEvent() and intercept any QEvent::LanguageChange event.
void MainWindow::changeEvent(QEvent *e)
{
QMainWindow::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
// Someone called qApp->installTranslator() with a new translation.
// Let's update the user visible strings.
// This function was created by uic from the Designer form.
// It translates all user visible texts in the form.
ui->retranslateUi(this);
// This function must be written by you. It translates other user visible
// texts that are not in the form. See down for an example.
this->retranslateUi();
break;
default:
break;
}
}
ui->retranslateUi() just calls QObject::tr() for each user visible string in the ui. It is called automatically at the end of setupUi() and populates the form's widgets with translated text (have a look, it is defined by uic in ui_MainWindow.h file). You may want to take a similar approach with other user visible texts, like the title of a QTableWidget. All the strings are set in a function (named perhaps retranslateUi() for consistency) which is called at application starts (or, better, after the relevant widgets are created) and every time a new translations is loaded.
MainWindow::MainWindow(QWidget * parent)
: QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// Creates other widgets, but do not set their user visible texts.
tableWidget = new QTableWidget(this);
...
someControl = new QLineEdit(this);
someOtherControl = new QSpinBox(this);
someModel = new MyModel(this);
...
// Ok, *now* we set their texts.
this->retranslateUi();
}
...
void MainWindow::retranslateUi()
{
// This function will be called (either manually or automatically by
// `changeEvent()`) when a new translator has installed, hence all the `tr()`
// calls will return the right translation for the last installed language.
QStringList labels;
labels.append(tr("First column"));
labels.append(tr("Second column"));
labels.append(tr("Third column"));
tableWidget->setHorizontalHeaderLabels(labels);
someControl->setText(tr("Control name"));
someOtherControl->setText(tr("Other control name"));
// Perhaps you have a model that need to be retranslated too
// (you need to write its `retranslateUi()` function):
someModel->retranslateUi();
...
}
Also, please note that if you are doing something like
void MainWindow::someFunction()
{
...
QTranslator translator;
translator.load(":/lang/English");
qApp->installTranslator(& translator);
...
}
as soon as that function returns the variable translator gets destroyed, so next time QObject::tr() is called the address stored with qApp->installTranslator(& translator) will be invalid. So you must allocate translator on the heap with new (and possibly deleting it with delete when you do not need it anymore). An exception is if you are doing that in main() before calling QCoreApplication::exec() since that function is blocking and will not return until application is closed.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
...
QTranslator translator;
translator.load(":/lang/English");
app.installTranslator(& translator);
...
app.exec(); // This function will return only on application's exit.
// Hence `translator` will outlive the application, there is
// no need to worry about it.
}

How to send a Qt signal containing a cv::Mat?

In short, I get following error:
QObject::connect: Cannot queue arguments of type 'cv::Mat'
(Make sure 'cv::Mat' is registered using qRegisterMetaType().)
What I'm trying to do is send a signal containing two cv::Mat images from a QThread to the main thread, so that I can display the output. There's no compile time error, but when I run the program, it gets stuck at a breakpoint in qglobal.h (inline void qt_noop() {}).
I've tried to add Q_DECLARE_METATYPE(cv::Mat) to the code, to no avail. I'm quite suck with what to do now.
code
In a QThread class:
signals:
void sndFlow(cv::Mat &leftEye, cv::Mat &rightEye);
void eyesDriver::run()
{
forever
{
flow->draw(leftEye, rightEye);
sndFlow(leftEye, rightEye);
}
}
Capturing in a QObject class:
public slots:
void recFlow(cv::Mat &leftEye, cv::Mat &rightEye);
void myClass::recFlow(cv::Mat &leftEye, cv::Mat &rightEye)
{
cv::imshow("left", leftEye);
cv::imshow("rigth", rightEye);
cv::waitKey(40);
}
In main:
Q_DECLARE_METATYPE(cv::Mat)
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
qRegisterMetaType< cv::Mat >("cv::Mat");
// create objects from QThread and QObject class
QObject::connect(&qthread, SIGNAL(sndFlow(cv::Mat&,cv::Mat&)),
&qobject, SLOT(recFlow(cv::Mat&,cv::Mat&)));
qthread.start();
return a.exec();
}
Changing the signal-slot variables to QSharedPointer< cv::Mat > does not work either. Gives the same error:
QObject::connect: Cannot queue arguments of type 'QSharedPointer<cv::Mat>'
(Make sure 'QSharedPointer<cv::Mat>' is registered using qRegisterMetaType().)
WORKS
All right, it seems to work. I've move qRegisterMetaType< cv::Mat >("cv::Mat"); right before the QObject::connect call. However I still have to 'F5' past the breakpoint in qglobal.h, it works afterwards.
I might be wrong, but it seems that the location of qRegisterMetaType is not trivial.
You need to call qRegisterMetaType in addition to the macro (or instead of it, depending on your needs). This is necessary for the signals to be able to marshal your data across threads. However, it might be a wiser idea to pass by reference or smart pointer, or raw pointer if you are using the QObject hierarchy to manage the object lifetime.

Convert a QStandardItemModel to a QVariant

I'm trying to send a QStandardItemModel-derived object to PythonQt, but I'm a little confused on how it needs to be sent. When I was using boost::python I had several controls like boost::noncopyable to ensure I wasn't recreating this object, but sharing it with python. I also had constructs to provide a boost shared pointer to python from inside python.
class Scene : public boost::enable_shared_from_this<Scene>, public QStandardItemModel
In PythonQt, however, I'm not sure what's available. The function call takes a QVariantList for all the function parameters.
QVariant PythonQt::call(PyObject* object, const QString &callable, const QVariantList &args = QVariantList))
What I'm confused about now is how to get my object to python via a QVariant. Since its derived from QStandardItemModel, I figured it would already be register
void MyObject::someFunction(QString fileName)
{
QVariant myObjectV = qVariantFromValue(this);
// send to python
...
}
But this gives me the following error:
'qt_metatype_id' : is not a member of 'QMetaTypeId<MyObject>'
I've tried registering it after I declare my class, but this throws a different error.
class MyObject : public QStandardItemModel
{
Q_OBJECT
...
};
Q_DECLARE_METATYPE(MyObject)
QStandardItemModel::QStandardItemModel(const QStandardItemModel&) is private within this context.
I actually get the error twice--once in header where I add the Q_DECLARE_METATYPE and in another header, which has a class which always derives from QStandardItemModel but is otherwise unrelated.
Is Q_DECLARE_METATYPE even the correct way to go about converting this object to a QVariant?
BOOST_PYTHON_MODULE(scene)
{
class_("Scene");
}
Yes, by default, QVariant can take one of te following types - http://doc.qt.io/qt-4.8/qvariant.html#Type-enum - and they are not enough for your task. You should declare additional types by yourself via qmetatype system. Thus you shoud call qRegisterMetaType() function.

Resources