c++qtqpushbuttonqdialog

Connect QPushButton in the QDialog in one header file with method in another header file


I've got such a project set up in CMakeLists.txt: (It's a window that opens in the maximized size. There is one button in it. When the button will be pressed - a popup window appears)

cmake_minimum_required(VERSION 3.5)

project(ADB VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 COMPONENTS Quick Widgets REQUIRED)

set(SRC_DIR "${CMAKE_SOURCE_DIR}/src")
set(HEADERS_DIR "${CMAKE_SOURCE_DIR}/headers")

set(GLOB_RECURSE
    "${SRC_DIR}/main.cpp"
    "${HEADERS_DIR}/mainwindow.cpp"
    "${HEADERS_DIR}/mainwindow.hpp"
    "${HEADERS_DIR}/profilecreator.cpp"
    "${HEADERS_DIR}/profilecreator.hpp"
)

include_directories(${SRC_DIR})
include_directories(${HEADERS_DIR})

qt_add_executable(
    appADB
    WIN32
    "${GLOB_RECURSE}"
)

set_target_properties(
    appADB PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

target_link_libraries(
    appADB
    PRIVATE Qt${QT_VERSION_MAJOR}::Widgets
    PRIVATE Qt${QT_VERSION_MAJOR}::Gui
)

install(TARGETS appADB
    BUNDLE DESTINATION .
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(ADB)
endif()

I've got the MainWindow class, that is simply initiates popup window by pressing QPushButton 'createP':

#ifndef MAINWINDOW_HPP
#define MAINWINDOW_HPP

#include <QWidget>
#include <QDialog>

class MainWindow : public QWidget
{
    Q_OBJECT

public:
    MainWindow(QWidget* parent = nullptr);
    ~MainWindow();

private:
    QDialog* popup;

};
#endif  // MAINWINDOW_HPP

in the mainwindow.cpp:

#include "mainwindow.hpp"
#include "profilecreator.hpp"

#include <QVBoxLayout>
#include <QGroupBox>
#include <QPushButton>
#include <QLineEdit>

MainWindow::MainWindow(QWidget* parent) : QWidget(parent)
{
    QPushButton* createP = new QPushButton("Create profile");
    createP->setStyleSheet("background-color: gray;");
    createP->setFixedSize(100, 25);
    createP->setToolTip("Create profile");

    QHBoxLayout* creationControls = new QHBoxLayout;
    controls->addWidget(createP);

    QGroupBox* controlsBox = new QGroupBox;
    controlsBox->setLayout(controls);

    // Add box the main layout
    QVBoxLayout* mainLayout = new QVBoxLayout;
    // add controls
    mainLayout->addWidget(controlsBox);

    setLayout(mainLayout);

    // Customize window
    setWindowTitle(tr("Checkbuttons table"));
    resize(1000, 1000);

    //==============Pop-up section=================

    // Create the popup window
    popup = new ProfileCreator();

    // Set the Qt::Popup window flag
    // NOTE: You can set flags only here, in the mainwindow where you instantiate popup class
    // otherwise: popup don't close correctly
    popup->setWindowFlags(windowFlags() | Qt::Popup);

    // Connect the createP button's clicked signal to the popup window's show slot
    QObject::connect(createP, &QPushButton::clicked, this, [&]() { popup->show(); });
        //<--- everything is good whith connecting 'createP' button and showing popup dialog

    // Connect create button from popup dialog to the addRow() method
    QObject::connect(popup, &ProfileCreator::createProfileClicked, this, [&]() { qDebug() << "you pressed"; });
       //<--- PROBLEM here. No instance of connect method for such actions
       // if I could simply log that I pressed a QDialog's button that would be enough for now
}

MainWindow::~MainWindow()
{
}

So in the ProfileCreator class are inherit QDialog class. In the header file:

#ifndef PROFILECREATOR_HPP
#define PROFILECREATOR_HPP

#include <QDialog>
#include <QPushButton>
#include <QLineEdit>

class ProfileCreator : public QDialog
{
    Q_OBJECT

signals:
    void createProfileClicked();

public:
    ProfileCreator();

    QPushButton* create;
};

#endif  // PROFILECREATOR_HPP

In the implementation file:

#include "profilecreator.hpp"
#include <QVBoxLayout>

ProfileCreator::ProfileCreator()
{
    // Set the size of the popup window
    this->resize(800, 1200);

    create = new QPushButton("Create");

    // Set the size policies of the widgets to Fixed
    create->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);

    // Create a layout for the widgets
    QVBoxLayout* layout = new QVBoxLayout();

    // Add the widgets to the layout
    layout->addWidget(create);
    layout->addStretch();

    // Set the layout of the popup window
    this->setLayout(layout);

    // Emit signal of pushing the create new profile button when it pressed
    QObject::connect(create, &QPushButton::clicked, this, [&]() { emit createProfileClicked(); });
        //<--- So with the previous line I want to send a signal that QDialog's button is clicked.
        //In the MainWindow constructor class I connect to such signal
}

And in main.cpp:

#include "mainwindow.hpp"

#include <QApplication>

int main(int argc, char* argv[])
{
    // Invoke application, just to appear everything else
    QApplication app(argc, argv);

    // Here we keep all widgets
    MainWindow window;

    // Use the following if you want to have the app open as maximized window:
    window.setWindowState(Qt::WindowMaximized);

    // Show window to application
    window.show();

    return app.exec();
}

So what do I do and what do I expect to get in a few steps:

  1. I create a popup window as a ProfileCreator class inherited from QDialog;
  2. In the ProfileCreator class I have QPushButton* create;
  3. When I press create in the ProfileCreator object will be emitted createProfileClicked signal.
  4. In the MainWindow class I initialize a pointer to the ProfileCreator object, 'popup'.
  5. Also in the MainWindow class I create a QPushButton* createP.
  6. I connect createP &QPushButton::clicked signal with popup show() method. And a popup should show up. <--- No problems until this point.
  7. I also want to connect a QPushButton* create from ProfileCreator to the lambda: [&](){qDebug() << "you pressed";}. To log a message - for start.

But it seems that I don't know how to do a connection for step 7.

So, can anyone tell me how to connect the button from the popup window in one class with slots in another class? I know that if a popup window will be created in the constructor of MainWindow there wouldn't be a problem connecting. But I want to organize my code and separate MainWindow from ProfileCreator popup window.


Solution

  • First control variable is not defined in your code, you may fix it with :

    QHBoxLayout* creationControls = new QHBoxLayout;
    creationControls->addWidget(createP);
    
    QGroupBox* controlsBox = new QGroupBox;
    controlsBox->setLayout(creationControls);
    

    About the connection issue ("step 7"), popup is of type QDialog * so your custom signal is not available as a QDialog :

    #ifndef MAINWINDOW_HPP
    #define MAINWINDOW_HPP
    
    #include <QWidget>
    #include <QDialog>
    
    #include "profilecreator.hpp"
    
    class MainWindow : public QWidget
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget* parent = nullptr);
        ~MainWindow();
    
    private:
        ProfileCreator* popup; // instead of QDialog *
    
    };