QComboBox doesn't connect - c++

I'm programming in QT 4.8.4 with C++. I want to have a drop-down menu, where I can select an option, and then it will run an exe with the selected item on the menu as the option for the exe.
Here's my code:
#ifndef GUI_H
#define GUI_H
#include <QDialog>
#include <QtGui>
class QLabel;
class QLineEdit;
class QPushButton;
class gui : public QDialog
{
Q_OBJECT
public:
gui(QWidget *parent = 0);
public slots:
void gui::on_go_clicked();
private:
QLabel *label1;
QLabel *label2;
QLineEdit *lineEdit;
QPushButton *goButton;
QComboBox cb;
};
#endif
And the .cpp file:
#include <QtGui>
#include <QApplication>
#include <QComboBox>
#include "gui.h"
#include <vector>
gui::gui(QWidget *parent) : QDialog(parent)
{
label1 = new QLabel(tr("Insert Name (Optional):"));
label2 = new QLabel(tr("Class Name (Required):"));
lineEdit = new QLineEdit;
goButton = new QPushButton(tr("&Go"));
goButton->setDefault(true);
connect(goButton, SIGNAL(clicked()), this, SLOT(on_go_clicked()));
QComboBox *cb = new QComboBox();
cb->addItem("Hello", "1");
cb->addItem("Test", "2");
QHBoxLayout *hLayout1 = new QHBoxLayout;
hLayout1->addWidget(label1);
hLayout1->addWidget(lineEdit);
QHBoxLayout *hLayout2 = new QHBoxLayout;
hLayout2->addWidget(label2);
hLayout2->addWidget(cb);
QHBoxLayout *hLayout3 = new QHBoxLayout;
hLayout3->addWidget(goButton);
hLayout3->addStretch();
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addLayout(hLayout1);
vLayout->addLayout(hLayout2);
vLayout->addWidget(cb);
vLayout->addLayout(hLayout3);
setLayout(vLayout);
setWindowTitle(tr("TEST"));
setFixedHeight(sizeHint().height());
}
void gui::on_go_clicked()
{
QMessageBox::information(this, "ASDF", cb.currentText());
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
gui *stuff = new gui;
stuff->show();
return app.exec();
}
Right now I'm just trying to figure out how to use QComboBox, which isn't working. My code compiles, but when I run it I get "Object::connect: No such slot gui::on_go_clicked()"
I'm doing exactly what a tutorial says to do. I can't figure out why this isn't working.

Remove gui:: :
class gui : public QDialog{
Q_OBJECT
...
public slots:
void gui::on_go_clicked();
^^^^^
Remove it

I wonder why you code even compiles. No 'extra qualification on member on_go_clicked'.
Remove gui:: from on_go_clicked in your header.

You have two QComboBox objects that you reference.
The first is at the class level:
class gui : public QDialog{
Q_OBJECT
public:
gui(QWidget *parent = 0);
public slots:
void gui::on_go_clicked();
private:
QLabel *label1;
QLabel *label2;
QLineEdit *lineEdit;
QPushButton *goButton;
QComboBox cb; // <<<=== class-level automatic object
};
The second is a local pointer-to-QComboBox object that exists in the constructor
gui::gui(QWidget *parent) : QDialog(parent){
...
QComboBox *cb = new QComboBox(); // <<<=== function-level pointer using the same name
// as the class-level automatic object
To correct the problem, you can change the class-level object to be a pointer and then change the object creation to be a simple assignment instead of a declaration-and-initialisation.
cb = new QComboBox();
Also, once you've done this, you'll need to modify the slot so that the pointer dereference operator is used to access the text() function
void gui::on_go_clicked(){
QMessageBox::information(this, "ASDF", cb->currentText());
}

Related

Widget initialized later will not show in MainWindow

I am learning Qt using Qt 5.13 on MacOS.
First I define MyWidget inherited from QWidget. MyWidget has a QPushButton, but this button will be created in a slot function called 'fresh', not in constructor.
I add MyWidget in MainWindow (inherited from QMainWindow), and defined another button_2 to emit signal to callMyWidget's 'fresh' function to create button.
If I did not hide MyWidget in MainWindow first, MyWidget's button will not show. If I hide MyWidget first, everything seems OK.
I hope to know the reason. Thanks
I tried to repaint or update MyWidget in 'fresh' function, but did not help.
mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include<QPushButton>
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = nullptr);
~MyWidget();
public slots:
void fresh();
private:
QPushButton* myButton;
};
#endif // WIDGET_H
mywidget.cpp
#include "mywidget.h"
MyWidget::MyWidget(QWidget *parent) :
QWidget(parent)
{
}
MyWidget::~MyWidget()
{
}
void MyWidget::fresh()
{
myButton = new QPushButton(this);
myButton->setStyleSheet("QPushButton { background-color: green;}");
show();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include"mywidget.h"
#include<QHBoxLayout>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
signals:
public slots:
private:
MyWidget* myWidget;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QWidget* qwidget = new QWidget;
myWidget = new MyWidget(this);
QPushButton* button = new QPushButton("Show",this);
QHBoxLayout* mainLayout = new QHBoxLayout;
mainLayout->addWidget(myWidget);
mainLayout->addWidget(button);
qwidget->setLayout(mainLayout);
setCentralWidget(qwidget);
//myWidget->hide();
connect(button,&QPushButton::clicked,myWidget,&MyWidget::fresh);
}
main.cpp
#include "mywidget.h"
#include"mainwindow.h"
#include<QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
If I add myWidget->hide(); in mainwindow.cpp, it seems right.
If I remove it, the green button will not show, even if I repaint or update or show in fresh function.
'mywidget' is taking the whole space, if you want to know if it is taking all the space or not :
mywidget->setStyleSheet("* {border: 4px solid orange;}")
Since you are using a layout, you might want to determine the minimum size of a QPushButton. the QPushButton has a default horizontal size policy : "Minimum", by default. Maybe if you set the minimum width using this function : "setMinimumWidth(int width)", might fix your problem.
Also, don't forget to call this :
myButton->show();
Every object that inherits from QObject should be shown with this func ".show".
Here is all the flags for QSizePolicy will help you understand what is going on in layouts (layouts work a lot with QSizePlicy flags) : https://doc.qt.io/qt-5/qsizepolicy.html#Policy-enum .
Unless you don't want the layout, you have to specify the position and the size in this way :
mywidget->setGeometry(QPoint(x, y), QSize(width, height));
and the same thing for your buttons.

Qt5 custom QDialog without using qt creator

I am trying to write a custom pure C++ QDialog so that I can create a base class and inherit from it later. The follow is the code that shows a QLabel in a QDialog:
"EDLController.h"
#ifndef EDLController_h
#define EDLController_h
#include <QDialog>
class EDLController : public QDialog {
Q_OBJECT
public:
EDLController(QWidget *parent = nullptr);
};
#endif
"EDLController.cpp"
EDLController::EDLController(QWidget *parent) : QDialog(parent) {
QVBoxLayout vBoxLayout;
QLabel label("text");
vBoxLayout.addWidget(&label);
setLayout(&vBoxLayout);
setWindowTitle("test");
}
"main.cpp"
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
EDLController *w = new EDLController();
w->show();
return app.exec();
}
However, it shows an empty window with correct title:
image
The program is running on Raspberry Pi (Raspbian). Can anyone help me to find out the problem.
The problem is your label declaration. You create a local variable label wich is destroyed at the end of the EDLController constructor.
You can confirm that by inheriting QLabel like this :
class MyLabel : public QLabel
{
Q_OBJECT
public:
MyLabel(const QString& str, QWidget* parent = nullptr) : QLabel(str,parent){}
~MyLabel() {qDebug() << "LABEL DELETED";}
};
The "LABEL DELETED" message will be logged when the QDialog is instanced.
And, of course, you cannot display a deleted widget.
The correct code is the following :
QLabel* label = new QLabel("text");
vBoxLayout.addWidget(label);
The label will be destoyed when the parent item (your dialog) will be destroyed.
vBoxLayout and label will be destroyed when EDLController constructor exits because they are local variables. Create new instances on heap to avoid that:
EDLController::EDLController(QWidget *parent)
: QDialog(parent)
{
QVBoxLayout * vBoxLayout = new QVBoxLayout(this);
QLabel * label = new QLabel(this);
label->setText("test");
vBoxLayout->addWidget(label);
setLayout(vBoxLayout);
setWindowTitle("test");
}

Parent issue (?) while using derived Qt widget class

The following is the smallest example I could make to present the isuue.
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QVBoxLayout *vLayout = new QVBoxLayout(this);
QGroupBox *gb = new QGroupBox;
// MyGroupBox *gb = new MyGroupBox;
vLayout->addWidget(gb);
QPushButton *btB = new QPushButton;
vLayout->addWidget(btB);
}
The code above produces the image above, it's just a group box and a button in vertical layout.
If I replace QGropBox by MyGroupBox then it doesn't show there anymore. The code below produces the image below.
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QVBoxLayout *vLayout = new QVBoxLayout(this);
// QGroupBox *gb = new QGroupBox;
MyGroupBox *gb = new MyGroupBox;
vLayout->addWidget(gb);
QPushButton *btB = new QPushButton;
vLayout->addWidget(btB);
}
Where mygroupbox.h (the constructor body is empty in the .cpp file):
#include <QWidget>
class MyGroupBox : public QWidget
{
Q_OBJECT
public:
explicit MyGroupBox(QWidget *parent = 0);
signals:
public slots:
};
Why the group box isn't showing there? How to make it appear?
This is why it doesn't appear:
class MyGroupBox : public QWidget
Your "group box" is basically just a QWidget. Inherit from QGroupBox instead.
As an aside, a minimal example could look like the below. Not a single declaration/statement/expression can be removed. The button aids in visualizing the problem, so it should be left in. The use of a failure trigger variable highlights exactly what condition triggers the failure: the code self-documents and you almost need no narrative to explain it. The question could be as concise as the test case below and one sentence "Why is the group box's border not visible when fail is true?". Most likely, had you followed the minimization fully through, you'd realize yourself what the problem was - it becomes rather obvious. It's not so when MyGroupBox is declared in another file!
The technique of putting it all into a single main.cpp file is critical in spotting the problem: all of the code is physically next to each other, making it much easier to spot mistakes! When you minimize, usually the first things that have to go are separate files: cram it all into one file, and then relentlessly remove absolutely everything that's not directly needed in reproducing the issue.
#include <QtWidgets>
struct MyGroupBox : public QWidget {};
int main(int argc, char ** argv) {
bool fail = true;
QApplication app{argc, argv};
QWidget widget;
QVBoxLayout layout{&widget};
QGroupBox groupBox;
MyGroupBox myGroupBox;
QPushButton button;
layout.addWidget(fail ? static_cast<QWidget*>(&myGroupBox) : &groupBox);
layout.addWidget(&button);
widget.show();
return app.exec();
}
This concise style is not only for trivial test cases. In your real code, the Widget's header and implementation could look as follows:
// Widget.h
#include <QtWidgets>
#include "MyGroupBox.h"
class Widget : public QWidget {
Q_OBJECT
QVBoxLayout layout{this};
MyGroupBox groupBox;
QPushButton button{tr("Click Me!")};
public:
explicit Widget(QWidget * parent = nullptr);
};
// Widget.cpp
#include "Widget.h"
Widget::Widget(QWidget * parent) :
QWidget{parent} {
layout.addWidget(&groupBox);
layout.addWidget(&button);
}
If you insist on shielding the interface from implementation details, don't use pointers to widgets etc., use a PIMPL.
// Widget.h
#include <QWidget>
class WidgetPrivate;
class Widget : public QWidget {
Q_OBJECT
Q_DECLARE_PRIVATE(Widget)
QScopedPointer<WidgetPrivate> const d_ptr;
public:
explicit Widget(QWidget * parent = nullptr);
};
// Widget.cpp
#include "Widget.h" // should always come first!
#include "MyGroupBox.h"
class WidgetPrivate {
Q_DECLARE_PUBLIC(Widget)
Widget * const q_ptr;
public:
QVBoxLayout layout{q_func()};
QGroupBox groupBox;
MyGroupBox myGroupBox;
QPushButton button{"Click Me!"};
WidgetPrivate(Widget * q) : q_ptr(q) {
layout.addWidget(&groupBox);
layout.addWidget(&button);
}
};
Widget::Widget(QWidget * parent) :
QWidget{parent}, d_ptr{new WidgetPrivate{this}}
{}

QT: simple text from QLineEdit to QLabel of different class

I'm trying to write a very basic program. The main window contains a label. Pressing the "Add New" button opens a QDialog with a QLineEdit. Changing the text, press "Add" and I would like the QLabel in the main window to be updated with the text from QLineEdit. I can get the signals through but the label is not updating. I understand that connect only works on instances of classes, not classes themselves. The problem seems to be the one class is not aware of the instance of the main window.
What I've tried to do is once the Add button is pressed, a signal is emitted. Once that signal is emitted, the slot in the mainWindow class receives a string to use in QLabel::setText().
I've read countless examples and documentation but the examples seem to be too different from the simple task I'm lost in. Any help is appreciated.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtWidgets>
#include <QLabel>
class QLineEdit;
class QPushButton;
class QLabel;
class addDlg : public QDialog{
Q_OBJECT
public:
addDlg(QWidget *parent = 0);
signals:
void textChanged(const QString &text);
private slots:
void sendText(QWidget *parent);
private:
QPushButton *addButton;
QLineEdit *inputText;
};
class mainWindow : public QWidget{
Q_OBJECT
public:
mainWindow();
QLabel *textLabel;
public slots:
void recvText(const QString &text);
private slots:
void addDlgShow();
private:
QPushButton *addWindow;
addDlg *dialog;
};
#endif // MAINWINDOW_H
MainWindow.cpp
addDlg::addDlg(QWidget *parent)
: QDialog(parent){
inputText = new QLineEdit(tr("enter here"));
addButton = new QPushButton(tr("Accept"));
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(inputText);
vLayout->addWidget(addButton);
setLayout(vLayout);
setWindowTitle(tr("Add new text"));
connect(addButton, SIGNAL(clicked()),
this, SLOT(sendText()));
}
void addDlg::sendText(){
QString text = inputText->text();
emit textChanged(text);
// This connect is where I believe the problem lies.
connect(this, SIGNAL(textChanged(QString)),
mainPtr, SLOT(recvText(QString)));
//mainPtr is uninitialized as I can't seem to point it to the manWindow instance
//I can do mainWindow* mainPtr = new mainWindow but that just creates a new instance.
//How do I pass on the first mainWindow main instance "mainPtr" to this class addDlg?
}
mainWindow::mainWindow()
: QWidget(0){
textLabel = new QLabel(tr("Empty"));
addWindow = new QPushButton(tr("Add New"));
dialog = new addDlg();
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(textLabel);
vLayout->addWidget(addWindow);
setLayout(vLayout);
setWindowTitle(tr("Test 4"));
connect(addWindow, SIGNAL(clicked()),
this, SLOT(addDlgShow()));
}
void mainWindow::addDlgShow(){ dialog->show(); }
void mainWindow::recvText(const QString &text){
QString input = text;
textLabel->clear();
textLabel->setText(input);
textLabel->update();
}
One solution is to put your connect code in mainWindow::mainWindow where you have pointers to both the mainwindow and your newly created dialog. The snippet might change to this:
mainWindow::mainWindow() : QWidget(0) {
// ... existing code ..
// add this
connect(dialog, SIGNAL(textChanged(QString)),
this, SLOT(recvText(QString)));
}

Some Problems with Qt (C++)

main.cpp
#include <QtGui>
#include <QApplication>
int main(int argv, char **args)
{
QApplication app(argv, args);
QTextEdit textEdit;
QPushButton quitButton("Quit");
QObject::connect(&quitButton, SIGNAL(clicked()), qApp, SLOT(quit()));
QVBoxLayout layout;
layout.addWidget(&textEdit);
layout.addWidget(&quitButton);
QWidget window;
window.setLayout(&layout);
window.show();
return app.exec();
}
notepad.cpp
#include <QtGui>
#include <QApplication>
class Notepad : public QMainWindow
{
Notepad::Notepad()
{
saveAction = new QAction(tr("&Open"), this);
saveAction = new QAction(tr("&Save"), this);
exitAction = new QAction(tr("E&xit"), this);
connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openAction);
fileMenu->addAction(saveAction);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
textEdit = new QTextEdit;
setCentralWidget(textEdit);
setWindowTitle(tr("Notepad"));
}
Q_OBJECT
public:
Notepad();
private slots:
void open();
void save();
void quit();
private:
QTextEdit *textEdit;
QAction *openAction;
QAction *saveAction;
QAction *exitAction;
QMenu *fileMenu;
};
ERRORS:
extra qualification 'NotePad::' on Member Notepad (Line 8)
notepad::notepad() cannot be overloaded (Line 32)
with notepad::notepad (line 8)
Why am I getting these errors? The constructor looks fine and the class setup looks fine. But I am getting these errors.
The Notepad:: in front of your Notepad() constructor inside the Notepad class is not necessary. Neither is the later declaration, because you have done this and defined it (although privately) above. You might want to consider separating it into a header and cpp file.
There are still various other issues with the code as you have posted, but the errors you posted are most likely caused by what I mentioned above.
You have qualified the inline private constructor with Notepad::
You have then incorrectly overloaded that private constructor as public in a second declaration
Q_OBJECT macro needs to be first in the class declaration before methods and members.
You have at least 4 memory leaks for each instance of Notepad?
etc
Perhaps pick up a book?