QPushButton not clickable even if activated



  • Hey!

    I'm programming a little software to help me coding my future softwares: its goal is to generate repetitive code when I create classes. My problem is for the part of code linked to the creation of constructors. We can have more than one constructor so I wanted to create a list in which there are items on the side of minus signs (which delete this item) and, at the end of the list, there is a button with a plus sign (which adds an item) (see picture below). My problem is that when I add/remove some items, at some point, some button won't be clickable anymore; there is no visual changement when the mouse is over the button (no highlighting), even if the rest of the visual part is normal. I don't exactly understand where it's coming from, and the only way to "unlock" the buttons is to turn the window into full screen.

    Picture of the list with plus and minus signed buttons:
    0_1564237922970_aaasssddd.PNG

    I'd really like some help if you understand where the error is coming from. To help you for that, you'll find my code just under this. I'm using Qt 5.12.4 extension on Visual Studio 2019.

    main.cpp

    #include "Window.h"
    
    #include <QtWidgets/QApplication>
    
    int main(int argc, char *argv[])
    {
    	QApplication a(argc, argv);
    	Window w;
    	w.show();
    	return a.exec();
    }
    

    window.h

    #ifndef DEF_WINDOW
    #define DEF_WINDOW
    
    #include "Constructor.h"
    
    #include <QWidget>
    #include <QVBoxLayout>
    #include <QPushButton>
    
    #include <vector>
    
    class Window : public QWidget
    {
    	Q_OBJECT
    
    public:
    	Window();
    
    public slots:
    	void addConstructor();
    
    private:
    	QVBoxLayout* mainLayout = new QVBoxLayout;
    	QVBoxLayout* constructorLayout = new QVBoxLayout;
    	std::vector<Constructor*>* constructorVector = new std::vector<Constructor*>;
    	QPushButton* addConstructorButton = new QPushButton("+", this);
    };
    
    #endif
    

    window.cpp

    #include "Window.h"
    
    Window::Window() {
    	connect(addConstructorButton, SIGNAL(clicked()), this, SLOT(addConstructor()));
    
    	mainLayout->addLayout(constructorLayout);
    	mainLayout->addWidget(addConstructorButton);
    	setLayout(mainLayout);
    }
    
    void Window::addConstructor() {
    	Constructor* c = new Constructor(this, constructorLayout, constructorVector);
    	constructorLayout->addWidget(c);
    	constructorVector->push_back(c);
    }
    

    constructor.h

    #ifndef DEF_CONSTRUCTOR
    #define DEF_CONSTRUCTOR
    
    #include <QWidget>
    #include <QLineEdit>
    #include <QHBoxLayout>
    #include <QPushButton>
    #include <QLayout>
    
    #include <vector>
    
    class Constructor : public QWidget
    {
    	Q_OBJECT
    
    public:
    	Constructor(QWidget* parentWidget, QLayout* parentLayout, std::vector<Constructor*>* parentVector);
    
    public slots:
    	void destroySelf();
    
    private:
    	QLineEdit* lineEdit = new QLineEdit(this);
    
    	QPushButton* removeConstructorButton = new QPushButton("-", this);
    	QLayout* parentLayout;
    	QWidget* parentWidget;
    	std::vector<Constructor*>* parentVector;
    };
    
    #endif
    

    constructor.cpp

    #include "Constructor.h"
    
    Constructor::Constructor(QWidget* parentWidget, QLayout* parentLayout, std::vector<Constructor*>* parentVector) : QWidget(parentWidget)
    {
    	this->parentWidget = parentWidget;
    	this->parentLayout = parentLayout;
    	this->parentVector = parentVector;
    
    	connect(removeConstructorButton, SIGNAL(clicked()), this, SLOT(destroySelf()));
    
    	QHBoxLayout* layout = new QHBoxLayout;
    	layout->addWidget(lineEdit);
    	layout->addWidget(removeConstructorButton);
    	setLayout(layout);
    }
    
    void Constructor::destroySelf()
    {
    	this->disconnect();
    
    	delete lineEdit;
    	delete removeConstructorButton;
    
    	parentLayout->removeWidget(this);
    
    	//remove object from vector
    	for (int i = 0; i < parentVector->size(); i++)
    		if (parentVector->at(i) == this) {
    			parentVector->erase(parentVector->begin() + i);
    			break;
    		}
    }
    

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    I don't have a direct answer to your question because there's currently nothing really obvious.

    However, there's at least one issue I can see in the design. Your Constructeur widget knows way more than it should about its containing widget. You are creating a tight loop that will end up a nightmare to maintain.



  • Thank you for you answer.

    I'm not sure I'm completely understanding what you're saying and, mostly, how I should fix it. Which input shouldn't be here and what do you mean by "tight loop" (why will it end up a nightmare to maintain) ?

    I'm sorry, I'm quite new with C++ programming. ^^'


  • Qt Champions 2018

    @lanfeust I guess @SGaist refers to the child-parent relationship.

    A child object should know nothing about its parent. The parent, which holds the childs, should have that knowlegde.

    Otherwise it's very hard to re-use the childs somewhere else.

    Example: When building a car (parent), you mount a motor and a gearbox (childs) to get a powertrain.

    However, neither the motor nor the gearbox know each other. It's the cars responsibility to make sure they fit together.

    Regards



  • This post is deleted!


  • @aha_1980 Very interessant, I think I understand, thank you. :)



  • Thank you everbody, thanks to you I have found a way to correct my program. I did as you told me to do: I removed everything the Constructor object knew about its parent (puting it in the parent instead) and the problem went away. I still don't know from where it was coming, but we can clearly see that having a better-programmed program helps to correct some bugs. ^^

    Thanks again to everybody. :D

    If you want my corrected code, here it is:

    main.cpp (nothing changed)

    #include "Window.h"
    
    #include <QtWidgets/QApplication>
    
    int main(int argc, char *argv[])
    {
    	QApplication a(argc, argv);
    	Window w;
    	w.show();
    	return a.exec();
    }
    

    Window.h

    #ifndef DEF_WINDOW
    #define DEF_WINDOW
    
    #include "Constructor.h"
    
    #include <QWidget>
    #include <QVBoxLayout>
    #include <QPushButton>
    
    #include <vector>
    
    class Window : public QWidget
    {
    	Q_OBJECT
    
    public:
    	Window();
    
    public slots:
    	void addConstructor();
    	void destroyConstructor(Constructor*);
    
    private:
    	QVBoxLayout* mainLayout = new QVBoxLayout;
    	QVBoxLayout* constructorLayout = new QVBoxLayout;
    	std::vector<Constructor*>* constructorVector = new std::vector<Constructor*>;
    	QPushButton* addConstructorButton = new QPushButton("+", this);
    };
    
    #endif
    

    Window.cpp

    #include "Window.h"
    
    Window::Window() 
    {
    	connect(addConstructorButton, SIGNAL(clicked()), this, SLOT(addConstructor()));
    
    	mainLayout->addLayout(constructorLayout);
    	mainLayout->addWidget(addConstructorButton);
    	setLayout(mainLayout);
    }
    
    void Window::addConstructor() 
    {
    	Constructor* c = new Constructor(this);
    	constructorLayout->addWidget(c);
    	constructorVector->push_back(c);
    
    	connect(c, SIGNAL(mustBeDestroyed(Constructor*)), this, SLOT(destroyConstructor(Constructor*)));
    }
    
    void Window::destroyConstructor(Constructor* c) 
    {
    	constructorLayout->removeWidget(c);
    
    	//remove object from vector
    	for (int i = 0; i < constructorVector->size(); i++)
    		if (constructorVector->at(i) == c) {
    			constructorVector->erase(constructorVector->begin() + i);
    			break;
    		}
    }
    

    Constructor,h

    #ifndef DEF_CONSTRUCTOR
    #define DEF_CONSTRUCTOR
    
    #include <QWidget>
    #include <QLineEdit>
    #include <QHBoxLayout>
    #include <QPushButton>
    #include <QLayout>
    
    #include <vector>
    
    class Constructor : public QWidget
    {
    	Q_OBJECT
    
    public:
    	Constructor(QWidget* parentWidget);
    
    public slots:
    	void destroySelf();
    
    signals:
    	void mustBeDestroyed(Constructor*);
    
    private:
    	QLineEdit* lineEdit = new QLineEdit(this);
    	QPushButton* destroyConstructorButton = new QPushButton("-", this);
    };
    
    #endif
    

    Constructor.cpp

    #include "Constructor.h"
    
    Constructor::Constructor(QWidget* parentWidget) : QWidget(parentWidget)
    {
    	connect(destroyConstructorButton, SIGNAL(clicked()), this, SLOT(destroySelf()));
    
    	QHBoxLayout* layout = new QHBoxLayout;
    	layout->addWidget(lineEdit);
    	layout->addWidget(destroyConstructorButton);
    	setLayout(layout);
    }
    
    void Constructor::destroySelf()
    {
    	delete lineEdit;
    	delete destroyConstructorButton;
    
    	emit mustBeDestroyed(this);
    
    	this->disconnect();
    	delete this;
    }