Qt/C++ : Centralise parameters in one class - c++

I'm trying to centralise some parameters in one class. I looked on several forums and tutorials without finding any real answer. Maybe I don't use Qt correctly.
I have a Qt class Application which handles theses parameters.
Application.h
class Application : public QApplication
{
public:
Application(int, char**);
~Application();
bool setFilesPath(QString path);
QString getFilesPath();
private:
QString filesPath;
}
main.cpp
int main(int argc, char *argv[])
{
Application app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
I'd like to access the setFilesPath() and getFilesPath() methods from everywhere (for exemple in another class. Therefore a made Application inherit from QApplication, hoping that qApp.setFilesPath() would work. But it doesnt.
It seems to be a quite usual thing to access some parameters from everywhere. So how could one do this ?
I've found this three ways :
Global variables
Static methods
Including an instance of Application in every class needing the method (but it seems wrong)
Which is more commonly used (and why) ? Why does my way doesn't work ?
Thank you.
EDIT:
In this topic, they use singelton design pattern.
So calling
Application *app = Application::getInstance();
everywhere I need it. Is it better ?

You can access your class using qApp pointer. According to the Qt documentation:
A global pointer referring to the unique application object. It is
equivalent to the pointer returned by the QCoreApplication::instance()
function except that, in GUI applications, it is a pointer to a
QApplication instance.
So, your code somewhere could look like:
Application *myApp = qobject_cast<Application *>(qApp);
QString path = myApp->getFilesPath();

You can have your classes in the main independently and connect a signal from each class that needs to access the value in your class to the slot that returns the value :
int main(int argc, char *argv[])
{
Application app(argc, argv);
MainWindow mainWindow;
MyClass myclass1;
QObject::connect(&mainWindow,SIGNAL(askFilesPath()),myclass1,SLOT(getFilesPath()));
mainWindow.show();
return app.exec();
}
This way when you call the signal askFilesPath() in your MainWindow, the slot in your custom class gets called and the value is returned:
QString filePath = askFilesPath();
You should note that if the two classes are in different threads then the connection type should be Qt::BlockingQueuedConnection.

Related

Qt 5.3 Signals and Slots, Simple Function and Lambda Expression

I tried to Write a program using Qt 5.3 and I try to using signals and slots as practice. I wrote the following code (part of the code) :
void exitToWin()
{
exit(0);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QMessageBox EndBox;
QObject::connect((EndBox.button(QMessageBox::Ok)),SIGNAL(clicked()),exitToWin);
w.show();
EndBox.show();
return a.exec();
}
I even change the declaration of the function to static and I checked the expression with parentheses and without them while I am writing the connect command. but although what Qt documented and what its IDE guided to. also I read here and I tested it.
Moreover I tried with lambda expression as below:
QObject::connect((EndBox.button(QMessageBox::Ok)),SIGNAL(clicked()),[=](){
exit(0);
});
but still I receive errors indicate "No matching function call".
And after all I have to say that I am using Microsoft Windows 7.
This works on Qt 5.3:
#include <QtWidgets>
void exitToWin()
{
exit(0);
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow w;
QMessageBox endBox;
endBox.addButton(QMessageBox::Ok); // (2)
endBox.connect(endBox.button(QMessageBox::Ok),
&QAbstractButton::clicked, exitToWin); // (1)
/* This works, too:
endBox.connect(endBox.button(QMessageBox::Ok),
&QAbstractButton::clicked,
[] () { exit(0); });
*/
w.show();
endBox.show();
return a.exec();
}
Here's why:
(1) You can use endBox's QObject to do the connection between the QAbstractButton's clicked signal and your exitToWin simple function. You also can't connect a SIGNAL to a simple function or a lambda, so we use the member function variety, instead.
(2) endBox doesn't actually get an OK button by default. When you mention it on line (1) in your code, it creates it, but not in time (apparently) to pass the pointer back to connect, so we create it first here.
Your code won't work for two reasons:
Firstly, QMessageBox does not have such a signal. See the documentation for the signals it does have.
Secondly, when making connections from a signal to a slot (or lambda function), you must define the function signatures, not specific values.
If a signal can pass a variety of values and you only want your slot to perform a certain function on a selection of those values (in this case, only if the value QMessageBox::Ok is passed) it is up to the slot to interrogate the values, not the connect statement.
Since the connect() method is from QObject it has to be called from a QObject child containing the Q_OBJECT macro in its declaration. Running qmake prepare the class to send signals and receive slots.

Must construct a QApplication before a QWidget

Everywhere only just "before QPaintDevice" questions and nowhere is my error. So, here we go.
I need an extern QWidget to be able to get access to it from outside (because I don't know any other ways to do it). Basically, I need this: Create 2 QWidgets from 1 window, go to first window and from there hide main window and show second window created by main window (although main window is not main(), it is QWidget too).
I added
extern QWidget *widget = new QWidget
everywhere and everyhow in possible ways, and I still got this message. I suppose, it means that I need to create my QApplication (in main.cpp) and only then declare any QWidgets. But then HOW can I access those QWidgets from another QWidgets?
Code is here:
https://github.com/ewancoder/game/tree/QWidget_before_QApp_problem
P.S. The final goal is to be able show and hide both gamewindow.cpp and world.cpp from battle.cpp (just regular class)
And btw, adding Q_OBJECT and #include both don't work.
Anyway, if I cannot use functions from one window to another, than what's the point? I can have one window in another, and then another in that one, and then one in that another... but I can't do anything from the last to the previous. After years on Delphi that seems strange to me.
Don't use extern or otherwise static variables which lead to creation of the widget before the QApplication is created in main. The QApplication must exist before the constructor of the QWidget is executed.
Instead of sharing the variable via extern, either make the other windows members of the main window, and then make the windows known to each other by passing around pointers, or keep them private in MainWindow and request the actions from the subwindows e.g. via signal/slots. As a generic rule, don't use global variables but class members.
In the following FirstWindow (which is supposed hide main window and secondWindow) gets the main window and the second window passed via pointers and then just calls show/hide on them directly.
int main(int argc, char **argv) {
QApplication app(argc, argv);
MainWindow mainWindow;
mainWindow.show();
return app.exec();
}
In main window, have two members for the two other windows, say FirstWindow and SecondWindow:
class MainWindow : public QMainWindow {
...
private:
FirstWindow *m_firstWindow;
SecondWindow *m_secondWindow;
};
MainWindow::MainWindow(QWidget *parent) {
m_firstWindow = new FirstWindow; //not pass this as parent as you want to hide the main window while the others are visible)
m_secondWindow = new SecondWindow;
m_firstWindow->setMainWindow(this);
m_firstWindow->setSecond(m_secondWindow);
m_firstWindow->show(); //Show first window immediately, leave second window hidden
}
MainWindow::~MainWindow() {
//Manual deletion is necessary as no parent is passed. Alternatively, use QScopedPointer
delete m_firstWindow;
delete m_secondWindow;
}
FirstWindow, inline for brevity:
class FirstWindow : public QWidget {
Q_OBJECT
public:
explicit FirstWindow(QWidget *parent = 0) : QWidget(parent) {}
void setMainWindow(MainWindow *mainWindow) { m_mainWindow = mainWindow); }
void setSecondWindow(SecondWindow *secondWindow) { m_secondWindow = secondWindow; }
private Q_SLOTS:
void somethingHappened() { //e.g. some button was clicked
m_mainWindow->hide();
m_secondWindow->show();
}
private:
MainWindow* m_mainWindow;
SecondWindow* m_secondWindow;
};
Maybe not helping the former author, but others facing the problem.
I simply got this error by mistaking a debug-library with a release one. So check your linker settings, if you are sure the implementation is done right (first instancing application and then using widgets).

Is it possible for QTestLib to display the GUI it is testing as it runs?

The use case is, I have a Qt app, and I would like to automate user-style testing of it; that is, I'd like to use keyClicks(), mouseClick(), and so on, but I would like for the Qt application window to actually be displayed while this is happening.
The issue I'm having right now is that using QTestLib involves using the QTEST_MAIN macro instead of defining main myself, so I never get an opportunity to show() the widgets being tested. So, another way to word this question is, is there a way to use QTestLib on an application that is using its main function?
I know Squish and probably Testability Driver are capable of this, but if it is possible to get this functionality without using extra tools, then that would be ideal.
Figured out how to do this. Makes Squish totally unnecessary, but it requires source code access.
In your test class, store a pointer to the QApplication and any widgets you want to test. For ease of use, store a pointer to your application's QMainWindow. Then, either instantiate your test class with pointers to the widgets you plan on testing, or use window->findChild() to grab any element you need. Keep in mind that you will need to call app->processEvents() after everything. Call it after showing the widget so that all of the child widgets appear. Call it after interacting with a widget so that the interaction is actually processed on the GUI. If you need things to be slow enough to watch, use QTest::qSleep().
#KelvinS. This is my snippet of code following #VGambit method, which tries to test adding a log to itemview.
#include <QApplication>
#include <QWidget>
#include <QtTest/QtTest>
#include "guimain.h"`
#include "xlogview.h"`
class TestLogView:public QObject
{
Q_OBJECT
public:
void set_mainwindow(QWidget * qw);
public slots:
void startTest();
private:
QWidget * m_qw ;
private slots:
void addItem();
};
void TestLogView::startTest()
{
QTest::qExec(this);
}
void TestLogView::set_mainwindow(QWidget * qw)
{
m_qw = qw;
}
void TestLogView::addItem()
{
XLogView * test_logview= m_qw->findChild<XLogView*>();
bool ret = test_logview->addLog("new log");
QVERIFY (ret == true);
}
#include "main.moc"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
GUIMain window;
window.show();
app.processEvents();
TestLogView test;
test.set_mainwindow(&window);
QTimer::singleShot(1000, &test, SLOT(startTest()));
return app.exec();
}

Qt: maximized frame

I have a beginner question. I'm trying to create a maximized QFrame with the following code but I'm receiving an error which says:
error C3867: 'QWidget::showMaximized': function call missing argument list; use '&QWidget::showMaximized' to create a pointer to member
Code:
class FrameWindow{
private:
QDesktopWidget *desktop;
QFrame frame_window;
QRect frame_rect;
public:
FrameWindow(QApplication& app){
desktop = app.desktop();
desktop->showMaximized;
frame_window.setWindowTitle("QT Trainning");
frame_window.show();
}
I'm totally beginner in C++, so what I'm missing please?
functions/methods generally need argument list, even an empty one -> object->method() Try using brackets.
You eventually want:
w->setWindowState(w->windowState() | Qt::WindowFullScreen);
Edit:
or as your solution:
w->setWindowState(w->windowState() | Qt::WindowMaximized);
In addition to what others have already noticed, it's completely counterproductive to pass either the current application or to hold a pointer to the desktop. The application pointer is always available via the global qApp macro. To get the desktop, simply use
qApp->desktop()
There is absolutely no reason to "cache" this value. Get it whenever you need it, that's all.
It'd be also more idiomatic to derive from the widget type, instead of holding it as a member. The code could be simplified as below. It is a complete, self-contained example.
#include <QFrame>
#include <QApplication>
class FrameWindow : public QFrame {
public:
FrameWindow(QWidget * parent = 0, Qt::WindowFlags * flags = 0) :
QFrame(parent, flags)
{
setWindowTitle("Qt Training");
setWindowState(windowState() | Qt::WindowMaximized);
}
};
int main(int argc, char ** argv) {
QApplication app(argc, argv);
FrameWindow fw; // constructor is called here
fw.show();
return app.exec();
// FrameWindow::~FrameWindow() destructor is called first before exiting
// QApplication::~QApplication() destructor is called next
}

Qt: How to put collection of GUI-Elements into independent SubClass (with seperate *.ui file)

I'm trying to collect an often used subset of GUI-Elements together into one Subclass, which can be "included" into the real GUIs later without rewriting the given functionality (don't ask why, I wanna learn it for later use). The Subclass should use it's own *.ui-File and should be put into an QWidget resding in the real GUI. After this, it would be nice to access some methods of the Subclass from the real GUI -- like the state of a button or so.
But how do I do this right?
In the moment, my Subclass works and is instantiated in main, but cannot be accessed from the real GUI because its only declared in main.
My Subclass Header-File:
class logger : public QWidget, private Ui::loggerWidget {
Q_OBJECT
public:
logger(QWidget *parent = 0);
virtual ~logger();
// some more stuff...
}
The corresponding constructor. I had to run setupUI with "parent" instead of "this", but I'm not sure that this is correct -- anyways, it works... otherwise, the subelements from the subclass are not shown in the main-window of the real GUI.
logger::logger(QWidget *parent) : QWidget(parent){
setupUi(parent);
//ctor
}
Inside the main.cpp the main-window is constructed, which uses it's own *.ui-File (containing one widget "widget_loggerArea") aswell. Doing so, I can not access methods of "logger" from within "loggerTest":
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
loggerTest window;
logger myLog(window.widget_loggerArea);
window.show();
return app.exec();
}
I can't put the constructor of "logger" into the constructor of the main-window "loggerTest", since it will be destroyed immidiately and never enters the event-loop.
I'm sure I'm missing some concept of object-oriented programming, or the way qt handles its stuff... I would be gratefull if someone could put my nose to this ;-)
I was so stupid... using a pointer with new and delete does the job... this is so silly, I can't believe it! I'm more used to VHDL recently, this weakens my C++-karma...
So, the answer is in the real GUI class. The Constructor:
testLogger::testLogger(QMainWindow *parent) : QMainWindow(parent){
setupUi(this);
myLog = new logger(widget_loggerArea);
}
In main.cpp:
QApplication app(argc, argv);
testLogger window;
window.show();
And in constructor of logger, setupUi works with "this":
dfkiLogger::dfkiLogger(QWidget *parent) : QWidget(parent){
setupUi(this);
}
Yes, thats it... Just for completebility, maybe someone needs a similar "push in the right direction"...
EDIT: In the header of the SubClass the scope of the ui-Elements has to be updated to "public", too:
class logger : public QWidget, public Ui::loggerWidget {
Q_OBJECT
public:
logger(QWidget *parent = 0);
virtual ~logger();
}