Connect not working properly while using QDialog as a popup - c++

I am having a problem with connect in the program I am currently writing. I first create a "main window" dialog that contains buttons, line edits, etc. (which all work perfectly fine with my custom slots). One of the buttons (the "Add Class" button) should create a new pop up dialog that is a child of the mainWindow dialog. I wrote a new .h and .cpp for this new dialog (addClass.h and addClass.cpp). When I click the button, the dialog modality is set to ApplicationModal and up to this point, the code works; when I click "Add Class" and new dialog shows up as a pop up with all the labels, line edits, and buttons that I want. The problem comes in when I try and use the connect using this new class. Upon clicking the ok button the connect is not executed. The program compiles properly (using qmake and then make) and gives no errors during run time. I also took the .h and .cpp files from the pop up dialog and tested them with their own main.cpp and the connect worked perfectly. I am stumped as to what the problem could be, so any help would be awesome!
Here are some snipets of code that might be helpful:
the custom slot that initiates the pop up dialog in mainWindow.cpp (works and I include "addClass.h" in mainWindow.cpp):
void mainWindow::addClassCombo(){
addClass aC(win);
}
addClass.h:
#ifndef ADDCLASS_H
#define ADDCLASS_H
#include <QDialog>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QString>
class addClass : public QDialog{
Q_OBJECT
public:
addClass(QWidget *parent = 0);
private slots:
void addToTxt();
private:
QDialog *addMathClass;
QVBoxLayout *mainLayout;
QHBoxLayout *layoutOkCanc;
QLabel *nameL; //label for name of math class to be added
QLineEdit *name; //line edit for name
QPushButton *ok; //ok button
QPushButton *canc; //cancel button
};
#endif
addClass.cpp (works with its own main.cpp but not the one with my mainWindow.cpp):
#include <QtGui>
#include <QTextStream>
#include "addClass.h"
#include <iostream>
addClass::addClass(QWidget *parent):QDialog(parent){
addMathClass = new QDialog(parent);
mainLayout = new QVBoxLayout(addMathClass);
layoutOkCanc = new QHBoxLayout();
nameL = new QLabel("Math Class Name:");
name = new QLineEdit;
nameL->setBuddy(name);
ok = new QPushButton("Ok");
canc = new QPushButton("Cancel");
QObject::connect(canc, SIGNAL(clicked()), addMathClass, SLOT(close()) ); //<-works
QObject::connect(ok, SIGNAL(clicked()), this, SLOT(addToTxt()) ); //<-doesn't work
QObject::connect(ok, SIGNAL(clicked()), addMathClass, SLOT(close()) ); //<-works
layoutOkCanc->addStretch();
layoutOkCanc->addWidget(ok);
layoutOkCanc->addWidget(canc);
mainLayout->addWidget(nameL);
mainLayout->addWidget(name);
mainLayout->addLayout(layoutOkCanc);
addMathClass->setWindowModality(Qt::ApplicationModal);
addMathClass->setWindowTitle("Add Class");
addMathClass->show();
}
void addClass::addToTxt(){
std::cout<<"testing"<<std::endl;
}

Your addClass aC(win); goes out of scope and is being destroyed. Connection works, but after object destruction is disconnected. That's why you're not getting slot called

Related

How to insert items dynamically in scroll area and loading the scroll bar in Qt?

Before we start things, this could be a possible duplicate of Qt Scroll Area does not add in scroll bars, however the answer provided by the user and which seemed to work for the OP, does not work for me. I fear it may have to do with versions, perhaps? Or am I missing something? (it is possible!)
Alright, for those who know Qt, I am a beginner and I have what seem to be a pretty silly problem, but is giving me a lot of headaches:
I want to press a push button and add items to a container, then it is supposed to be possible to scroll it down. As simple as that.
So I thought that perhaps setting a layout to scrollArea would do the job. It indeed adds my items as I wanted, but it doesn't load the scrollBar. I have checked the ScrollPolicy already, but nothing satisfied my issue. It is like the GVBoxLayout doesn't increase size and doesn`t let the scroll area to scroll.
Does anybody have a clue on how to fix it?
Code below:
saleWindow.h
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include<QString>
namespace Ui {
class SaleWindow;
}
class SaleWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SaleWindow(QWidget *parent = 0);
~SaleWindow();
private slots:
void on_pushButton_clicked();
private:
Ui::SaleWindow *ui;
QVBoxLayout *gBoxLayout;
QMap<QString, QListWidget *> m_mappings;
};
#endif // SALEWINDOW_H
saleWindow.cpp
#include "salewindow.h"
#include "ui_salewindow.h"
#include <iostream>
#include <QGroupBox>
#include <QLabel>
//#include <QtSql/QSqlDatabase>
//#include <QtSql>
#include <QtWidgets/QPushButton>
SaleWindow::SaleWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::SaleWindow),
gBoxLayout(new QVBoxLayout())
{
ui->setupUi(this);
// Adding layout to scrollbar
{
ui->scrollArea_sales->setWidgetResizable(true);
ui->scrollArea_sales->setLayout(gBoxLayout);
QWidget *central = new QWidget;
ui->scrollArea_sales->setWidget(central);
}
}
SaleWindow::~SaleWindow()
{
delete ui;
delete gBoxLayout;
}
void SaleWindow::on_pushButton_clicked()
{
QGroupBox *sale = new QGroupBox();
sale->setTitle("minha venda");
gBoxLayout->addWidget(sale);
ui->scrollArea_sales->setLayout(gBoxLayout);
}
If you are using a QScrollArea for the scrollArea_sales object from the ui editor, you can see in the object inspector(qtdesigner) a default widget in the QScrollArea, so you not need to add this. Try this code:
// Adding layout to scrollbar(on the contrctor, replace yor scope by)
{
ui->scrollArea_sales->widget()->setLayout(gBoxLayout);
}
void MainWindow::on_pushButton_clicked() {// on the slot replace all by:
QGroupBox *sale = new QGroupBox();
sale->setTitle("minha venda");
ui->scrollArea_sales->widget()->layout()->addWidget(sale);
}

How to get the member object for SLOT in connect()?

I Started learning Qt (5.5) a couple of days ago, and I recently got stuck on something when working with the connect function, specifically the SLOT parameter. I'm calling a member function from the same class that the connect function is called in, but when the SLOT function is triggered it acts like it's creating a new class object. It worked initially when I kept everything in the same class, but this problem popped up when I tried implementing a hierarchy. I wrote a short program to demonstrate my problem.
Main.cpp
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
MainWindow QtWindow;
QtWindow.show();
return app.exec();
}
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QGridLayout>
#include "TopWidget.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QMainWindow *parent = 0);
private:
QWidget *mainWidget;
QGridLayout *mainLayout;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QMainWindow *parent) : QMainWindow(parent){
mainWidget = new QWidget(this);
mainLayout = new QGridLayout(mainWidget);
setCentralWidget(mainWidget);
TopWidget tWidget(this);
mainLayout->addWidget(tWidget.topWidget, 0, 0);
}
TopWidget.h
#ifndef TOPWIDGET_H
#define TOPWIDGET_H
#include <stdlib.h>
#include <QWidget>
#include <QPushButton>
#include <QGridLayout>
#include <QDebug>
#include <QErrorMessage>
class TopWidget : public QWidget
{
Q_OBJECT
public:
TopWidget(QWidget *parent);
QWidget *topWidget;
private:
QGridLayout *wLayout;
QPushButton *Button;
int memVar1;
int memVar2;
private slots:
void testConnect();
//void SlotWithParams(int a, int b);
};
#endif // TOPWIDGET_H
TopWidget.cpp
#include "TopWidget.h"
TopWidget::TopWidget(QWidget *parent) : QWidget(parent){
topWidget = new QWidget(parent);
wLayout = new QGridLayout(topWidget);
memVar1 = 123;
memVar2 = 321;
Button = new QPushButton("Click Me", topWidget);
connect(Button, &QPushButton::clicked, [=](){ TopWidget::testConnect(); });
}
void TopWidget::testConnect(){
qDebug("Button worked");
if(memVar1 != 123 || memVar2 != 321){
qDebug("Linking failed");
}else{
qDebug("Linking success");
}
}
Since I just started with Qt, I don't have a good feel for what's "proper" Qt code, and what I should avoid, so tips in that direction are also appreciated. The following is the qmake file, if that's important.
CONFIG += c++11
CONFIG += debug
CONFIG += console
QT += widgets
QT += testlib
SOURCES += main.cpp
SOURCES += MainWindow.cpp
SOURCES += TopWidget.cpp
HEADERS += MainWindow.h
HEADERS += TopWidget.h
Release:DESTDIR = bin/Release
Release:OBJECTS_DIR = obj/Release
Release:MOC_DIR = extra/Release
Release:RCC_DIR = extra/Release
Release:UI_DIR = extra/Release
Debug:DESTDIR = bin/Debug
Debug:OBJECTS_DIR = obj/Debug
Debug:MOC_DIR = extra/Debug
Debug:RCC_DIR = extra/Debug
Debug:UI_DIR = extra/Debug
When I run the program in debug mode and press the button, it outputs "Button worked" indicating the link to the function was successful, but then outputs "Linking failed" indicating that a new object was created rather than taking the old one. My knowledge of C++ is patchy, since I only pick up what I need to, and I spent hours yesterday trying to fix this, so forgive me if the fix is something ridiculously easy, but I've mentally exhausted myself over this.
The problem comes from this line:
TopWidget tWidget(this);
You are allocating tWidget on the stack, and it gets destroyed just at the end of the MainWindow constructor.
Replace by:
TopWidget * tWidget = new TopWidget(this);
Also, you should replace your connect line by this one
connect(Button, &QPushButton::clicked, this, &TopWidget::testConnect);
It appears that your slot is called even after the TopWidget is destroyed. Qt normally disconnects connections when sender or receiver are destructed, but it's not able to do that when you connect to a lambda.
And finally, you are doing something weird. What is the purpose of your TopWidget class besides just creating another widget and receiving signals on its slot? You never add the TopWidget to any layout, but just its child. TopWidget is never shown, so it should rather derive from QObject only.

QButtonGroup setExclusive() issue

I'm trying to group a few QPushButton`s into QButtonGroup with exclusive checking, but after launch i'm still able to check multiple buttons.
// pen toggle button
penB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
penB.setIconSize(QSize(ICON_SIZE,ICON_SIZE));
penB.setCheckable(true);
penB.toggle();
penB.setIcon(QIcon(":icons/pen.png"));
// circle toggle button
circleB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
circleB.setIconSize(QSize(ICON_SIZE,ICON_SIZE));
circleB.setCheckable(true);
circleB.setIcon(QIcon(":icons/circle.png"));
figureBox.addButton(&penB);
figureBox.addButton(&circleB);
figureBox.setExclusive(true);
// add buttons to grid
layoutG.addWidget(&openB,1,1);
layoutG.addWidget(&saveB,1,2);
layoutG.addWidget(&penB,1,3);
layoutG.addWidget(&circleB,2,3);
I think, its just need to procees some events. If its true, which events exactly?
Thanks in advance.
I've tried to replicate your example and for me it works OK:
widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QPushButton>
#include <QButtonGroup>
#include <QGridLayout>
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
QGridLayout layoutG;
QButtonGroup figureBox;
QPushButton openB;
QPushButton saveB;
QPushButton penB;
QPushButton circleB;
};
#endif // WIDGET_H
widget.cpp:
#include "widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent)
{
// pen toggle button
penB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
penB.setIconSize(QSize(16, 16));
penB.setCheckable(true);
penB.toggle();
// circle toggle button
circleB.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
circleB.setIconSize(QSize(16, 16));
circleB.setCheckable(true);
figureBox.addButton(&penB);
figureBox.addButton(&circleB);
figureBox.setExclusive(true);
// add buttons to grid
layoutG.addWidget(&openB,1,1);
layoutG.addWidget(&saveB,1,2);
layoutG.addWidget(&penB,1,3);
layoutG.addWidget(&circleB,2,3);
setLayout(&layoutG);
}
Widget::~Widget()
{
}
The single thing that could be not ok in your code is that I don't see where you set the layout, but maybe you didn't add the code for simplicity reasons. Another thing is that the only excluding buttons would be penB and circleB.
Check my example, see what you're doing wrong and maybe come back with a feedback.
Sorry, guys. Its time to go to the bed. Im forgot to declare QButtonGroup in .h file, it was declared at the local function, so just memory leak.

Custom Slot from qt4 design generated h file

Hi Im try to make a custom slot with the h file that qt4 designer generated
I see how the standard slot is made but i would like to, "once past learning this step" have run terminal commands and have it output in the text box so im tryin to replace the past() slot with one i can right commands in
Here is the h file file that works great but.... the above problem'' trying to understand the flow.. 2nd day so any pointers are awsome. so here it is i will comment where i think i should be working.. but have had no success all day lol.
#ifndef SWEETGUIFORMQ19488_H
#define SWEETGUIFORMQ19488_H
#include <QtCore/QVariant>
#include <QtGui/QAction>
#include <QtGui/QApplication>
#include <QtGui/QButtonGroup>
#include <QtGui/QDialogButtonBox>
#include <QtGui/QHeaderView>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QWidget>
QT_BEGIN_NAMESPACE
class Ui_SweetGuiForm
{
public:
QVBoxLayout *verticalLayout_2;
QVBoxLayout *verticalLayout;
QTextEdit *textEdit;
QDialogButtonBox *buttonBox;
void setupUi(QWidget *SweetGuiForm)
{
if (SweetGuiForm->objectName().isEmpty())
SweetGuiForm->setObjectName(QString::fromUtf8("SweetGuiForm"));
SweetGuiForm->resize(511, 275);
verticalLayout_2 = new QVBoxLayout(SweetGuiForm);
verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2"));
verticalLayout = new QVBoxLayout();
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
textEdit = new QTextEdit(SweetGuiForm);
textEdit->setObjectName(QString::fromUtf8("textEdit"));
verticalLayout->addWidget(textEdit);
buttonBox = new QDialogButtonBox(SweetGuiForm);
buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
verticalLayout->addWidget(buttonBox);
verticalLayout_2->addLayout(verticalLayout);
QWidget::setTabOrder(textEdit, buttonBox);
retranslateUi(SweetGuiForm);
QObject::connect(buttonBox, SIGNAL(rejected()), SweetGuiForm, SLOT(close()));
ok here i guess i could replace the paste() with on_buttonBox_accepted(), please correct me i really am still quessing at this point but where do i right the function? do i do the in a file called sweetguiform.cpp ? this is where im lost.. help..
QObject::connect(buttonBox, SIGNAL(accepted()), textEdit, SLOT(paste()));
QMetaObject::connectSlotsByName(SweetGuiForm);
} // setupUi
void retranslateUi(QWidget *SweetGuiForm)
{
SweetGuiForm->setWindowTitle(QApplication::translate("SweetGuiForm", "Form", 0, QApplication::UnicodeUTF8));
} // retranslateUi
};
namespace Ui {
class SweetGuiForm: public Ui_SweetGuiForm {};
} // namespace Ui
QT_END_NAMESPACE
#endif // SWEETGUIFORMQ19488_H
Is this the way to do things when brand new?
I think you shouldn't be editing the header file that Qt generates for you. Instead, you should write your own header/implementation file that includes this auto-generated header and sets up the signal-slot connections there. For example:
#include "ui_SweetGuiForm.h"
class SweetGuiForm : public QWidget
{
public:
SweetGuiForm( ): ui( new Ui::SweetGuiForm )
{
ui->setupUi( this );
}
public slots:
void on_buttonBox_accepted( )
{
// your code here
}
protected:
Ui::SweetGuiForm* ui;
};
Qt will find the on_buttonBox_accepted method and set up the signal-slot connection for you, so you don't have to call QObject::connect.

Qt window wont close using "this->close()" from other class

I will start off by explaining my main goal. I have a main window with 7 buttons on it(amongst other things), when you hit each button, it closes out the current window and opens up a new window. All the windows will have the same 7 buttons, so you can go between each window. With all windows having the exact same 7 buttons, I wanted to set up a function that each class can call to set up each button and connect to a slot() in my mainwindow.cpp(called setupSubsystemButtons in example below). However, I can't seem to get the window to close using the standard "this->close()"...it works when I go from the main window to another window(the main window closes) but when I go from a different window to say the home window, the different window doesn't close. Suggestions would be greatly appreciated. My guess is that my understanding of "this" when it comes to calling slots in another class is wrong.
mainwindow.cpp( the parts that are relevant)
void MainWindow::ECSgeneralScreen()
{
ECSgeneralCommand *ECSgeneral = new ECSgeneralCommand;
this->close();
ECSgeneral->show();
//opens up the ECS screen
}
void MainWindow::homeScreen()
{
MainWindow *home = new MainWindow;
this->close();
home->show();
//opens up the ECS screen
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setupSubsystemButtons(QGridLayout *layout)
{
//Push Button Layout
homeScreenButton = new QPushButton("Home");
layout->addWidget(homeScreenButton, 3, 11);
connect(homeScreenButton, SIGNAL(clicked()), this, SLOT(homeScreen()));
ECSgeneralScreenButton = new QPushButton("General");
layout->addWidget(ECSgeneralScreenButton,5,11);
connect(ECSgeneralScreenButton, SIGNAL(clicked()), this, SLOT(ECSgeneralScreen()));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QDialog
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
QWidget *window;
void setupSubsystemButtons(QGridLayout *layout);
~MainWindow();
private slots:
public slots:
void ECSgeneralScreen();
void homeScreen();
};
#endif // MAINWINDOW_H
ecsgeneralcommandWindow
include "ecsgeneralcommand.h"
#include "mainwindow.h"
#include <QtWidgets>
#include <QtCore>
ECSgeneralCommand::ECSgeneralCommand(MainWindow *parent) : QDialog(parent)
{
QGridLayout *layout = new QGridLayout;
QWidget::setFixedHeight(600);
QWidget::setFixedWidth(650);
...
//Setup Subsystem Buttons
test.setupSubsystemButtons(layout);
setLayout(layout);
}
ecsgeneralcommandWindow header
#ifndef ECSGENERALCOMMAND_H
#define ECSGENERALCOMMAND_H
#include <QDialog>
#include <QMainWindow>
#include <QtWidgets>
#include <QObject>
#include "mainwindow.h"
class ECSgeneralCommand : public QDialog
{
Q_OBJECT
public:
explicit ECSgeneralCommand(MainWindow *parent = 0);
private:
MainWindow test;
public slots:
};
#endif // ECSGENERALCOMMAND_H
Slots are just normal functions. When Qt invokes a slot, it ends up calling the appropriate receiver's method. In other words, this equals to the value of the 3rd argument of your connect statements. You passed this there, so the receiver is MainWindow object. E.g. MainWindow::homeScreen method always tries to close MainWindow. If it is already hidden, this action takes no effect.
You should either have a slot in each window class and connect buttons to appropriate receivers, or use a pointer to the currently active window instead of this when calling close(). But your architecture is strange in the first place. Why would you need to create these buttons for each window? It is reasonable to create them once and use in all windows. Also hiding and showing windows is not necessary. You can create one main window with buttons and a QStackedWidget that will contain the content of all other windows. Maybe you can even use QTabWidget instead of these buttons.