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...
Related
My situation is, a big Qt project with many QWidget communication requirement.
For example, I've a QPushButton B and a QLabel L, I need to click thd button B to show some text on label L or hide it, etc. But the problem is neither of them can get each other's object pointer, because both of them located in a deep QWidget tree, maybe their grandgrandgrand parent widget was sibling, what ever.
So my option, is creating a global unique QObject, just for singal/slot forwad,like this:
class GlobalForward: public QObject
{
Q_OBJECT
public:
GlobalForward():QObject(null) {}
signal:
void SigForwardButton(bool toggle);
}
GlobalForward* gForwardObj;
int main(int argc, char* argv[])
{
QApplication app(argc, argv[]);
gForwardObj = new GlobalForward();
QWidget w;
QPushButton* button = new QPushButton(&w);
QWidget m;
QLabel* label = new QLabel(&m);
w.show();
m.show();
connect(button, &QPushButton::clicked, gForwardObj, &GlobalForward::SigForwardButton);
connect(gForwardObj, &GlobalForward::SigForwardButton, label, &QWidget::hide);
return app.exec();
}
Actually, the button and the label are so faraway that they cannot see each other. I want to use GlobalForward to concat the singnal to make it work . Further more, it can forwad QEvent silmiarly.
What I want to know is, is this way properly solved my problem, and what's the disadvantage of it. Also, any better solution will be appropriate, thanks.
For example I have 2 widgets and I press button on first widget. I need to delete first widget and create new widget.
How is it possible? I mean some structure for this. I used stackedwidgets, but pages from stackedwidgets located in memory. I need to avoid this.
void Window::on_registrationButton_clicked(){
ui->logWindow->hide();
ui->RegistrWindow->show();
}
As you are going to eliminate the object you can not do it within the same class the object belongs to, you have to do it outside of it, for example in the following code I created a signal that is triggered when the button is pressed, this I have connected it to a lambda function where the new object is created and the object that emits it is eliminated.
class LogWindow: public QWidget{
Q_OBJECT
public:
LogWindow(const QString &text, QWidget *parent=Q_NULLPTR):QWidget(parent){
setLayout(new QVBoxLayout);
btn = new QPushButton(text, this);
layout()->addWidget(btn);
connect(btn, &QPushButton::clicked, this, &LogWindow::customSignal);
}
signals:
void customSignal();
private:
QPushButton *btn;
};
class RegWindow : public QWidget{
[...]
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LogWindow *log= new LogWindow("LogWindow");
RegWindow *reg;
QObject::connect(log, &LogWindow::customSignal, [®, &log](){
reg = new RegWindow("RegWindow");
reg->show();
log->deleteLater();
});
log->show();
return a.exec();
}
#include "main.moc"
The complete example can be found in the following link
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.
I am following Qt examples (like TabDialog) and I notice that all the UI items are created as pointers - yet I see no delete and no destructor.
Is that right ? Will that not lead to memory leak ?
I am trying to add destructors
~TabDialog()
{
delete tabWidget;
delete buttonBox;
}
and on caller
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
But the program crashes when I close the dialog.
Are the destructors, and delete all pointer items, unnecessary or am I doing it wrong ?
I think that you are confused because of these lines:
tabWidget = new QTabWidget;//and so on
You don't see explicit parent (like new QTabWidget(this);), but it is not necessary here. Take a look here:
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(tabWidget);
mainLayout->addWidget(buttonBox);
setLayout(mainLayout);
setLayout will reparent your QVBoxLayout and QVBoxLayout will reparent all widgets inside it, so now your widgets has a parent and they will be destroyed after your dialog.
As doc said:
When you use a layout, you do not need to pass a parent when
constructing the child widgets. The layout will automatically reparent
the widgets (using QWidget::setParent()) so that they are children of
the widget on which the layout is installed.
Note: Widgets in a layout are children of the widget on which the
layout is installed, not of the layout itself. Widgets can only have
other widgets as parent, not layouts.
I'm sorry, but this just doesn't reproduce. The test case is below. You'd probably need to add some extra code to make it reproduce.
Qt's memory management will take care of everything, since all of the widgets end up having parents. Namely:
Tabs are parented as soon as they are passed to addTab.
tabWidget and buttonBox are parented as soon as they are added to the layout.
Since you delete the tabWidget and buttonBox before Qt attempts to delete them, everything is fine. As soon as you delete them, QObject's memory management is informed and they are removed from the TabDialog's child list. I've made this point explicit in the destructor code.
The meaning of Q_ASSERT is: "At this point during runtime, the following must be true". If we're wrong, the debug build will abort. Since it doesn't, the assertions are correct. Thus, before delete tabWidget, the dialog has both QTabWidget and QDialogButtonBox children. After delete tabWidget, the dialog should not have any QTabWidget children anymore. And so on.
#include <QApplication>
#include <QDialog>
#include <QTabWidget>
#include <QDialogButtonBox>
#include <QVBoxLayout>
class TabDialog : public QDialog
{
QTabWidget *tabWidget;
QDialogButtonBox *buttonBox;
public:
TabDialog() :
tabWidget(new QTabWidget),
buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok |
QDialogButtonBox::Cancel))
{
tabWidget->addTab(new QWidget, tr("General"));
tabWidget->addTab(new QWidget, tr("Permissions"));
tabWidget->addTab(new QWidget, tr("Applications"));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(tabWidget);
layout->addWidget(buttonBox);
setLayout(layout);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
~TabDialog() {
Q_ASSERT(findChild<QTabWidget*>());
Q_ASSERT(findChild<QDialogButtonBox*>());
delete tabWidget;
Q_ASSERT(! findChild<QTabWidget*>());
Q_ASSERT(findChild<QDialogButtonBox*>());
delete buttonBox;
Q_ASSERT(! findChild<QTabWidget*>());
Q_ASSERT(! findChild<QDialogButtonBox*>());
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
return 0;
}
The only way it'd crash is if you tried the following:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TabDialog *tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->exec();
// At this point `tabDialog` is a dangling pointer.
delete tabDialog; // crash
return 0;
}
Unfortunately, Qt examples are a case of pointless premature pessimization. Qt's classes utilize the PIMPL idiom extensively. Thus the size of, say a QTabWidget is not much larger than that of QObject (48 vs. 16 bytes on my 64 bit platform). By allocating the fixed members of your class on the heap, you're performing two heap allocations: a small one for the QObject-derived class, and then another one for its PIMPL. You're doubling the number of allocations for no good reason.
Here's how to avoid this pessimization:
#include <QApplication>
#include <QDialog>
#include <QTabWidget>
#include <QDialogButtonBox>
#include <QVBoxLayout>
class TabDialog : public QDialog
{
QVBoxLayout m_layout;
QTabWidget m_tabWidget;
QDialogButtonBox m_buttonBox;
QWidget m_generalTab, m_permissionsTab, m_applicationsTab;
public:
TabDialog() :
m_layout(this),
m_buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
{
m_tabWidget.addTab(&m_generalTab, tr("General"));
m_tabWidget.addTab(&m_permissionsTab, tr("Permissions"));
m_tabWidget.addTab(&m_applicationsTab, tr("Applications"));
m_layout.addWidget(&m_tabWidget);
m_layout.addWidget(&m_buttonBox);
connect(&m_buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(&m_buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
auto tabDialog = new TabDialog();
tabDialog->setAttribute(Qt::WA_DeleteOnClose);
tabDialog->show(); // NOT tabDialog->exec()!!
return app.exec();
}
The less explicit heap allocations, the better. This way you can't even be tempted to delete anything in the destructor, since there are no pointers involved. The compiler generates necessary destructor calls for you automatically.
Furthermore, if you're showing only one window in main, there's no point to explicit heap allocation either:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TabDialog tabDialog;
tabDialog.show();
return app.exec();
}
Memory handling on Qt
Qt handles the widgets as a tree, every widget has a parent and every parent has
the obligation to free the children memory, if a widget has no parent you should delete it manually with the operator delete.
I'm a beginner in C++ and I started learning how to use QT components through code at MVS IDE. I still don't know if that was the best option to begin, but since I'm a java programmer, I made the path I made with Java (Swing components). So, my problem is, how to comunicate two class of my code, since in one I made the window frame and in the other I made my menu bar?
In java I would make something like:
JFrame frame = new JFrame();
JMenu menu = new JMenu();
frame.add(menu);
Anyway, This is my code:
#include "Header.h"
class MainWindow{
private:
QWidget *widget;
public:
void buildWindow(QApplication& app){
widget = app.desktop();
QMainWindow *main_window = new QMainWindow();
QWidget *mainWid = new QWidget(main_window);
MyMenuBar myMenuBar(mainWid);
main_window->setWindowState(mainWid->windowState() | Qt::WindowMaximized);
main_window->setWindowTitle("QT Trainning");
main_window->show();
}
};
class MyMenuBar:QMainWindow {
public:
MyMenuBar(QWidget* mainWid){
QAction *quit = new QAction("&Quit", this);
QMenuBar *menu = new QMenuBar(mainWid);
QMenu *file;
menu->addMenu(file);
file = menuBar()->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow frame;
frame.buildWindow(app);
return app.exec();
}
I tryed to create an Instance of MenuBar inside the Window class but wans't so helpfull and to be honest most of the materials I found to deal with QT interface they supose that you are using the QT GUI...Any tips about how to solve the problem or what should I really do to practice C++??
Thanks in advance
You should specify access specifier for inheritance,otherwise default mode is public.
Also, if you are going to have all the classes in the same file the ordering is important(i think). In your case MyMenuBar should come before MainWindow. So, it is a better practice to have different components in different headers and then include them as necessary.
Here is the code for the case where you need two classes separately:
class TrainingMenu:public QMainWindow {
public:
TrainingMenu(QMenuBar *menubar){
QAction *quit = new QAction("&Quit", menubar);
QMenu *file;
file = menubar->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
};
class MainWindows:public QMainWindow{
private:
TrainingMenu* _menu;
public:
MainWindows(QMainWindow *parent = 0):QMainWindow(parent) {
_menu=new TrainingMenu(MainWindows::menuBar());
this->setWindowTitle("Qt training");
this->setWindowState(Qt::WindowMaximized);
this->show();
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindows window;
return app.exec();
}
This example should be good enough. You do the following:
Create a QMenu with the top widget as a parent
Add submenu QMenu instances to the root level menu