how to create static QLabel in Qt - c++

Is it possible to create some static QLabels in one class, and other classes can access its QLabels variable and apply changes to the QLabels without creating its object?
I found some answers online like if you want to access one class variables without creating its object in another class, you have to make its data static.
So basically what I am trying to do here is accessing and changing one class variables, for me it is QLabels, in another class without creating its object.
I know how to create static variables, but when comes to declare a staic QLabel, I found it difficult to achieve it.

I think you may just make the label accessible, i.e. expose it as a public member. Say you have a Form class, and a label QLabel in its ui. Add this method to the class:
public:
QLabel * label();
the implementation is just:
QLabel *Form::label()
{
return ui->label;
}
If all you need to expose is the label text property, just add these two accessors methods:
public:
QString labelText();
void setLabelText(QString & text);
in implementation file:
QString Form::labelText()
{
return ui->label->text();
}
void Form::setLabelText(QString &text)
{
ui->label->setText(text);
}
These last strategy fits encapsulation better.
About having it static: what if you have more than one instance of the Form class? Which label is supposed to be pointed to by the static member? If you are 100% sure you will have only one instance of the widget, you can add a static public QLabel * member:
public:
static QLabel * label;
in implementation file, on top:
QLabel *Form::label = 0;
in Form constructor:
ui->setupUi(this);
if(label == 0)
{
label = ui->label;
}
Again, this makes sense if you have one Form instance only. Otherwise, the static pointer will point forever to the label of the widget which was created first (and, dangerously, to nothing when that instance gets destroyed).

Related

Qt and C++: Overwrite or Expand Class

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.

Binding instance of C++ object to QML object

I'm new to Qt, and have written a basic application which has one class which inherits from QObject and is bound to a QML file.
I now want that class to contain a Vector of objects (let's say from a class Customers), which contains some data, such as a QString for name, etc.
To make life easier I'll create these objects manually in main, and place some text fields in my QML file.
I now want to be able to bind specific objects to specific text fields in the QML file, such that when a value changes, the value in the text field updates.
How can this be done? It looks like QML statically calls methods of the classes it's bound to, instead of on an assigned object.
I feel like QAbstractList may have some use here, but not too sure. Would rather not have to inherit from anything for my Customers class.
EDIT:
I think I may be able to do what I want with a QObjectList-based Model (https://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html). I notice it says at the bottom that "There is no way for the view to know that the contents of a QList has changed. If the QList changes, it is necessary to reset the model by calling QQmlContext::setContextProperty() again."
Does this mean that if a value inside DataObject (such as name) changes, the model has to be reset, or only when the Qlist itself changes (i.e. new item added, or item deleted)? If the latter, I would think this should be fairly easy to maintain as I would only need to set the context property whenever anything is added or deleted.
This may be usefull if you want to process raw QObject instance in QML script. You can append properties to Element class and modify them from qml.
class Element : public QObject {
Q_OBJECT
private:
QString type;
QLinkedList<Element*> child;
public:
explicit Element(QString type, QLinkedList<Element*> child);
virtual ~Element();
public:
QLinkedList<Element*> getChild() const;
QString getType() const;
public:
static void printTree(Element* root);
};
this is so simple you need to use NOTIFY
define your properties like this :
Q_PROPERTY (QString name READ name WRITE setName NOTIFY nameChanged)
then you need to define each one like this :
public : QString name() const;
signals :
void nameChanged(QString name);
public slots:
void setName(const QString &name);
private QString _name;
and then you should define body in cpp like this :
QString className::name() const{
return _name;
}
void className::setName(const QString &name){
if(name==_name) return;
_name = name;
Q_EMIT nameChanged(_name);
}
after registering it to QML with qmlRegisterType<ClassName>("com.className",1,0,"className");
simply set name it will notify if it changes for example in a textfield set text to that name property

Reading a QList<QPoint> in QML

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.

Classes, Objects, Treewidget and QlistWidget

I'm trying to create a program for a project in school (University).
The program is basically supposed to have a QTreeWidget with a bunch of components, the QTreeWidget will update when you click on a button (for example Chassis-button will change the QTreeWidget into a bunch of different chassis).
From the QTreeWidget, you're then supposed to be able to mark one that you want and click on a "choose-button" which will transfer that row to a QListWidget. One example of a row could be :
"Fractal Design"
"R3"
"100euro"
"ATX"
I have a bunch of classes for each component. One of the classes is Chassis and it has a function named addChassis which looks like this :
void ChassisHandler::addChassis(string manufacturer, string model, int price, string size, string color, int fanSpots) {
Chassis **temp = new Chassis*[this->nrOfChassis + 1];
for (int i = 0; i < nrOfChassis; i++)
{
temp[i] = this->chassis[i];
}
delete[] this->chassis;
this->chassis = temp;
this->chassis[this->nrOfChassis] = new Chassis(manufacturer, model, price, size, color, fanSpots);
this->nrOfChassis++;
}
This function works fine if I want to create a class object and add a few chassis into the object and then print out the object, but I can not use it to add chassis into the treewidget. It needs to be QString instead of string and int and Qt seems to have a problem with me making a class object and then transfer the object to the treewidget. I simply do not have enough knowledge to be able to put all the chassis into the QTreeWidget. Right now I've created an additional function in my .cpp file that belongs to the .ui file which look like this :
void Computer::AddChassi(QString manufacturer, QString model, QString price, QString size, QString color, QString fanSpots){
QTreeWidgetItem *itm = new QTreeWidgetItem(ui->treeWidget);
itm->setText(0, manufacturer);
itm->setText(1, model);
itm->setText(2, price);
itm->setText(3, size);
itm->setText(4, color);
itm->setText(5, fanSpots);
}
But if I try to put this function in the Chassiclass, it says that "UI is not defined". It's very important that we use classes in this project.
So my two problems are :
How to create proper addfunctions to put strings into my TreeWidget?
How to transfer the wanted string from my TreeWidget to my ListWidget?
if I try to put this function in the Chassi class, it says that "UI is
not defined".
Your AddChassi() method looks mostly correct, except of course you are trying to dereference a variable named "ui" and (it appears that) there is no member variable named "ui" that is part of your Computer class, which is why you get that compiler error. Presumably the pointer "ui" is one that is available for use only in other contexts (e.g. because it is a member variable of another class), so making it available for use inside AddChassi() is just a matter of passing it in -- you could pass it every time as one of the arguments to AddChassi() if you want, or you could pass it in to the Computer class's constructor and hold it as a member variable of the Computer class for later use. Or, perhaps better yet, instead of passing in the ui pointer, just pass in the pointer to the QTreeWidget object, since that is the only thing you really need to pass in to the QTreeWidgetItem constructors anyway.
For example:
void Computer::AddChassi(QTreeWidget * tw, QString manufacturer, QString model, QString price, QString size, QString color, QString fanSpots){
QTreeWidgetItem *itm = new QTreeWidgetItem(tw);
[...]
my Second problem is to transwer the wanted string from my TreeWidget
to my ListWidget
The QTreeWidget class has various accessor functions (such as currentItem() and topLevelItem()) that you can use to obtain a pointer to one of the QTreeWidgetItems objects current attached to the QTreeWidget. Once you have that pointer, you can call the QTreeWidgetItem::text(int) method on it to extract the QString representing the text in the nth column of that item's row. Once you have that QString you can use it to create a new QListWidgetItem with that QString as its constructor argument.

Options for program

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.