I have created a class Atom that extends the Qt class QGraphicsItem like this:
Atom::Atom(qreal rad, qreal mass, int element, int state) : QGraphicsItem()
{
// Initialization code
}
void Atom::changeState(int newState)
{
// Code...
}
Then, I add my atom to the scene like this:
Atom *a=new Atom(rad,mass,element,state);
a->setPos(pos);
scene->addItem(a);
However, Qt converts my Atom class to a QGraphicsItem class. Now, when I call scene->items(), I get a QList of QGraphicsItems, which do not have the properties and methods of my Atom class.
So, I am asking the question: How would I go about getting a list of the Atoms that I have added to my QGraphicsScene?
Thanks.
You'll need to cast the QGraphicsItems to Atoms. Please see this question for details:
Subclassing QGraphicsItem prevents me from being able to use itemAt() on a QGraphicsScene/View
No. Your items are not converted to anything. They are still of your custom type. In C++, all objects of a derived class are also of class they derive from. Nothing is converted so nothing is lost.
Do a dynamic_cast<Atom*>(item) and you will get your item back.
Related
I want to add some properties (like an ID) to a QPushButton. Therefore, I need to expand or overwrite the class Q_WIDGETS_EXPORT QPushButton : public QAbstractButton
How do I do that?
Thanks for the help.
you dont need to extend the class to just put an id in it ... instead make use of the property system.
as specified in the official doc here:
A property can be read and written using the generic functions QObject::property() and QObject::setProperty(), without knowing anything about the owning class except the property's name.
you just have to do:
ui->myButton->setProperty("Id", 123456);
can also be another object e.g a string (or even your own class if you define it to do that)
ui->myButton->setProperty("_name", "123456");
to read the property is the method property() there for you but read the doc because you get a QVariant as return example:
QVariant(int, 123456)
It really depends on the use case. There is no problem (and often the intended way) in inheriting from Qt-(Widget) Classes (correct me, if I am wrong).
So you could do:
class MyQPushButton : public QPushButton
{
Q_OBJECT
public:
MyQPushButton() : QPushButton(...) {}
private:
int ID = -1;
}
Qt has a very good documentation and you can look at the sources to see what to override.
You could also extend a new class with QPushButton, but than you always have to deal with the QPushButton reference in your class, if you want e.g. connect something. In the inherited class you can connect the slots and so on. But for example you could do this:
class MyQPushButton
{
public:
MyQPushButton() {}
const QPushButton& const GetQPushButton() { return pushButton; }
const QPushButton* const GetQPushButtonPtr() { return &pushButton; }
private:
QPushButton pushButton;
int ID = -1;
}
There is no right and wrong. But I would use the inheritance for Qt-classes.
I have the following class definition:
class PlaneGridQML : public QObject
{
Q_OBJECT
........
Q_INVOKABLE QList<QPoint> getPlanesPoints() {
return m_PlaneGrid.getPlanesPoints();
......
}
In main I am making it available to the QML engine
PlaneGridQML pgq(10, 10, 3, false);
engine.rootContext()->setContextProperty("PlaneGrid",&pgq);
Then inside a QML Component I would like to do the following:
Connections {
target: PlaneGrid
onPlanesPointsChanged: {
var pointsArray = PlaneGrid.getPlanesPoints()
console.log(pointsArray[0].x)
}
}
I am getting an error "Unknown method return type: QList" and obviously I cannot read pointsArray and display its first member. According to the Qt documentation QPoint can be directly transferred as a JS type. On the other hand QPoint does not derive from QObject.
Can anyone explain how can I list the elements of the array ( the QPoints ) in the JS function?
Yes, a QPoint will be auto converted to QML, and even a QList of certain objects will get auto converted to QML, but just because QList<int> works and QPoint work, it is not necessary mean that QList<QPoint> will also work.
This is the list of automatic types in a list that QML supports:
QList<int>
QList<qreal>
QList<bool>
QList<QString> and QStringList
QList<QUrl>
QVector<int>
QVector<qreal>
QVector<bool>
As you see, QPoint is not one of them.
Wrapping in a QObject would be a waste.
But do not despair. I suggest you declare QList<QPoint> * as a meta type, then you can wrap that in a QVariant to pass it as a opaque pointer to QML. Then, in your PlaneGridQML or another, single QObject derived type, you implement an interface to get the size of the list and individual points at a given index.
You basically implement a standalone accessor / manipulator for lists of points. And you are all set.
I also strongly recommend that you use QVector instead of QList in this scenario.
class PlaneGridQML : public QObject
{
Q_OBJECT
........
Q_INVOKABLE QPoint get(int i) { return planesPoints[i]; }
...
}
...
console.log(PlaneGrid.get(0).x)
If you only have one plane grid and one set of points, you don't even need to pass the opaque pointer to QML, you can just directly use the plane grid to get the size and individual elements via index. Easy peasy.
You can expose QPoint to QML, but not QList<QPoint>.
I see three possible solutions to your problem:
Add arguments to PlaneGridQML::planesPointsChanged signal. You cannot expose QList<QPoint> but you can send two variables of type QList<qreal> as the signal arguments. One list could hold x values and another y values.
Implement int PlaneGridQML::getPlanesPointsCount() and QPoint PlaneGridQML::getPlanesPoint(int index). So you have two functions - one which returns how many points there are, and second which return point for each index.
Create a new class that will hold two variables (planePointX, planePointY) and return QQmlListProperty<NewClass> with PlaneGridQML::getPlanesPoints. However this approach is rather not a very good idea for your case (too complicated). More info.
I have a class structure that looks something like this:
template <typename T>
class Origin
{
public:
void SetOrigin(T x, T y) { __x = x; __y = y; }
void SetOrigin(vector2<T> vect) { __x = vect.x; __y = vect.y; }
private:
T __x;
T __y;
}
class Sprite : Origin<float>
{
public:
using Origin::SetOrigin;
}
class Text : Origin<int>
{
public:
using Origin::SetOrigin;
}
class Button : Sprite, Text
{
public:
using Sprite::SetOrigin;
using Text::SetOrigin;
}
The class Button should have 2 different origins, the origin of the Text (where is the text in the Button) and the origin of the Button itself.
I don't want to have to cast the argument to float or int, because it should be obvious what method is called, so I'd like to call the second one btn.SetTextOrigin(x, y).
In this very simple case, I can just reimplement the methods with different names, but I have to make as many implementations as there are overloads of SetOrigin in class Sprite.
Is there an easier way to use all SetOrigin methods with a different name than to reimplement all of them? (Implementing 20 functions just to have a different name is pretty boring.)
For example, is it possible to change the name of a method in the derived class without rewriting each overloaded function? I think of something like:
using Text::SetOrigin as SetTextOrigin;
or
using SetTextOrigin = Text::SetOrigin
But I haven't found anything, if there is nothing like that, what would you suggest doing in that case?
Well, it looks to me that the button is better implemented as containing Sprite and Text. It won't save you anything on typing, in fact, you'll likely write a little bit more code, but it be a cleaner design. The button is neither a sprite or text - it can have a sprite and a text. So making the sprite and text member variables would be a lot more straightforward way of expressing the nature of their relationship.
Also, should the button have an origin different from either the sprite or text, e.g. say, the location of button's corner?
Are all buttons on the system expected to have both the text and the image?
Is it possible to add other elements to the button with the origin. I don't know, maybe two text elements with different fonts?
In this case, you may end up aggregating the origin elements.
I believe that you can call the functions like this
button myButton;
myButton.text::setOrigin();
myButton.sprite::setOrigin();
You could implement two different named methods:
class Button : public Sprite, public Text
{
public:
void SetSpriteOrigin()
{
Sprite::SetOrigin();
}
void SetTextOrigin()
{
Text::SetOrigin();
}
private:
void SetOrigin(); // Prevent users from using this ambiguous method.
};
At the moment I'm writing an application which shows level measurement data into some graphs. Always I have date/time on x-axis and data on th y-axis. I use Qwt for this and modified QwtPlotPicker class to show proper time labels. I did this by derivation and redefining a member function:
class myQwtPlotPicker : public QwtPlotPicker {
Q_OBJECT
public:
explicit myQwtPlotPicker( QWidget* canvas, bool DateScale = false );
explicit myQwtPlotPicker( int xAxis, int yAxis, QWidget* canvas, bool DateScale = false );
explicit myQwtPlotPicker( int xAxis, int yAxis, RubberBand rubberBand, DisplayMode trackerMode, QWidget* canvas, bool DateScale = false );
virtual ~myQwtPlotPicker() {};
protected:
virtual QwtText trackerTextF( const QPointF &position ) const {
... redefinition of the label text ...
}
};
As you can see I also added a new parameter DateScale which turns date labels on or off. This works perfectly, but there is a class QwtPlotZommer which is derivated from QwtPlotPicker:
class QWT_EXPORT QwtPlotZoomer: public QwtPlotPicker { };
Now, the problem is, how do I get the class QwtPlotZommer to derive from myQwtPlotPicker and not from QwtPlotPicker?
Or course I could edit the Qwt sources, but there has to be a proper way of doing this.
I hope there is a proper way to do this. I would be glad, if someone could help me with this.
Try multiple inheritance:
class myQwtPlotZoomer : public QwtPlotZoomer, public QwtPlotPicker { };
There's no way to change class hierarchy at runtime in C++.
I guess that you should reconsider your design - you cannot and should not change the inheritance hierarchy of some library class.
Did you look at some examples to see how the classes you mentioned are intended to be used? Perhaps you should ask a new question to find out how to solve the problem you are actually facing (i.e. how to create a zoomable plot in qwt if I understand you correctly)
You have to overload QwtPlotZoomer reimplementing trackerTextF(). If you also have a use case of a standalone QwtPlotPicker - not being a QwtPlotZoomer - you have to do it twice:
class YourPicker: public QwtPlotPicker ...
class YourZoomer: public QwtPlotZoomer ...
As your implementation is a one-liner I don't see a problem in writing it twice, but if you want to avoid that, you have to put the code to some other class, that is called in both overloaded methods.
I am doing some algorithmic work using C++. My algorithms have some options which I need to be able to add to my program with as little effort as possible. I am currently using this code.
Everything works as expected: I added some code to my program so I can call the binary with arguments like -oopt1=val1,opt2=val2 and the options are set automatically.
The problem is that I am also writing a GUI at the same time. Now every kind of option has to be able to be set/requested using the GUI. However, I might need a spinbox for an integer value and a check box for a boolean option. I am using Qt as a toolkit, so I could just write a member
function that returns a QWidget* which is the appropriate base class.
However, I do not want any GUI-specific code in the header where I declare my options, since I would like to separate the GUI from the rest of the program. I could subclass any Option to create an appropriate QWidget*, but if I get a list of OptBase*, I wouldn't know what kind of widget I should create.
Is there some way that I can keep the GUI separated from the rest of the program while still being able to create appropriate widgets?
For me the solution is to create an abstract factory :
The factory should have an interface with two abstract methods to createBoolOption and CreateChoiceOption. Possibly more methods are needed
You can then make two concrete implementations of this interface where one is returning the same ones as you are doing now, but when you are running in QT you can use a different implementation that returns an optbase derived class that does know how to create a widget.
You can even use multiple inheritance (ie a second interface) so that you don't have to create a method in the first interface to specifically create a widget.
Of course then in running the QT application you have to explicitely cast to the second interface, when you want to create the widget.
The abstract factory itself should be passed to constructor of algobase. Ie dependency injection.
class ifactory{
public:
virtual Option<bool>* createBoolOption()=0;
virtual ChoiceOption<Mode>* createChoiceOption()=0;
virtual Widget* createWidget()=0; //here or in another interface
};
class ConcreteNonGuiFactory : public ifactory{
virtual Option<bool>* createBoolOption();
virtual ChoiceOption<Mode>* createChoiceOption();
virtual Widget* createWidget()={;};
};
class ConcreteGuiFactory : public ifactory{
virtual Option<bool>* createBoolOption();
virtual ChoiceOption<Mode>* createChoiceOption();
virtual Widget* createWidget();
};
class Algo1 : public AlgoBase{
public:
Algo1(ifactory& f):factory(f){
ChoiceOption<Mode>* opt = factory.createChoiceOption();
}
private:
ifactory factory;
}
If the creation of the widget is in a different interface you can reduce your dependencies.
In this example at least the widget has to be forward declared.
You need a bunch of variables to be accessed by both setter (GUI, commang-line parser) and getter (algorithm function). QVariant should be fine. As you options have names, they also have implicitly types. Getter should retrieve the value by their name and explicitly make type conversion. Setter shouldn't care - QVariant will.
Create a singleton instance which has a map of option-names. Implement slots triggered by GUI value-change signals, set values in map.
e.g:
class VarTable
{
static VarTable & instance(){ static VarTable inst; return inst; }
QMap<QString, QVariant> _map;
public:
void setVar( QString n, QVariant v ){ _map[n] = v };
QVariant getVar( QString n ) const { return _map[n]; }
};
//Call in Slot triggered by a value-change signal (e.g. QEditLine::returnPressed)
VarTable::instance().setVal( "option1", val1 );
//Regrieve in non-gui code
QString option1 = VarTable::instance().getVal( "option1" ).toString();
Regards
P.S.: I've not compiled the code, mey have some typos.