Qt/C++ widget inside widget does not appear - c++

I am writing Qt/C++ project and I created my mainwindow.ui in QtDesigner. I placed in mainwindow.ui an empty widget which later I want to extend by putting there my widget written in code. This is my code:
class which extends QWidget
#pragma once
#include <QtGui>
#include <QWidget>
using namespace QtDataVisualization;
class GraphDataCreator : public QWidget
{
Q_OBJECT
public:
GraphDataCreator(QWidget* parent = 0);
~GraphDataCreator();
};
cpp of this class:
#include "GraphDataCreator.h"
GraphDataCreator::GraphDataCreator(QWidget* parent)
: QWidget(parent)
{
this->setStyleSheet("background-color:green;");
}
and the mainwindow class:
#pragma once
#include <QMainWindow>
#include "ui_MainWindow.h"
#include "GraphDataCreator.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QMainWindow*parent = Q_NULLPTR);
~MainWindow();
private:
Ui::MainWindow ui;
};
cpp of main window class
#include "MainWindow.h"
#include <string>
#include <QtGui>
#include "GraphDataCreator.h"
MainWindow::MainWindow(QMainWindow*parent)
: QMainWindow(parent)
{
ui.setupUi(this);
QGridLayout* layout = new QGridLayout(ui.Chart3DWidget);
GraphDataCreator* chart3D = new GraphDataCreator(ui.Chart3DWidget);
layout->addWidget(chart3D);
QWidget* test_widget = new QWidget;
test_widget->setStyleSheet("background-color: red;");
layout->addWidget(test_widget);
ui.Chart3DWidget->setLayout(layout);
}
I wanted to be the whole widget in ui green, but it didn't appear so I put there test_widget with red background and the result is that it is half nothing/half red. So the green widget excists there but it is not visible. And my question is why the green part is not visible??? And how to solve it?
Of course names of classes are weird because I tried to do something else and this explanation simplifies that problem.
EDIT:
thx #sajas for help! Actually I used that link Why do stylesheets not work when subclassing QWidget and using Q_OBJECT? and I used case 2 written there so I deleted Q_OBJECT macro in GraphDataCreator class and it worked without any other changes. The function for background color of widget I left the same and everything else. The result is as expected half green / half red. Anyway I think I should include macro Q_Object as written in link over there because it is a Qt class, but it does work without. Maybe there is a small bug in Qt??? To sum up if you delete Q_Object macro it works.

Related

Qt connect signals and slots of different windows/ mirror a lineEdit text on two windows

I'm new to any form of programming but have to do a project with Qt for my "programming for engineers" course where we simultaneously learn the basics of c++.
I have to display a text from one lineEdit to a lineEdit in another window.
I have a userWindow that opens from the mainWindow and in this userWindow I have a lineEdit widget that displays the current selected user as a QString (from a QDir object with .dirName() ). But now I have to display the same String in a lineEdit in the mainWindow as well.
From what I've read I have to do this with "connect(...)" which I have done before with widgets inside a single .cpp file but now I need to connect a ui object and signal from one window to another and I'm struggling.
My idea /what I could find in the internet was this:
userWindow.cpp
#include "userwindow.h"
#include "ui_userwindow.h"
#include "mainwindow.h"
#include <QDir>
#include <QMessageBox>
#include <QFileDialog>
#include <QFileInfo>
QDir workingUser; //this is the current selected user. I tried defining it in userWindow.h but that wouldn't work how I needed it to but that's a different issue
userWindow::userWindow(QWidget *parent) : //konstruktor
QDialog(parent),
ui(new Ui::userWindow)
{
ui->setupUi(this);
QObject::connect(ui->outLineEdit, SIGNAL(textChanged()), mainWindow, SLOT(changeText(workingUser) //I get the error " 'mainWIndow' does not refer to a value "
}
[...]
mainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDir>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void changeText(QDir user); //this is the declaration of my custom SLOT (so the relevant bit)
private slots:
void on_userButton_clicked();
void on_settingsButton_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "userwindow.h"
#include "settingswindow.h"
#include "click_test_target.h"
#include "random_number_generator.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
[...]
}
[...]
//here I define the slot
void MainWindow::changeText(QDir user)
{
QString current = user.dirName();
ui->userLine->insert("The current working directory is: "); //"userLine" is the lineEdit I want to write the text to
ui->userLine->insert(current);
}
I know I'm doing something wrong with the object for the SLOT but can't figure out how to do it correctly.
If anyone could help me I would be very grateful.
Alternatively: perhaps there is another way to mirror the text from one lineEdit to another over multiple windows. If anybody could share a way to do this I would be equally grateful. Is there maybe a way to somehow define the variable "QDir workingUser;" in such a way as to be able to access and overwrite it in all of my .cpp files?
Thank you in advance for any help. Regards,
Alexander M.
"I get the error 'mainWindow' does not refer to a value"
I don't see you having any "mainWindow" named variable anywhere,
but you also mentioned that the MainWindow is the parent, which means you could get reference anytime, like:
MainWindow *mainWindow = qobject_cast<MainWindow *>(this->parent());
Also, your signal-handler (changeText(...) slot) should take QString as parameter (instead of QDir), this way you handle how exactly the conversion is handled, in case users type some random text in input-field (text-edit).
void changeText(const QString &input);
Finally, you either need to specify type:
QObject::connect(ui->outLineEdit, SIGNAL(textChanged(QString)), mainWindow, SLOT(changeText(QString));
Or, use the new Qt-5 syntax:
connect(ui->outLineEdit, &QLineEdit::textChanged,
mainWindow, &MainWindow::changeText);
You can create new signal (same params as lineEdit's textChanged) to userWindow which is connected to the textChanged signal of the lineEdit. Then connect that signal userWindow to mainWindow's slot.
//In userWindow.h
signals:
void textChanged(const QString&);
//In userWindow.cpp
connect(ui.lineEdit, &QLineEdit::textChanged, this, &userWindow::textChanged);
//In mainWindow.cpp
connect(userWindow, &userWindow::textChanged, this, &mainWindow::onTextChanged
Then in onTextChanged write the same text to mainWindow's lineEdit

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);
}

Initializing a Ui pointer From a QMainWindow class to a QDialog Class

I'm really stuck on one problem that I want to solve. the problem is that I have a Class for QMainWindow which holds the Ui variable for that form. Now I want to be able to edit that Form using the Ui variable in that class on a QDialog cpp file. I probably sound really stupid and I really have no idea how I should explain this, but I have code which maybe can help.
MainWindow.h:
#include "ui_mainwindow.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
Ui::MainWindow *ui;
}
MainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "dialog.h"
Dialog *dialog;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
dialog->show();
}
QDialog.cpp:
#include "ui_mainwindow.h"
#include "mainwindow.h"
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
Ui::MainWindow *mainui;
void Dialog::on_pushbutton_clicked(){
mainui->label->setText("test");
}
So as you can see from the above code, it shows that I have a pointer to the Ui variable however its uninitialised, therefore it would lead to a SIGSEGV error, so how to do Initialize this pointer? any help here is highly appreciated, and even though this is probably really simple I just don't know what to do. (I have looked at other questions but I couldn't quite grasp what to do, so please explain what I am to do before linking me to a similar question. Also, I have left out the Dialog.h file as I didn't think it was needed, please tell me if I need to show it, thanks!).
Generally in C++ you should practice what is called encapsulation - keep data inside a class hidden from others that don't need to know about it. It's not good to have multiple pointers to the UI object as now all those other objects have to know how the main window UI is implemented.
In this case, what I would recommend is to use Qt's signals and slots mechanism to allow the dialog to tell the main window what you need it to do. That has the advantage that if you add more dialogs, or change how things are implemented in the main window, you don't need to alter the signal slot mechanism, and the details are hidden cleanly.
So - for your dialog, add a signal like this in the header file
class Dialog : QDialog
{
Q_OBJECT
signals:
void setTextSignal(QString text);
}
and in your main window header, add a slot.
class MainWindow : public QMainWindow
{
Q_OBJECT
public slots:
void setTextSlot(const QString &text);
}
now in your method where the button is pressed,
void Dialog::on_pushbutton_clicked()
{
emit setTextSignal("test");
}
and in your main window
void MainWindow::setTextSlot(const QString &text)
{
mainUi->label->setText(text);
}
The final part is to connect the signal and slot together, which you would do in your main window function where you create the dialog:
void MainWindow::on_pushButton_clicked()
{
dialog = new Dialog(this);
connect(dialog, SIGNAL(setTextSignal(QString)), this, SLOT(setTextSlot(QString)));
dialog->show();
}
You can see there are many advantages to this; the Dialog no longer needs a pointer to the main window UI, and it makes your code much more flexible (you can have other objects connected to the signals and slots as well).
Short answere - your can't! If you want to create a new instance of the ui, you would have to do:
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(this);
However, the this-pointer for a UI created for a QMainWindow based class must inherit QMainWindow - thus, you can't.
In general, it is possible if you create your Ui based on a QWidget instead of a QMainWindow, since both inherit QWidget.
Alternativly, you could try the following:
QMainWindow *subWindow = new QMainWindow(this);
subWindow->setWindowFlags(Qt::Widget);
MainWindow::Ui *ui = new MainWindow::UI();
ui->setupUi(subWindow );
//... add the mainwindow as a widget to some layout
But I would guess the result will look weird and may not even work in the first place.

Hiding/Showing DockWidgets in Qt 5 in Designer

I'm developing an application with Qt, a framework with which I'm not at all familiar, and I'm attempting to hide and show a DockWidget that I created using designer.
Unlike many of the seemingly similar questions about hiding and showing dockwidgets in Qt is that I made my widget entirely with Qt Designer, so I don't know how to link much of the code I've found in these questions' answers. Essentially, I have no mention of a dockwidget in my *.cpp files, but I do in my .ui file.
How can I incorporate this Designer-created dockwidget into my code to make it visible and invisible?
Sorry for such a nooby question.
Thanks,
erip
Wenn you build your application, qmake generates h from your ui files. So for instance ui_dlg_about.ui is translated into a ui_dlg_about.h automatically. Usually in a folder calles GeneratedFiles or something like that. You can then create an acutal customisable dialog class which you use in your application by creating something along the following:
dlg_about.h
#include "ui_dlg_about.h"
#include <QDialog>
class dlg_about : public QDialog, protected Ui::ui_dlg_about
{
Q_OBJECT
public:
dlg_about(QWidget* = 0);
public slots:
void toggle_dockwidget();
};
dlg_about.cpp
#include "dlg_about.h"
dlg_about::dlg_about(QWidget* parent) : QDialog(parent)
{
setupUi(this);
QObject::connect(this->somebutton, SIGNAL(clicked()), this, SLOT(toggle_dockwidget()));
}
void dlg_about::toggle_dockwidget()
{
if(something){
this->dockwidget->setVisible(true);
}else{
this->dockwidget->setVisible(false);
}
}
It is also possible for your dialog to not be derived from ui_dlg_about but having it as a member:
dlg_about.h
#include "ui_dlg_about.h"
#include <QDialog>
class dlg_about : public QDialog
{
Q_OBJECT
public:
dlg_about(QWidget* = 0);
public slots:
void toggle_dockwidget();
protected:
Ui::ui_dlg_about ui;
};
dlg_about.cpp
#include "dlg_about.h"
dlg_about::dlg_about(QWidget* parent) : QDialog(parent)
{
setupUi(this->ui);
QObject::connect(this->ui.somebutton, SIGNAL(clicked()), this, SLOT(toggle_dockwidget()));
}
....

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.