I am currently working in QT and recently I noticed something that really confused me.
As far as I can tell normally when we want to create a pointer we have to use the following syntax in C++:
int number = 10;
int* pNumber = &number;
(or something similar to that)
I wanted to create a pointer to a button which was created in QT design. It was for testing purposes only. (I am new to QT and c++ so I wanted to test things out)
But then I noticed something strange that I could not understand. for some reason when I created the pointer of type "OPushButton" with the name of "button" I did not have to use the "&" with the "(*ui).pushButton_5" syntax. (pushButton_5 is the name of my button in my ui)
The code works and the text "5" is added to my "lineEdit" in QT. How does this work? Am I missing something about pointers?
Here is my code:
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPushButton* button = (*ui).pushButton_5;
ui->lineEdit->setText((*button).text());
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.h:
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
& is not the way to create pointers, it's the way to acquire a pointer to a specific thing that you have access to.
If somebody else tells you where a thing is, you don't need the help of & to find out.
void g(int* q)
{
int* p = q; // 'q' is the location of some unknown 'int', and so is `p`.
}
You need & if you have a thing and want to know where that thing is.
void f()
{
int x = 5;
int* p = &x; // The location of 'x'.
g(&x); // Pass the location of 'x' to 'g'.
}
Also, we usually write x->y rather than (*x).y.
This convention makes a lot of sense if you look at more than one level of indirection – compare x->y->z->w to (*(*(*x).y).z).w.
Related
I need to access the mainWindow object in a different class. The problem is, that I can not give mainWindow to this class (I don't want to do this, it would make everything much more complicated). Question: Is there any way in C++ or Qt to put an object in something like a local "database" or sth where every other class in the project can look into and communicate with the objects.
What I want to have in the end is something like this:
// A.h
#ifndef A_H
#define A_H
class A{
public:
A() { /*here comes the ting*/ myMainWindow->sayHi(); }
};
#endif // A_H
// MainWindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "a.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
A *a = new A;
}
MainWindow::~MainWindow(){delete ui;}
MainWindow::sayHi(){
// just do anything
}
I don't think, this is possible, but I give it a try...
Thanks for answers!
I need to access the mainWindow object in a different class. The
problem is, that I can not give mainWindow to this class (I don't want
to do this, it would make everything much more complicated).
That is doable. The author don't want to expose the "main window" variable holding the reference or pointer to the object. And, obviously the author wants that UI object to be callable from other objects. In Qt that implies either both objects on UI thread or communication is via queued signal-slot connection only. But the direct call wanted, hence on the same thread.
Is there any way in C++ or Qt to put an object in something like a
local "database" or sth where every other class in the project can
look into and communicate with the objects.
Local thread storage is a known pattern to implement things like that. Qt has own implementation of it called QThreadStorage. You can attempt something like that:
// myLts.h
void ltsRegisterObject(const QString &key, QObject *object);
void ltsRemoveObject(const QString &key);
QObject* ltsGetObject(const QString &key);
template <typename T> T* ltsGet(const QString &key) {
return qobject_cast<T*>(ltsGetObject(key));
}
// myLts.cpp
static QThreadStorage<QMap<QString, QObject*> > s_qtObjects;
void ltsRegisterObject(const QString &key, QObject *object)
{
s_qtObjects.localData().insert(key, object);
}
void ltsRemoveObject(const QString &key)
{
if (!s_qtObjects.hasLocalData())
return;
s_qtObjects.localData().remove(key);
}
QObject* ltsGetObject(const QString &key)
{
QObject *object;
auto it = s_qtObjects.localData().find(key);
return it != s_qtObjects.localData().end() ? it.value() : nullptr;
}
Register main window object in LTS:
#include "myLts.h"
// ...
// register main window in LTS
ltsRegisterObject("mainWindow", &mainWindow);
Find and use the object:
#include "myLts.h"
// ...
// use main window from LTS
auto* pMainWnd = ltsGet<QMainWindow>("mainWindow");
if (pMainWnd)
pMainWnd->show();
P.S. I did not compile this. But it is not hard to fix if so.
I'm really stuck on one problem that I want to solve. the problem is that I have a Class for QMainWindow which holds the Ui variable for that form. Now I want to be able to edit that Form using the Ui variable in that class on a QDialog cpp file. I probably sound really stupid and I really have no idea how I should explain this, but I have code which maybe can help.
MainWindow.h:
#include "ui_mainwindow.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
Ui::MainWindow *ui;
}
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog.h"
Dialog *dialog;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
dialog->show();
}
QDialog.cpp:
#include "ui_mainwindow.h"
#include "mainwindow.h"
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
Ui::MainWindow *mainui;
void Dialog::on_pushbutton_clicked(){
mainui->label->setText("test");
}
So as you can see from the above code, it shows that I have a pointer to the Ui variable however its uninitialised, therefore it would lead to a SIGSEGV error, so how to do Initialize this pointer? any help here is highly appreciated, and even though this is probably really simple I just don't know what to do. (I have looked at other questions but I couldn't quite grasp what to do, so please explain what I am to do before linking me to a similar question. Also, I have left out the Dialog.h file as I didn't think it was needed, please tell me if I need to show it, thanks!).
Generally in C++ you should practice what is called encapsulation - keep data inside a class hidden from others that don't need to know about it. It's not good to have multiple pointers to the UI object as now all those other objects have to know how the main window UI is implemented.
In this case, what I would recommend is to use Qt's signals and slots mechanism to allow the dialog to tell the main window what you need it to do. That has the advantage that if you add more dialogs, or change how things are implemented in the main window, you don't need to alter the signal slot mechanism, and the details are hidden cleanly.
So - for your dialog, add a signal like this in the header file
class Dialog : QDialog
{
Q_OBJECT
signals:
void setTextSignal(QString text);
}
and in your main window header, add a slot.
class MainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void setTextSlot(const QString &text);
}
now in your method where the button is pressed,
void Dialog::on_pushbutton_clicked()
{
emit setTextSignal("test");
}
and in your main window
void MainWindow::setTextSlot(const QString &text)
{
mainUi->label->setText(text);
}
The final part is to connect the signal and slot together, which you would do in your main window function where you create the dialog:
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
connect(dialog, SIGNAL(setTextSignal(QString)), this, SLOT(setTextSlot(QString)));
dialog->show();
}
You can see there are many advantages to this; the Dialog no longer needs a pointer to the main window UI, and it makes your code much more flexible (you can have other objects connected to the signals and slots as well).
Short answere - your can't! If you want to create a new instance of the ui, you would have to do:
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(this);
However, the this-pointer for a UI created for a QMainWindow based class must inherit QMainWindow - thus, you can't.
In general, it is possible if you create your Ui based on a QWidget instead of a QMainWindow, since both inherit QWidget.
Alternativly, you could try the following:
QMainWindow *subWindow = new QMainWindow(this);
subWindow->setWindowFlags(Qt::Widget);
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(subWindow );
//... add the mainwindow as a widget to some layout
But I would guess the result will look weird and may not even work in the first place.
I Started learning Qt (5.5) a couple of days ago, and I recently got stuck on something when working with the connect function, specifically the SLOT parameter. I'm calling a member function from the same class that the connect function is called in, but when the SLOT function is triggered it acts like it's creating a new class object. It worked initially when I kept everything in the same class, but this problem popped up when I tried implementing a hierarchy. I wrote a short program to demonstrate my problem.
Main.cpp
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow QtWindow;
QtWindow.show();
return app.exec();
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QGridLayout>
#include "TopWidget.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QMainWindow *parent = 0);
private:
QWidget *mainWidget;
QGridLayout *mainLayout;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QMainWindow *parent) : QMainWindow(parent){
mainWidget = new QWidget(this);
mainLayout = new QGridLayout(mainWidget);
setCentralWidget(mainWidget);
TopWidget tWidget(this);
mainLayout->addWidget(tWidget.topWidget, 0, 0);
}
TopWidget.h
#ifndef TOPWIDGET_H
#define TOPWIDGET_H
#include <stdlib.h>
#include <QWidget>
#include <QPushButton>
#include <QGridLayout>
#include <QDebug>
#include <QErrorMessage>
class TopWidget : public QWidget
{
Q_OBJECT
public:
TopWidget(QWidget *parent);
QWidget *topWidget;
private:
QGridLayout *wLayout;
QPushButton *Button;
int memVar1;
int memVar2;
private slots:
void testConnect();
//void SlotWithParams(int a, int b);
};
#endif // TOPWIDGET_H
TopWidget.cpp
#include "TopWidget.h"
TopWidget::TopWidget(QWidget *parent) : QWidget(parent){
topWidget = new QWidget(parent);
wLayout = new QGridLayout(topWidget);
memVar1 = 123;
memVar2 = 321;
Button = new QPushButton("Click Me", topWidget);
connect(Button, &QPushButton::clicked, [=](){ TopWidget::testConnect(); });
}
void TopWidget::testConnect(){
qDebug("Button worked");
if(memVar1 != 123 || memVar2 != 321){
qDebug("Linking failed");
}else{
qDebug("Linking success");
}
}
Since I just started with Qt, I don't have a good feel for what's "proper" Qt code, and what I should avoid, so tips in that direction are also appreciated. The following is the qmake file, if that's important.
CONFIG += c++11
CONFIG += debug
CONFIG += console
QT += widgets
QT += testlib
SOURCES += main.cpp
SOURCES += MainWindow.cpp
SOURCES += TopWidget.cpp
HEADERS += MainWindow.h
HEADERS += TopWidget.h
Release:DESTDIR = bin/Release
Release:OBJECTS_DIR = obj/Release
Release:MOC_DIR = extra/Release
Release:RCC_DIR = extra/Release
Release:UI_DIR = extra/Release
Debug:DESTDIR = bin/Debug
Debug:OBJECTS_DIR = obj/Debug
Debug:MOC_DIR = extra/Debug
Debug:RCC_DIR = extra/Debug
Debug:UI_DIR = extra/Debug
When I run the program in debug mode and press the button, it outputs "Button worked" indicating the link to the function was successful, but then outputs "Linking failed" indicating that a new object was created rather than taking the old one. My knowledge of C++ is patchy, since I only pick up what I need to, and I spent hours yesterday trying to fix this, so forgive me if the fix is something ridiculously easy, but I've mentally exhausted myself over this.
The problem comes from this line:
TopWidget tWidget(this);
You are allocating tWidget on the stack, and it gets destroyed just at the end of the MainWindow constructor.
Replace by:
TopWidget * tWidget = new TopWidget(this);
Also, you should replace your connect line by this one
connect(Button, &QPushButton::clicked, this, &TopWidget::testConnect);
It appears that your slot is called even after the TopWidget is destroyed. Qt normally disconnects connections when sender or receiver are destructed, but it's not able to do that when you connect to a lambda.
And finally, you are doing something weird. What is the purpose of your TopWidget class besides just creating another widget and receiving signals on its slot? You never add the TopWidget to any layout, but just its child. TopWidget is never shown, so it should rather derive from QObject only.
This might come off as a very stupid question, but I have to write a very simple program, consisting of a line edit and push button.
This program has to be able to take inputs(numbers) from the user in the line edit area and every time the push button is pressed, store the number values within an array of size 10.
I have some experience with C++ but am just generally very confused with the GUI aspects of Qt. The GUI stuff is just way over my head so I apologize again if this is trivial! But if anyone could help me figure out how to do this you would be the coolest.
Thanks!
Things need to do
set a button and a lineedit either in ui or in constructor of mywindows.
set validator for int.
declare a slot for button, to pass the int in lineEdit to your data structure.
fixed array is not enough to store all the user input, you need to think about whether you need is a list, a dynamic array, a fixed array of stack or queue.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QList>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QList<int> m_list;
};
#endif // MAINWINDOW_H
mainwindows.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->lineEdit->setValidator(new QIntValidator(0, 9999, this));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
m_list.append(ui->lineEdit->displayText().toInt());
qDebug() << m_list;
}
Put lineEdit and button on form in Qt Designer or create it by yourself:
Create slot in header:
private slots:
void mySlot();
//do connection in dialog's constructor
connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(mySlot()));
//Write slot
void Dialog::mySlot()
{
QString str = ui->lineEdit->text()
//now str contains all your text you can put it in different arrays.
}
text() return QString, but if you sure that it is double, then call toDouble() method
QString str = ui->lineEdit->text().replace(",",".")
double var = str.toDouble();
Moreover you can set QDoubleValidator to lineEdit and user can input only double in this lineEdit. Search in web what validator is and use setValidator() method to set it to lineEdit.
here is my code:
//MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui>
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QTextEdit *textEdit;
};
#endif // MAINWINDOW_H
// MainWindow.cpp
#include "mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent)
{
textEdit = new QTextEdit();
}
MainWindow::~MainWindow()
{
delete textEdit;
}
//main.cpp
#include <QtGui>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Is it more efficient (here's the "Q[Objects] VS using Pointers?" part of the question) to:
1) Use pointers as I am actually doing or
2) Use objects (removing * + delete statement)
Thank you!
MainWindow::MainWindow(QWidget *parent)
{
textEdit = new QTextEdit(this);
}
MainWindow::~MainWindow()
{
}
For QObject members as pointers, you shouldn't use delete, the QTextEdit will probably be a child of MainWindow, so it will be deleted automatically.
It would, of course, be theoretically faster to use non-pointer QObject members, with one less level of indirection. Like this (for those who didn't understand the question):
class MainWindow : public QMainWindow {
...
private:
QTextEdit textEdit;
};
and there is also less code to type, because you don't have to retype the class name of the members to initialize them in the constructor.
But since QObject are themselves already heavily using indirection (with their d-pointer), the gain will probably be negligible. And the extra code you type with pointer members allows you to have a lower coupling between your header files and Qt, because you can use forward declarations instead of header inclusion, which means faster compilations (especially if you are not using precompiled headers yet) and recompilations.
Also,
manually deleting QObject pointer members, or
declaring QObject as non-pointers members
can causes double deletion, if you don't respectively delete/declare them in the right order (children then parents for deletion, or parents then children for declaration).
For example:
class MainWindow : public QMainWindow {
...
private:
QTextEdit textEdit;
QScrollArea scrollArea;
};
MainWindow::MainWindow() {
setCentralWidget(&scrollArea);
QWidget *scrolledWidget = new QWidget(&scrollArea);
QVBoxLayout *lay = new QVBoxLayout(scrolledWidget);
lay->addWidget(...);
lay->addWidget(&textEdit); // textEdit becomes a grand-child of scrollArea
scrollArea.setWidget(scrolledWidget);
}
When MainWindow is deleted, its non-static class members are deleted in the reverse order of their declaration in the class. So scrollArea is destroyed first then textEdit, but scrollArea also destroys its children including textEdit, so textEdit is effectively destroyed twice causing a crash.
So it is less error prone to use QObject members as pointers, and to not delete the QObject which have a parent yourself.
Try creating QLineEdit on the stack and then put it into layout... Quit your application... What do you see? HINT: launch your application in debugger.
ksming is right about reading documentation. It is not language specific issue. If you are asking what is faster: heap or stack allocation then form your question properly.