Calling qmlRegisterType() in the registered class on debug crashes application - qt

I want to use qmlRegiterType() in registered class itself. I tried to use method from this topic but whenever I try to run application in debug mode it crashes the application with error
read access violation at 0x0
Crashes on macro QML_GETTYPENAMES inside qqml.h (235 line).
TestClass.h:
class RegisterQmlTest : public QObject
{
Q_OBJECT
public:
explicit RegisterQmlTest(QObject *parent = 0);
};
TestClass.cpp:
QML_REGISTER(RegisterQmlTest);
RegisterQmlTest::RegisterQmlTest(QObject *parent) : QObject(parent)
{ }
void RegisterQmlTest::foo()
{
qDebug() << "Foo test";
}
I tried to compile application on MSVC2013x64 on Qt 5.6.2, on Windows.

You are not the only one that it is happening to : https://github.com/benlau/quickflux/issues/7, and I believe it is likely due to the
static initialization order fiasco.
One solution could be to use Q_COREAPP_STARTUP_FUNCTION to ensure the call to qmlRegisterType is not done too early.
You can use this macro in a .cpp file like so :
static void registerMyQmlTypes() {
qmlRegisterType<MyType>("MyImortUri", 1, 0, "MyType");
}
Q_COREAPP_STARTUP_FUNCTION(registerMyQmlTypes)

I had the exact same issue. The problem is that the staticMetaObject associated to your class is not initialized at the moment the macro invokes the call to qmlRegisterType. As already stated in this answer (from the same topic), you're more flexible without macros. I solved this by introducing one static type per custom class.
appQmlRegister.hpp
#include <functional>
#include <QtQml>
#include <QList>
namespace app {
namespace Qml {
namespace Register {
auto Init() -> void;
static auto GetList()->QList<std::function<void(void)>>&;
template <class T>
struct Type {
Type() {
auto initializer = []() {
qmlRegisterType<T>();
};
GetList().append(initializer);
}
};
}
}
}
appQmlRegister.cpp
#include "appQmlRegister.hpp"
namespace app {
namespace Qml {
namespace Register {
auto Init() -> void {
for (auto registerFunc : GetList()) {
registerFunc();
}
}
auto GetList()->QList<std::function<void(void)>>& {
static QList<std::function<void(void)>> List;
return List;
}
}
}
}
The type app::Qml::Register::Type takes a template argument (the type of your custom class) and wraps the call to qmlRegisterType in a lambda. And that's the basic concept. Instead of an immediate call you now have full control of when to register all your custom types via app::Qml::Register::Init(). By calling that function at runtime but before starting the QML engine you can ensure that the staticMetaObjects are initialized properly and you're safe to register them.
This requires a bit of typing on a per-custom-class level though. You'd have to declare a static member in the header of the class you want to register in QML:
MyCustomClass.hpp
#include "appQmlRegister.hpp"
namespace app {
class MyCustomClass : public QObject {
Q_OBJECT
private:
static Qml::Register::Type<MyCustomClass> Register;
// stuff...
}
}
and then define it in the .cpp file like this:
MyCustomClass.cpp
#include "MyCustomClass.hpp"
namespace app {
Qml::Register::Type<MyCustomClass> MyCustomClass::Register;
}
This can of course be extended to support other sorts of type registration like registering uncreatable types, custom versions/names etc. I implemented this in a QML showcase/template project on GitHub
Hope this helps!

Related

QObject connect fails in Qt

everyone!
I am having a problem using QObject::connect with some custom classes I've created. First of all, I have created 2 classes that inherit from QObject, they are called: Valve and PushButton. They are instantiated inside controllers called PanelController and SynopticController, which are also QObjects. And these controllers are instantiated inside another class called MasterController, also a QObject. I find this information useful since I think it is a problem of referencing the classes or the way I might be instantiating my classes inside these controllers. I strongly think this, because in my main method, when I do the following snippet of code, the connection works:
...
avionics::synoptic::Valve valveTest(nullptr, avionics::synoptic::ValveName::ABV);
avionics::panel::PushButton pushButtonTest(nullptr, avionics::panel::PanelNames::RECIRC);
QObject::connect(&pushButtonTest, &avionics::panel::PushButton::onStateColorChanged, &valveTest, &avionics::synoptic::Valve::updateState);
...
Basically, the controller classes are:
// MasterController
class MasterController : public QObject {
...
private:
panel::PanelController* panelController{nullptr};
synoptic::SynopticController* synopticController{nullptr};
}
// Panel Controller
class PanelController : public QObject {
...
explicit PanelController(QObject *parent = nulptr){
this->pushButtons.append(new avionics::panel::PushButton(_panelController, avionics::panel::PanelNames::RECIRC));
}
private:
QList<avionics::panel::PushButton*> pushButtons{};
}
// SynopticController
class SynopticController : public QObject {
private:
QList<avionics::synoptic::Valve*> iceValves{};
explicit SynopticController(QObject *parent = nullptr) {
antiIcePneumaticLines.append(new avionics::synoptic::PneumaticLine(_synopticController, avionics::synoptic::PneumaticLineName::APU_2_ABV));
}
}
My problem is that when I do the same call for the QObject::connect either from my MasterController constructor or my main method, the signal doesn't call the slot function. I want to connect pushButtons to valves, and to do this I am using getters from my controllers. The call to QObject::connect that doesn't work is:
QObject::connect(panelController->getpushButtons().at(1), &avionics::panel::PushButton::onStateColorChanged, synopticController->getValves().at(1), &avionics::synoptic::Valve::updateState);
// Example of getter
QList<avionics::panel::PushButton*> PanelController::getPushButtons(){
return pushButtons;
}
I've put some prints inside the method that emits the signal and tried debugging it, but the signal is emitted and the slot isn't called. The classes return from the getters are not undefined or null, I've checked it. Let me know if something wasn't clear. Thanks in advance!

How to use protected function setLocalPort?

I should use setlocalport for my socket connection but the property is protected and i have an error of compilation.
This is in qt application.
m_pSocket = new QTcpSocket();
m_pSocket->setLocalPort(m_iLocalPort);
error: ‘void QAbstractSocket::setLocalPort(quint16)’ is protected
If you want to use protected member like a public one, then you should provide a custom class that is the child of the class whose protected method you intend to use. There is nothing that would forbid you to create a child class inheriting QTcpSocket, and then using the protected method you want. Example for the QTcpSocket case that has been described here can be the following.
// Let us define CustomTcpSocket, i.e. the class inheriting QTcpSocket
#pragma once
#include <QTcpSocket>
class CustomTcpSocket
: public QTcpSocket
{
Q_OBJECT
public:
CustomTcpSocket(QObject* parent = nullptr);
virtual ~CustomTcpSocket();
// This method will be used to call QTcpSocket::setLocalPort which is protected.
void SetLocalPort(quint16 port);
};
Then, we provide the implementation itself.
#include "CustomTcpSocket.h"
CustomTcpSocket::CustomTcpSocket(QObject* parent)
: QTcpSocket(parent)
{
}
CustomTcpSocket::~CustomTcpSocket()
{
}
void CustomTcpSocket::SetLocalPort(quint16 port)
{
// Since method is protected, and scope is the child one, we can easily call this method here.
QAbstractSocket::setLocalPort(port);
}
Now we can easily use this newly created class in the following way.
auto customTcpSocketInstance = new CustomTcpSocket();
customTcpSocketInstance->SetLocalPort(123456);
Through usage of polymorphism, instances of CustomTcpSocket should be accepted by other Qt's APIs. However, there is no guarantee it will work as you would expect it to. Qt developers wanted this method to be protected for some of the reasons. So, use it with caution.

Returning managed pointer from a clone method

In C++11, two types of "managed" pointer types were introduced - shared_ptr and unique_ptr. Let's now assume we have a set of classes that support a clone() method, such as foo->clone() would return a copy of the foo object. If your goal was to return a managed pointer from the clone() method, how would you allow the user of the interface to select which kind of pointer he wants to be returned?
As a sub-question, would you rather return a raw pointer from the clone() method and let the user construct either shared_ptr or unique_ptr by himself? If not, why?
The standard smart pointer to manage a dynamic allocation is always unique_ptr. By contrast, shared_ptr is a very specific tool with specialized features (e.g. type-erased deleter, weak pointer observers) and higher costs (virtual dispatch, locked atomic operations) that should only be used when you definitely know you want it. Public raw pointers are a taboo out of principle, and so the natural clone interface looks like this:
struct Base
{
// must have virtual destructor to destroy through base pointer
virtual ~Base() {}
// non-leaf classes are abstract
virtual std::unique_ptr<Base> clone() const = 0;
};
struct Derived : Base
{
virtual std::unique_ptr<Base> clone() const override
{
return std::unique_ptr<Derived>(new Derived(*this));
// or "return std::make_unique<Derived>(*this)" in C++14
}
};
(Unfortunately, we cannot use any kind of covariant return types here, since the template classes unique_ptr<Base> and unique_ptr<Derived> are unrelated. If you prefer to have a clone function that returns the derived type, you could add a non-virtual function like direct_clone that returns a std::unique_ptr<Derived>, and implement the virtual clone() in terms of that.)
Something along this lines would give you the means to select the kind of smart pointer returned. Would probably be better if encapsulated in a mixin Clonable class template, for maintainability and reusability of the idea.
#include <iostream>
#include <memory>
class Base {
public:
virtual ~Base() {
std::cout << "deleting Base\n";
}
template <template <typename ...Args> class SmartPtr>
SmartPtr<Base> clone() {
return SmartPtr<Base>(this->inner_clone());
}
virtual void speak() const = 0;
private:
virtual Base *inner_clone() const = 0;
};
class C: public Base {
public:
~C() {
std::cout << "deleting C\n";
}
template <template <typename ...Args> class SmartPtr>
SmartPtr<C> clone() {
return SmartPtr<C>(this->inner_clone());
}
void speak() const {
std::cout << "I am C and I inherit from Base!\n";
}
private:
C *inner_clone() const override {
return new C(*this);
}
};
// End boilerplate.
int main()
{
auto original = C{};
// the declarations below should use auto, and are just explicitly typed to
// show the correct return type of clone();
std::shared_ptr<C> shared = original.clone<std::shared_ptr>();
std::unique_ptr<C> unique = original.clone<std::unique_ptr>();
// the declarations below show it working through conversion to a base class
// smart pointer type
std::shared_ptr<Base> sharedBase = original.clone<std::shared_ptr>();
std::unique_ptr<Base> uniqueBase = original.clone<std::unique_ptr>();
// the declarations below show it working through the base class for real
std::shared_ptr<Base> sharedBaseFromBase = sharedBase->clone<std::shared_ptr>();
std::unique_ptr<Base> uniqueBaseFromBase = uniqueBase->clone<std::unique_ptr>();
shared->speak();
unique->speak();
sharedBase->speak();
uniqueBase->speak();
sharedBaseFromBase->speak();
uniqueBaseFromBase->speak();
}
Compiles with gcc 4.8.1, and should in any compiler supporting variadics.
I would still prefer to simply return a unique_ptr and move the result into a shared_ptr, which would be automatic since the call to clone() is in itself an rvalue.

gtest hangs during deconstructing fixture when a mock returns a mock as default value

I have found a strange behavior I can't understand nor resolve. I have a factory FooFactory, which delivers some real-live objects of type Foo. To test method calls of Fooobjects I mocked FooFactory, in that way that MockFooFactory returns MockFooobjects for which I can expect calls.
The tests (not included) are working fine, but after the test gmock/gtest hangs (seems like mutex problem) during the deconstruction of MockFooFactory. To be precise the deletion of the Default ON_CALL leads to problems when the Mutex is created.
There must an issue with the smart pointers, when I build a version without smart pointers, it works fine. But the software I test uses shared_ptr as smart pointers, and so I can't get rid of them.
Here is a sample I build which reproduces the error:
#include <boost/shared_ptr.hpp>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
class Foo
{
public:
void doSomething() {}
};
typedef boost::shared_ptr<Foo> FooPtr;
class FooFactory {
public:
FooPtr create() {
return FooPtr(new Foo());
}
};
typedef boost::shared_ptr<FooFactory> FooFactoryPtr;
class MockFoo : public Foo {
public:
MOCK_METHOD0(doSomething, void());
};
typedef boost::shared_ptr<MockFoo> MockFooPtr;
class MockFactory : public FooFactory
{
public:
MOCK_METHOD0(create, FooPtr());
};
typedef boost::shared_ptr<MockFactory> MockFactoryPtr;
using ::testing::Return;
class Fixture : public ::testing::Test {
protected:
virtual void SetUp() {
mockFoo = MockFooPtr(new MockFoo());
mockFactory = MockFactoryPtr(new MockFactory());
ON_CALL(*mockFactory, create()).WillByDefault(Return(mockFoo));
}
MockFactoryPtr mockFactory;
MockFooPtr mockFoo;
};
TEST_F(Fixture, Test)
{
/* Not needed */
}
Has anyone experienced the same problem or has a solution for it?
Okay after updating to the trunk version of gmock everything is fine, because they fixed this issue:
https://code.google.com/p/googlemock/issues/detail?id=79

Derive UIC generated Qt UI class from custom interface

I've a simple Qt Question. I want that automatically generated UIC files are derived from a custom interface class like in:
Intention
class MyUiInterface {
public:
virtual void setupUi(QWidget* w) = 0;
virtual void retranslateUi(QWidget*w) = 0;
};
Generated UIC file should look like:
class Ui_MyWidget {
public:
void setupUi(QWidget* w) {
...
}
void retranslateUi(QWidget* w) {
...
}
};
namespace Ui {
class MyWidget : public MyUiInterface , public Ui_MyWidget {};
}
Why?
Every Ui::Class would then implement MyUiInterface. In each class that derives from Ui::Class (see The Multiple Inheritance Approach) I would be able to call setupUi and retranslateUi which makes sense if the class that derives from UI::Class class is a base class either. I want every widget to be derived from my abstrcat base class MyWidgetBase. Consider following:
class MyWidgetBase abstract : public QWidget, protected MyUiInterface {
protected:
void changeEvent(QEvent *e) {
QWidget::changeEvent(e);
if (e->type() == QEvent::LanguageChange) {
retranslateUi(this); // Still abstract here
}
}
};
class MyWidget : public MyWidgetBase : public Ui::MyWidget {
};
The effect is, every time MyWidget::changeEvent() is callled, retranslateUi of that specific class is called. Otherwise changeEvent had to be reimplemented in each class. This would be a bit against "code reuse" concept.
I think Qt UIC is not able to handle this situation isn't it? Is there a similar way to solve this problem?
Unfortunately, reading XML Schema for ui files is telling us that this is not possible to automate using uic compiler.
However, it is unclear to me why you would want to implement that automatically - even if the Uic somehow manages to implement your interface, you will still need to add bodies of the functions by hand, editing generated .h file, as I am sure that there is no way to include custom code in xml file which will translate as C++ code.
Why you just don't reimplement setupUi and retranslateUi in your MyWidget class? Every Ui class will have one of these classes, so you can implement this on this level, instead of base class. It is possible that I am missing something, but I see this as an appropriate way to do this.
class MyWidget : public MyWidgetBase, public Ui::MyWidget {
public:
void setupUi(QWidget* w) {
...
}
void retranslateUi(QWidget* w) {
...
}
};
With this approach, you don't need to reimplement changeEvent() in any of your custom widgets, and changeEvent will still call the appropriate retranslateUi().

Resources