I have a progress bar object (ui->QprogressBar) available in my mainwindow.cpp. But, I want to use this object in another class (readerfile.cpp).
Headers
mainwindow.h
demo.h
Sources
mainwindow.cpp
demo.cpp
I use this method to call object most of the time:- Using a function call, for example -mainwindow.cpp I will call this function
mainwindow->isFunction(ui->QprogressBar);
isFunction is available inside my demo.cpp file
void demo :: isfunction (QProgressBar *progress)
But, Now I want to use QprogressBar object directly inside my demo.cpp file.
I tried all possible combinations, connections and just can't get it work.
So could someone please explain me, how to access UI elements object from class demo.
Any idea for the solution will be a great help.
Thanks.
To get a pointer to an object from another class you need to implement a public function that returns this pointer. I will give you a little example:
Your class MainWindow in the header file will include a function progressbar().
mainwindow.h:
//...
class MainWindow : public QMainWindow
{
Q_ObBJECT
public:
QProgressBar *progressbar(); //returns a pointer to the QProgressBar
//..
private:
//..
};
This function is implemented in mainwindow.cpp like this:
QProgressBar *MainWindow::progressbar()
{
return ui->progbar; //I just called it like this to avoid confusion, it's the just the name you defined using QtDesigner
}
Then, in demo.hpp if you have an instance of MainWindow in your class:
//..
class Demo : public QObject
{
Q_OBJECT
public:
//..
private:
MainWindow *window;
//..
}
you can just access QProgressBar using by calling the function in demo.cpp:
QProgressBar *bar;
bar = window->progressbar();
I have to say though that it's unusual to have an instance of MainWindow in another class. Usually your QMainWindow or QApplication is the main entry point to the program and you have instances of the other classes in them, not the other way around.
Related
I am a bit new to Qt C++ and I think there is a small thing I'm missing but can't figure what is it.
I am trying to make a simple Qt C++ application just to get familiar with it, but I face some problem, First, I have the votor class, which is the main application class, and another class which is called recorder, which will be used inside the main votor class. For simplicity, I omitted un-related parts,
Here are the files:
votor.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_votor.h"
#ifndef TSTRECORD_H
#define TSTRECORD_H
#endif
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QWidget>
#include "recorder.h"
class VOTor : public QMainWindow
{
Q_OBJECT
public:
VOTor(QWidget *parent = Q_NULLPTR);
recorder xs;
private:
Ui::VOTorClass ui;
};
votor.cpp
#include "votor.h"
VOTor::VOTor(QWidget *parent) : QMainWindow(parent), xs(parent)
{
ui.setupUi(this);
//xs = recorder();
}
recorder.h
#pragma once
#include <QDebug>
#include <QObject>
#include <QtCore/qbuffer.h>
#include <QtCore/qiodevice.h>
#include<QtMultimedia/qaudioformat.h>
#include<QtMultimedia/qaudiodeviceinfo.h>
#include<QtMultimedia/qaudioinput.h>
class recorder : public QObject
{
Q_OBJECT
public:
// recorder();
recorder(QObject *parent);
~recorder();
//Some functions related to recording omitted for more focus
private:
//omitted members for simplicity, just some integers, chars and qt objects not related to problem
recorder.cpp
#include "recorder.h"
recorder::recorder(QObject *parent) : QObject(parent)
{
//just initializing the omitted members normally
}
//recorder::recorder() {}
recorder::~recorder()
{
}
as you see, recorder object is a member inside votor class. Now, I need to call recorder constructor to initialize its parent. Now, I knew I can't just make (inside votor.h)
recorder xs(parent);
so,
1- is there a way I can call recorder constructor other than initialization list ?
I want another way as I was more convenient to use recorder xs(..) than initialization list, I feel (just feel) that using initialization list is heavy (not performance-wise but on readability ). I know also I can use dynamic allocation, but I don't want to use it without a good reason for.
2- I have decided to use initialization list to call recorder constructor and pass (Qobject* parent) to recorder. The code is built successfully, but when running, it gives access violation error which I can't figure why...
it gives:
"Access violation reading location 0x7C32F08D."
I think I am missing small thing.. I hope to know what is wrong.
Edit:
as #p-a-o-l-o suggested, the access violation was from the omitted code, So, I am posting it here as I don't know what is the problem in my code:
full version of recoder.h
class recorder : public QObject
{
Q_OBJECT
public:
recorder();
//recorder(QObject *parent);
~recorder();
void record();
void stop();
public slots:
void stateChanged(QAudio::State);
private:
unsigned char state;
QBuffer* voiceBuffer;
QAudioFormat* format;
QAudioDeviceInfo* info;
QAudioInput* audioIn;
unsigned char writeWav(QByteArray*);
};
and the part causes access violation according to debug mode, which is constructor of recorder class
recorder::recorder() : QObject(Q_NULLPTR)
{
state = 0;
voiceBuffer->open(QIODevice::WriteOnly);
format->setSampleRate(8000);
format->setChannelCount(1);
format->setSampleRate(16);
format->setByteOrder(QAudioFormat::LittleEndian);
format->setCodec("audio/pcm");
format->setSampleType(QAudioFormat::SignedInt);
*info = QAudioDeviceInfo::defaultInputDevice();
audioIn = &QAudioInput(*info, *format);
//audioIn->stateChanged.connect(stateChanged);
//connect(audioIn, &QAudioInput::stateChanged, stateChanged);
connect(audioIn, SIGNAL(stateChanged (QAudio::State) ), this, SLOT(stateChanged(QAudio::State)));
}
About question #1: as rightfully suggested in comments, a proper constructor for a QObject-derived class would have a nullptr default argument:
recorder(QObject *parent = Q_NULLPTR);
If you really need that parent object to initialize the other members in construction, you have no alternatives and must call that constructor, somehow.
Otherwise, have a no-arguments constructor and initialize the other members there:
recorder::recorder() : QObject(Q_NULLPTR)
{
//just initializing the omitted members normally
}
Such a constructor will be invoked automatically, no need of initialization list here.
If you still need a parent for the recorder object, give it one in the VOTor constructor:
VOTor::VOTor(QWidget *parent) : QMainWindow(parent)
{
ui.setupUi(this);
xs.setParent(parent);
}
About question #2: as far as I can see from the code you posted, the access violation have nothing to do with Qt parenting and must be related to the (omitted) code inside the recorder constructor.
Just to clear it out: parenting a member object is always safe, since it will go out of scope before ~QObject() gets called, so it will be removed from the children list before ~QObject() could possibly call delete on it.
Taking the OP code as an example, the sequence of destructors is the following:
~VOTor()
~recorder() ---> xs is removed from the children list
.
.
.
~QObject() ---> will call delete on all children, but ws is not in the list anymore
Qt documentation is quite clear about the order of construction/destruction of parents and children: in short, if the child is created on the stack everything will be fine until the child is created after the parent.
But, again, if the child happens to be a member of the parent class, it will be fine as well for the reasons mentioned above (even if its construction actually happens before its parent's).
To be specific to my problem I've been trying to connect a a slot from one class to a regular function of another class. I'm trying to do this so I can close the ui of one the main window from a dialog window. I tried everything I could possibly think of but it seems like every time I think of something to try the Qt compiler shuts me down by throwing some error or not working for no apparent reason such as when I did this
function(Ui::MainWindow *ui)
{
copy = ui; // copy is a pointer declared as Ui::MainWindow *copy in the dialog class
}
I tried this so I could close the main window from the copy pointer in the dialog class and although it compiled for that, it wouldn't compile when I tried to use it in another function of that class even though it was a class variable. After that I then realized that I should be able to connect the two functions from the main function. I wrote this
QObject::connect(&i, SIGNAL(on_passInput_returnPressed()), &w, SLOT(initalizer()));
The above compiles but when debugging I discovered it never gets executed and not sure why despite the fact that the SIGNAL on_passInput_returnPressed() is actually declared as slot in the class header. If that is the reason why it doesn't get executed how do I connect the slot from the dialog class to a regular function from the MainWindow class? There must be a way because I spent a day practically thinking about this non-stop and can't think of any other way given the nature of object scopes (in OOP) on top of the fact that the pointer thing I thought of didn't work.
Also I just now recreated the error from the pointer thing described above here it is.
error: invalid use of incomplete type 'class Ui::MainWindow'
copy->close();
^
Again this error is referring to trying to access the close function via the copy pointer from another function in the same class as the pointer assignment that worked in the other function. The copy pointer is declared as follows in the class header. Also in case you're wondering, yes, the pointer assignment written above does get executed. I checked via debugging.
private:
Ui::InitalPrompt *ui;
Ui::MainWindow *copy;
If you need more info just let me know what you need and I'll edit this post with it. I've obsessively tried so much I can think so much so that I've given up without further help due to how unforgiving Qt has been with me.
Also if there's a way of doing what I'm trying to do with the new Qt5 syntax of the connect function can you please give me the exact thing to type because despite looking into that new syntax myself I can't get it to compile for the life of me. (and yes I'm using Qt5) That's why the code above is written as old-fashion syntax.
Added the following as suggested to do so in a reply which is the class of the copy pointer.
#include "initalprompt.h"
#include "ui_initalprompt.h"
#include "mainwindow.h"
#include <QLineEdit>
#include <QCloseEvent>
#include <QMessageBox>
InitalPrompt::InitalPrompt(QWidget *parent) :
QDialog(parent),
ui(new Ui::InitalPrompt)
{
ui->setupUi(this);
}
InitalPrompt::~InitalPrompt()
{
delete ui;
}
void InitalPrompt::on_passInput_returnPressed()
{
pass = ui->passInput->text();
}
void InitalPrompt::reject()
{
QMessageBox::StandardButton resBtn = QMessageBox::Yes;
bool changes = false;
if (changes) {
resBtn = QMessageBox::question( this, "APP_NAME",
tr("Are you sure?\n"),
QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
QMessageBox::Yes);
}
if (resBtn == QMessageBox::Yes) {
QDialog::reject();
}
// the only issue is with the statment below don't know why
copy->close();
}
void InitalPrompt::catcher(Ui::MainWindow *ui)
{
copy = ui;
}
"Invalid use of incomplete type" means the compiler does not (yet) have a definition for the class when it reaches that line. In the header file that contains your copy pointer, include a forward declaration above the class declaration (the file would look something liek this):
#ifndef BLAH_BLAH_H
#define BLAH_BLAH_H
/*All of your normal #includes here*/
namespace Ui {
class InitialPrompt;
class MainWindow; //Note the forward declaration here
}
#include "mainwindow.h"
class BlahBlah
{
/*Class stuff here*/
private:
Ui::InitalPrompt *ui;
Ui::MainWindow *copy;
};
#endif //BLAH_BLAH_H
If you post the entirety of your class file that has the *copy, we can look further into it.
No, it is not possible. You can either:
call w->initalizer() directly from on_passInput_returnPressed() or
define a signal signal_on_passInput_returnPressed() in your ui class and emit that signal from on_passInput_returnPressed(). Then
QObject::connect(&i, SIGNAL(signal_on_passInput_returnPressed()), &w, SLOT(initalizer()));
should work.
For example:
class Whatever :
public QObject {
Q_OBJECT
void on_passInput_returnPressed();
signals:
void signal_on_passInput_returnPressed();
};
void Whatever::on_passInput_returnPressed() {
emit signal_on_passInput_returnPressed();
}
I'm trying to call my function as a function slot in Qt,But i don't know how to go about it.
it seems the following approach is wrong :
Update:
According to an answer i updated my source code,but still something is apparently wrong with it.Trying to compile this snippet of code causes these errors:
C2515:' no appropriate default constructor is available.'
And
C2665: QObject::connect':none of the 3 overloads could convert all the
arguments.'
respectively in Visual studio 2010.
#include <QtGui/QApplication>
#include <QPushButton>
#include <QObject>
#include <QMessageBox>
class myclass;
int main(int argc,char *argv[])
{
QApplication a(argc,argv);
QPushButton btnshowmessage("show");
myclass *my=new myclass();
QObject::connect(&btnshowmessage,SIGNAL(clicked()),my,SLOT(warningmessage()));
btnshowmessage.show();
return a.exec();
}
//////////////////////////////////////////////////////////////////////////
class myclass: public QObject
{
Q_OBJECT
public:myclass(){}
public slots:
void warningmessage()
{
QMessageBox::warning(0,"Warning","Test Message!",QMessageBox::Ok);
}
};
You use signals and slots to connect one Object's signal to another Object's slot. Every signal or slot should be inside a class which must be also derived from QObject class and contain the Q_OBJECT macro.
So to make your code work, put the slot into some class of yours:
class MySlotClass:public QObject
{
Q_OBJECT
public slots:
void MyFunction()
{
QMessageBox::warning(0,"WarningTest","This is a waring text message",QMessageBox::Ok);
}
}
and connect like this:
MySlotClass m = new MySlotClass();
Qobject::connect(&btnShowaMessageBox,SIGNAL(clicked()), &m ,SLOT(MyFunction()));
Currently Qt does not allow connection of signals to functions that are not declared as slots on some QObject derivative. I believe Qt5 may offer this possibility, but connect will have different syntax to allow this.
basically your slot function must be in a QObject derived class and declared in a
public slots:
section.
Read the documentation on signals/slots.
I'm a beginner to both C++ and Qt, so perhaps this is trivial. It certainly feels like it should be simple, but I've been searching for an answer for a few hours now and can't find the solution. I'm making a simple board game where the MainWindow's ui (made in QtDesigner) contains a canvas for the game board (a QGraphicsView). Now, the main.cpp is as simple as can be:
MainWindow Game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game.show();
return a.exec();
}
Since I need to access and edit the MainWindow Widgets from another totally unrelated class, I thought the easiest way would be to just make MainWindow a global variable. It seems that this approach was very wrong, though. Upon trying to run the project in QtDesigner I get a Microsoft Visual C++ runtime library error: the application has requested runtime to terminate it in an unusual way.
So what is the correct way to do what I need?
Aside from the MainWindow I have a dialog for a new game (QDialog, generated from QtDesigner) that is displayed after clicking a menu item in MainWindow. When the user inputs all parameters for the game and clicks OK in the dialog, I instantiate a custom non-Qt class called GameState. This class is meant to operate the game itself, draw the board, prompt the user, etc. However, as this class is created in the QDialog, it does not know of the existence of a MainWindow and so I cannot do anything with the MainWindow from this class. How can I modify the MainWindow from an unrelated class, then?
Also, jsut how does the setEnabled() function work? It never seems to do anything. Any widget I set as disabled in the QtDesigner and then try to enable through this function still stays disabled in the GUI...
First off it's a bad idea to create MainGame before you create your QApplication object.
If you want to have your MainGame object globally available like this it should be a pointer:
MainWindow *Game;
int main (int argc, char **argv)
{
QApplication a (argc, argv);
Game = new MainWindow();
Game->show();
int result = a.exec();
delete Game;
Game = NULL;
return result;
}
This approach is however not the most elegant. There are two much better choices.
The QApplication object actually stores all top level windows like your MainGame which means you can allways aquire it through QApplication::topLevelWidgets() which is a static function and returns a list with all top level widgets. Since you only have one, the first one is your MainGame. The drawback is you'll have to cast it, but using Qts qobject_cast<MainGame*>(...) is fairly safe. You'll have to check the result though to make sure it isn't a NULL pointer.
Use the singelton design pattern. You should store the global Game pointer in the source (cpp) file of the Game class itself (subclass QMainWindow) and your Game class should implement a static public method which returns this global pointer. So if any other class needs the Game pointer, it simply calls:
MyGame *theGame = MyGame::getInstance();
for example.
Regarding your setEnabled() problem. Please post the relevant code. If it's too much feel free to send me the *.ui file and the piece of code via mail.
Best regardsD
I am doing it this way:
QMainWindow* getMainWindow()
{
foreach (QWidget *w, qApp->topLevelWidgets())
if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w))
return mainWin;
return nullptr;
}
If your application has only one window you can simply use:
MainWindow * win = (MainWindow *) qApp::activeWindow();
The easiest way to do this is to first set up a signal in the header file of your other class to say perform a function to manipulate an object in the main class like this
signals:
void disableLoadButtton();
Then create a slot under private slots in the header file of the main window like this
private slots:
void disableLoadButtton();
Then create the function as a members function in the main window to manipulate the object
void MainWindow::disableLoadButton()
{
ui->loadButton->setenabled(false);
}
Then add the following line in another member function of the main window which say sets up the page. My other class is called searchWidget
void MainWindow::setUpPage()
{
connect(searchWidget, SIGNAL(disableLoadButton()), this, SLOT(disableLoadButton()));
}
Then all you have to do to disable the loadButton (which is a object in MainWindow) is to add the following line in any members function of my other class searchWidget
void searchWidget::performSomething()
{
emit disableLoadButton();
}
This will then manipulate the object loadButton in the mainwindow from within a member function of the other class searchWidget.
In the past I used approach described in this answer (found in Qtractor project).
Now I use QObject 'name' property and discover it anywhere as described here.
main.c
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include <QString>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "c.h"
MainWindow * MainWindow::pMainWindow = nullptr;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
pMainWindow = this;
setCentralWidget(&m_pb);
connect(&m_pb, SIGNAL(clicked()), this, SLOT(on_pb_clicked()));
}
MainWindow::~MainWindow() {delete ui;}
// kind of singleton reference.
MainWindow *MainWindow::getMainWinPtr()
{
return pMainWindow;
}
void MainWindow::pbSetText()
{
m_pb.setText(QString{"Call from c."});
}
void MainWindow::on_pb_clicked()
{
c C; // call of MainWindow from class c ctor
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QPushButton>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow * getMainWinPtr();
void pbSetText();
public slots:
void on_pb_clicked();
private:
static MainWindow * pMainWindow;
Ui::MainWindow *ui;
QPushButton m_pb{QString{"Press me."}, this};
};
#endif // MAINWINDOW_H
c.cpp
#include "c.h"
#include "mainwindow.h"
c::c()
{
MainWindow * mw = MainWindow::getMainWinPtr();
mw->pbSetText();
}
c.h
#ifndef C_H
#define C_H
class c
{
public:
explicit c();
};
#endif // C_H
If you have to access your MainWindow from another window, you are probably doing it wrong. Using another class to pass information with signals/slots is probably a much better approach
I want to add a signal to a class that inherits from QGraphicsScene.
signals:
void update(std::vector< std::vector<int> > board);
When I do this, Qt Creator warns me that I forgot the Q_OBJECT macro. But somewhere I read that since QGraphicsScene doesn't inherit from QObject, I shouldn't put it in my class definition. But signals need this macro.
How do I add a signal to a class that doesn't inherit from QObject?
boardgui.h
#ifndef BOARDGUI_H
#define BOARDGUI_H
#include <QGraphicsView>
#include <QGraphicsScene>
class BoardGUI : public QGraphicsScene
{
Q_OBJECT
public:
BoardGUI(QGraphicsView*& view, int dimension);
~BoardGUI();
void buildBoard();
signals:
void update(std::vector< std::vector<int> > board);
private:
int dimension;
QGraphicsView* view;
};
#endif // BOARDGUI_H
Reposting as answer, as requested:
Is update() your signal? did you try to implement the signal yourself? If yes, don't do that, signals are defined by moc.
QGraphicsScene does inherit from QObject. You can consult the documentation.
http://doc.qt.io/qt-5/qgraphicsscene.html
Vtables have something to do with virtual functions. When you have an error like Undefined reference to vtable then it cannot find an implementation for a virtual function (I think). Have you implemented all of your functions? Maybe you used the virtual keyword when you weren't supposed to? Or vice versa?
Also, you say that you want to add a signal, but your code chunk shows a slot? Could you show a little more of your class?
If you have not implemented any class with Q_Object before to the project and you add the Q_OBJECT line yourself, you get the vtable error. If you add another c++ class to the project that inherits from QObject, then you get rid of this problem. You can remove this class you created if you dont need it. I am not sure why this happens, but this is easy way to get rid of the problem. Maybe the creator adds some line to the . pro file when you add a class that inherits from qobject.
Have you implemented your destructor? If not, try changing ~BoardGUI(); to ~BoardGUI(){};
Have you added boardgui.h to the MOC preprocessor's file list? Any class that uses QObject and Signals/Slots needs to be passed through the Meta-Object Compiler so it can generate the actual code behind the signals.
I am unsure if Qt Creator handles this automatically.
You simply have to inherit from QObject yourself.
boardgui.h
#ifndef BOARDGUI_H
#define BOARDGUI_H
#include <QGraphicsView>
#include <QGraphicsScene>
class BoardGUI : public QObject, public QGraphicsScene
{
Q_OBJECT
public:
BoardGUI(QGraphicsView*& view, int dimension);
~BoardGUI();
void buildBoard();
signals:
void update(std::vector< std::vector<int> > board);
private:
int dimension;
QGraphicsView* view;
};
#endif // BOARDGUI_H
If you are using Qt Creator, you shouldn't have to worry about moc, everything should be handled by Qt Creator.