My GUI class in constructor is creating new object of my database class. It looks like that:
GUI::GUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
Baza *plik = new Baza();
connect(ui.insertBtn, &QPushButton::clicked, this, &GUI::run);
}
I've managed to get user input from QDialog:
void GUI::run() {
DialogInput dialog;
dialog.exec();
site_text = dialog.getSite();
}
How should I pass site_text to function in Baza class? I need to use that object (plik) created in GUI constructor but I can't access it from GUI::run() function.
Add plik to the declaration of GUI:
class GUI : public QWidget {
// ...
Baza* plik;
};
then in the constructor
GUI::GUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
plik = new Baza();
connect(ui.insertBtn, &QPushButton::clicked, this, &GUI::run);
}
As your code stands, plik is leaked as soon as GUI constructor completes.
Clean up plik in the destructor:
GUI::~GUI()
{
// ...
delete plik;
}
Alternatively, use std::unique_ptr to store plik in GUI so you don't need to remember to destruct it. Or, if plik benefits from deriving from QObject (e.g. for signals and slots), you can parent it to the GUI and Qt will handle the destruction. In both cases, this advice assumes plik has the same lifetime as GUI.
When you create a pointer inside the constructor the scope of the object is till the end of the constructor.
You need to create a global private variable to GUI class for that variable to be accessed by all the method in the same class. Baza * pLink;
When you create a pointer in the constructor, do not forget to delete the same pointer in the Destruction.
class GUI : public QWidget{
//...
GUI();
~GUI();
private:
Baza * pLink;
}
GUI::GUI(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
pLink = new Baza();
connect(ui.insertBtn, &QPushButton::clicked, this, &GUI::run);
}
GUI::~GUI()
{
delete pLink;
}
void GUI::run() {
DialogInput dialog;
dialog.exec();
site_text = dialog.getSite();
/* use the pointer to call the method to pass site_text */
pLink->SomeMethod(site_text);
}
Naming convention would play a big role when you are declaring local variables for the function and the global variables for the class.
So use pLink or consider using m_pLink where m_ would be added to all the global variable and p for pointer type.
Related
I want to create a window application with Qt framework and C++, in which an object is created to operate hardware, and should be accessible to MainWindow and all its members and methods. I do not have very much experience of doing things like this.
int main(int argc, char *argv[]) {
QApplication qApp(argc, argv);
CoolHardware *CoolHardware500 = new CoolHardware; // Object that connects to hardware.
CoolHardware500.Connect();
// Show main window here.
MainWindow qApp_Win(CoolHardware500); // This is the only elegant way I could think.
qApp_Win.show();
return qApp.exec();
// Deconstructor.
CoolHardware500>~CoolHardware();
}
In the methods of MainWindow, is not accessible. How to solve this?
void MainWindow::CoolHardwareDoSomething() {
CoolHardware500->DoSomehing(); // Here CoolHardware500 is shown as not defined.
}
Questions:
Is it an elegant way to create an hardware-operating object in the main() function? How to make it accessible to the members/methods of the MainWindow?
Is it better to create objects in the constructor of the MainWindow and deconstruct objects in the MainWindow deconstructor? In this way, accessing object is easy.
If this two ways are both not elegant ways of doing things, what is the elegant way of doing that?
Thank you very much.
MainWindow is subclassing QMainWindow, but it's a regular C++ class, so just store either an instance directly, or a pointer, as a member variable on it.
In MainWindow.h (or .hpp):
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
// Either this:
CoolHardware500* m_coolHardwarePtr;
// Or that:
CoolHardware500 m_coolHardware;
};
In the constuctor MainWindow::MainWindow you can pass arguments to the CoolHardware500 ctor as needed, or use a new if you use a pointer.
If using a pointer, you also want to have the destructor MainWindow::~MainWindow do a delete m_coolHardwarePtr;.
You could also use a smart pointer (like std::unique_ptr) to avoid to remember to do that delete yourself.
Mainwindow.cpp, assuming you have a Ctor CoolHardware500::CoolHardware500(int):
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow),
m_coolHardware(1),
m_coolHardwarePtr(new CoolHardware500(1))
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
delete m_coolHardwarePtr;
}
Here's how:
struct MainWindow : QMainWindow {
private:
CoolHardware hardware;
// ...
public:
MainWindow() {
hardware.connect();
// ...
}
// use `hardware`
};
MainWindow::MainWindow(QWidget *parent, GraphicalUI *graphicalUI) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QLabel *label = new QLabel("Label", this);
label->setPixmap(graphicalUI->textures["background"]);
label->setStyleSheet("background-color: black;");
}
void buildWindow(Level *level, GraphicalUI *graphicUI) {
QGridLayout layout = QGridLayout(this);
}
The problem here is found in the buildWindow() function. Obviously I cannot just use
QGridLayout(this). But I want the MainWindow to be the parent of my QGridLayout.
How do I do this? Also, the buildWindow function is going to be called externally.
this is an implicit argument to all member functions. Which means it is available in all member functions not just the constructor. It's just a pointer to the current object.
Since the buildWindow function is not a member function of MainWindow(which I do not recommend) you can pass the address of the MainWindow instance to buildWindow function. By default MainWindow is instantiated in the main.cpp file when you create a new GUI project in Qt Creator.
like:
void buildWindow(Level *level, GraphicalUI *graphicUI, MainWindow* window) {
QGridLayout* layout = new QGridLayout(window);
}
But:
In your code:
void buildWindow(Level *level, GraphicalUI *graphicUI) {
QGridLayout layout = QGridLayout(this);
}
variable layout is a local variable in the scope of this function. When your code reaches the end of function (closing brackets), your QGridLayout layout object is destroyed. In order to avoid this, you should use pointers and the new keyword.
QGridLayout *layout = new QGridLayout(this);
now leyout is just a pointer to a QGridLayout object. This object is destroyed if you call delete layout; manually or the parent object (in this case your mainwindow object) get's destroyed.
But now the problem is you can't access this QGridLayout later on from other functions because the pointer layout will be lost at the end of this function. I recommend using a class member variable like:
private:
QGridLayout *layout;
in your header file and initialize if inside your function like:
void MainWindow::buildWindow(Level *level, GraphicalUI *graphicUI) {
layout = new QGridLayout(this);
}
Make sure you don't use the layout pointer before calling this function.
void MainWindow::buildWindow(Level *level, GraphicalUI *graphicUI) {
QGridLayout* layout = new QGridLayout(this);
}
Thats the solution.
The function is also required to exist in the header of the class.
I need to open a new QMainWindow when i click on a button.I would understand why it works with a pointer and does not work with a reference :
the slot that fires a new window is the following ,it should open two window but only the window created with the new operator shows up:
MyWin win1(this);
win1.show();
MyWin *win2 = new MyWin(this);
win2->show();
the following are MyWin.h and MyWin.ccp
#ifndef MyWin_H
#define MyWin_H
#include <QMainWindow>
namespace Ui {
class FrmManipolo1;
}
Class MyWin : public QMainWindow
Q_OBJECT
public:
explicit MyWin(QMainWindow *parent = 0);
~MyWin();
private:
Ui::MyWin *ui;
};
#endif
MyWin.cpp
include "MyWin.h"
include "ui_MyWin.h"
MyWin::MyWin(QMainWindow *parent) :
QMainWindow(parent),
ui(new Ui::MyWin)
{
ui->setupUi(this);
}
MyWin::~MyWin()
{
delete ui;
}
This doesn't work:
MyWin win1(this);
win1.show();
because it creates the win1 object on the stack, so the win1 object is destroyed at the end of the current scope, before it can actually be drawn.
This works:
MyWin *win2 = new MyWin(this);
win2->show();
because the object is allocated on the heap and it's lifetime doesn't end at the current scope, it ends when you call delete on it's address (the win2 pointer, that only holds the address of the object, not the actual object), or the parent will call delete in your case (because you pass the this pointer as a parent parameter to the constructor).
I've declared a member array to store the pointers for a bunch of Qt Control widgets (QLineEdit),
In the main code, I programmatically create these widgets and assign, however they are only accessible while the function is in scope:
// MyGui.h
class myGui : public QMainWindow, private Ui::uiFormWin
{
Q_OBJECT
public:
MyGui(QMainWindow *parent = 0);
Test();
private:
QTimer *pUiTimer;
QLineEdit* le2T[ 32 ];
public slots:
void GuiUpdate(void);
}
// MyGui.c
MyGui::MyGui(QMainWindow *parent) : QMainWindow(parent)
{
// Create Objects and Assign
for ( int i = 0 ; i < 32; i++ ){
le2T[ i ] = new QLineEdit (this);
}
// This Displays fine:
le2T [ 0 ]->setText ("Hello");
// Setup Timer To Update Line Edit Later
pUiTimer = new QTimer(this);
pUiTimer->setInterval(100);
connect(pUiTimer, SIGNAL(timeout()), this, SLOT(GuiUpdate()) );
}
void MyGui::GuiUpdate( void )
{
// This next line causes Run-Time Crash -- le2T[0] object is null!
le2T [ 0 ]->setText ("World"); // Error
}
Interestingly, even though they are no longer accessible, they still appear on the GUI.
I've tried making these QLineEdit objects as members variables in my class (instead of an array of pointers), but, accessing QLineEdit's member functions fails.. and Qt doesn't even auto-detect these as QLineEdit objects!
.h
QLineEdit le2T[ 32 ];
.cpp
le2T[ 0 ].setText ("World"); // Error
How can I create an array of widgets at run-time, and save as member variables so that they can be accessed from any method in the class?
I am making a C++ application in Qt and want to load a login keyboard (QWidget) whenever I call the constructor of the corresponding ui-class. The constructor is called everytime I switch to my login window. When I leave this window, the destructor is called and everything is destroyed, so i don't leave a single bit in my RAM. i want also just to have one instance the keyboard (singleton) and then hide() and show() whenever needed.
When I call the constructor the first time, i create an instance of my keyboard and add it to my verticalLayout. This works fine. But when i call the constructor for a second time, e.g. when I switch to another window and switch back to my login window, then my static keyboard becomes unreachable. This is what my debugger says...it's unreachable. So i already have an instance of my keyboard and i just want to add it to my verticalLayout again and I don't get it why i can't access it. Maybe it is some property of static variables, i really don't as I am new to C++. So here is my code
#ifndef LOGINKEYBOARD_H
#define LOGINKEYBOARD_H
#include <QWidget>
namespace Ui
{
class LoginKeyboard;
}
class LoginKeyboard : public QWidget
{
Q_OBJECT
public:
explicit LoginKeyboard(QWidget *parent = 0);
~LoginKeyboard();
static LoginKeyboard * instance()
{
if (!loginKeyboard)
{
loginKeyboard = new LoginKeyboard();
}
return loginKeyboard;
}
private:
Ui::LoginKeyboard *ui;
static LoginKeyboard * loginKeyboard;
private slots:
};
#endif // LOGINKEYBOARD_H
#include "headerFiles/loginkeyboard.h"
#include "ui_loginkeyboard.h"
LoginKeyboard *LoginKeyboard::loginKeyboard = 0;
LoginKeyboard::LoginKeyboard(QWidget *parent) : QWidget(parent), ui(new Ui::LoginKeyboard)
{
ui->setupUi(this);
}
LoginKeyboard::~LoginKeyboard()
{
delete ui;
}
#include "headerFiles/support.h"
#include "ui_support.h"
#include "headerFiles/mainwindow.h"
#include "headerFiles/loginkeyboard.h"
Support::Support(QWidget *parent) : QWidget(parent), ui(new Ui::Support)
{
ui->setupUi(this);
MainWindow::setPreviousPage(MainWindow::widgetStack->first());
ui->verticalLayout->addWidget(LoginKeyboard::instance()); //error when it gets called the 2nd time
}
Support::~Support()
{
delete ui;
}
When you add your static instance of LoggingKeyboard it will be deleted by it when the layout is destroyed.
See here
Note: The ownership of item is transferred to the layout, and it's the layout's responsibility to delete it.
So it's not a good idea to have a singleton subclass of QWidget. If you really need the singleton property - you could extract the necessary functionality to a different class (which will not be subclassing QWidget) and use it from LoginKeyboard. However, if you don't really need it - then just don't do it - singletons should be avoided as much as possible because they are just glorified versions of global variables and may cause a wide variety of hard-to-track bugs.