Qt GUI Easiest way to access MainWindow from another class - c++

I am doing a blackjack program and I am keeping track of the cards in the players hand in another class ("hand.h") than the main window class.
In the hand class, for every card that I collect, I am also creating a QLabel that grabs the proper card image for the card and also sets the coordinates for where the card should appear on the main window.
The problem is that I am not able to create the QLabel based on the MainWindows object that is originally created at the main function. Is there any easy way that I am able to get that information fairly easily? Thanks for your help!
I have tried using QGuiApplication::topLevelWindows(), but haven't came to luck with using that. Here is my function that I am using.
#include <QRect>
#include <QApplication>
#include <iostream>
#include <QLabel>
#include "mainwindow.h"
#include <QMainWindow>
#include <QWindowList>
#include <QWidgetList>
#include "ui_mainwindow.h"
void Test() {
QList<QWindow*> Main_Window = QGuiApplication::topLevelWindows();
for (int i = 0; i < Main_Window.size(); ++i) {
if(Main_Window.objectName() == "mainWindow") // name is OK
break;
}
QMainWindow* mainWindow = static_cast<QMainWindow*>(Main_Window);
QLabel* temp;
temp = new QLabel(Main_Window);
temp->setPixmap(QString("Ten of Clubs.png"));
temp->setGeometry(290, 300, 350, 390);
temp->show();
}
Here is the main.cpp file that creates the mainwindow
int main(int argc, char *argv[])
{
srand(time(NULL));
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
I found the iterating code online and have been having issues from it.
I am having issues while trying to iterate through the list, but I have no idea how to identify the list and the error says that there is no objectName() function. Also, in the static cast line, there is an error that says that I cannot convert an QList to type QMainWindow. Any help would be greatly appreciated.

No way in general, because some applications may have several (toplevel) QMainWindow-s (and their list could change with time). So for that case you'll better pass the pointer to it (the particular QMainWindow you want to deal with) explicitly....
A possible way might be to have your specific subclass of QApplication (which is a singleton class, see QCoreApplication::instance to get its sole instance) and in your application subclass put, as fields, the explicit windows you want to deal with (maybe you even want to add some new signal or slot to your application class).
However, you could use QGuiApplication::topLevelWindows() or QGuiApplication::allWindows() to get the list of all such windows. Notice that a QWindowList is just a QList<QWindow *>. So see QList for how to traverse or iterate on that list.
Once you have found which QMainWindow you want, adding a QLabel into it is usual practice (but again, signals & slots could be helpful).
BTW, each (displayed) widget has its window, see QWidget::window()
About your code:
Your Main_Window is really poorly named (and the name is so confusing that I cannot use that). It is a list not a window. So code first:
QMainWindow* mainWindow = nullptr;
{
QList<QWindow*> topwinlist = QGuiApplication::topLevelWindows();
int nbtopwin = topwinlist.size();
for (int ix=0; ix<nbtopwin; ix++) {
QWindow*curwin = topwinlist.at(ix);
if (curwin->objectName() == "mainWindow")
mainWindow = dynamic_cast<QMainWindow*>(curwin);
}
}
I did not test the above code and I am not sure it is correct or even can compile. But why don't you just have a global pointer to your main window:
MainWindow*mymainwinp = nullptr;
and initialize it appropriately in your main body:
int main(int argc, char *argv[]) {
srand(time(NULL));
QApplication a(argc, argv);
MainWindow w;
mymainwinp = &w;
w.show();
int r = a.exec();
mymainwinp = nullptr;
return r;
}
then use mymainwinp elsewhere (e.g. in your Test)? If you want more elegant code, define your own subclass of QApplication and have mymainwinp be a field in it.

Related

Qt - Non Modal Dialog before Main Window is created

I've been struggling to do this : I want to show on a window a QWidget, or a QDialog before the MainWindow is created, but I cannot use exec() because it will enter its loop and won't create my MainWindow before I accept or reject the dialog.
The reason I want to do this is to have a widget showing information while the MainWindow constructs itself. I don't want to keep this extra window once the MainWindow is showing up.
I believe the issue comes from the fact that the main window is already created when a.exec() is called and the window won't show up before a.exec(). The solution I found is to use a QDialog instead and call exec() but it blocks the rest of the code which I don't want to happen.
Code :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start; //this is my custom QDialog, can be a QWidget if necessary.
qDebug() << "starting up!";
MainWindow w;
start.exec(); //I tried show() but it won't show up.
w.startApp(&start); //this function will do some stuff.
w.show();
//I don't want start to stay after mainwindow shows up
return a.exec();
}
Here is what I tried so far :
I tried to create and show the StartUpDialog while constructing the MainWindow but it won't work out.
Use start.show(), but it won't show before the mainwindow does, both for a QWidget and a QDialog.
Use start.exec(), this does what I want but it's modal and I couldn't make it non-modal with SetModal(false) or setWindowModality(Qt:NonModal).
I also tried to use start.exec() and attempted to reimplement accepted() and exec() so that it automatically calls accepted() as soon as it appears but it will still close the window.
Hopefully you can help me in that issue, and thanks for reading !
UPDATE : Solved thanks to Trap, here is how I made it :
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
StartUpDialog start;
QSplashScreen *splash = new QSplashScreen();
StartUpWidget *start = new StartUpWidget(splash);
splash->resize(350,380);
start->show();
splash->raise();
splash->show();
qDebug() << "starting up!";
MainWindow w;
w.startApp(start);
w.show();
splash->finish(&w);
start->deleteLater();
splash->deleteLater();
return a.exec();
}
My only concern is that I use a Gif inside my widget using QMovie and updating it has to be done manually apparently.
If I understand your problem correctly (showing a dialog until your main window is created), you should have a look at the QSplashScreen class : http://doc.qt.io/qt-5/qsplashscreen.html

QMainWindow doesn't .show() but .showFullScreen() works

I have a desktop application that I'm building which checks a QSetting value and if it isn't set shows one QMainWindow class but if it is, shows a different QMainWindow class. The two classes are literally identical at this point as it's early on and don't really contain anything.
In my main function this is what I've got:
int main (int argc, char *argv[]) {
...
if (userToken == "NO_USER") {
LoginWindow w;
w.show();
} else {
MainWindow w;
w.show();
}
return a.exec();
}
The only difference in this between the default project set up from when I created the project is the addition of the conditional window load. Both MainWindow and LoginWindow don't have anything loading other than the ui file associated with them, they're functionally the same.
The weirdness is if I do w.showFullScreen() for the LoginWindow it will show up and take up the whole screen, if I do w.show() nothing at all happens, no compiler warnings|errors, application runs fine, just no window displays.
If I remove the conditional statements and LoginWindow references, MainWindow shows up fine.
Any idea why a call to .showFullScreen() would work but a call to .show() on the same class wouldn't?
I am not sure if this solves you problem, but there definitely is a bug in your code. You are instanciating the window objects on the stack inside a a tight scope, and as you know those objects will be destructed as soon as they go out of that scope. What you are doing is letting them go out of scope before the application is ever started.
Please try this instead:
int main (int argc, char *argv[]) {
...
if (userToken == "NO_USER") {
LoginWindow w;
w.show();
return a.exec();
} else {
MainWindow w;
w.show();
return a.exec();
}
}

How to call created widget object in other widgets in QT [duplicate]

This question already exists:
How to create object widget in other widgets in QT
Closed 7 years ago.
In my application I'm having three widgets, I created the objects for all widgets in main() function, but I don't know how to call the created objects in other widgets, please guide me, I create the objects like this:
#include <QtGui/QApplication>
#include "widget.h"
#include "one.h"
#include "two.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget *w = new Widget();
One *one = new One();
Two *two = new Two();
w->show();
return a.exec();
}
How can created objects call other widgets?
You're not supposed to 'call' them, but to connect them through the Qt signal slot mechanism:
class One : public QObject {... boilerplate omitted
public slots:
void slotWithVoid(){ emit slotWithInt(1); }
signals:
void signalWithInt(int); // filled in by Qt moc
};
// note: give your widgets an owner
auto *w = new QButton(&app);
auto *one = new One(&app);
auto *two = new Two(&app);
connect(w, &QButton::click,
one, &One::slotWithVoid);
connect(one, &One::signalWithInt,
two, &Two::slotWithInt);
Now when something happens (e.g. a button click), Qt event system will take care that your objects are called in the right order, from the right thread, safely, etc...

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
}