Edit: I removed the destructor from the slot. But now I have memory leaking problems. Each new window that I open occupies some memory,and when I close it,the memory stays occupied
When I execute the program,and open new windows, they are opened normally. When I close any of them, the whole application crashes (not only that specific window),and I get the crash error.
What am I doing wrong?
mainWindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QHBoxLayout;
class QTextEdit;
class QWidget;
class QDialog;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void closeWindow();
void newWindow();
private:
Ui::MainWindow *ui;
MainWindow *tempMainWindow;
QHBoxLayout * mainLyt;
QTextEdit *txtEdit;
QWidget *mainWidget;
};
#endif // MAINWINDOW_H
mainWindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QWidget>
#include <QHBoxLayout>
#include <QTextEdit>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
mainWidget=new QWidget();
mainLyt=new QHBoxLayout();
txtEdit=new QTextEdit();
mainLyt->addWidget(txtEdit);
mainWidget->setLayout(mainLyt);
setCentralWidget(mainWidget);
connect(ui->actionExit,SIGNAL(triggered()),this,SLOT(closeWindow()));
connect(ui->actionNew,SIGNAL(triggered()),this,SLOT(newWindow()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::closeWindow()
{
this->close();
delete txtEdit;
delete mainLyt;
delete mainWidget;
this->~MainWindow();
}
void MainWindow::newWindow()
{
tempMainWindow=new MainWindow(this);
tempMainWindow->show();
}
If you pass to QWidget(), QHBoxLayout() and QTextEdit() also this (which is the parent), at the delection of the MainWindow Qt will delete for you the ui and all the additional widgets yur defined in the construstor. In this way you can avoid to call closeWindow() method.
delete ui is also not necessary.
ui->setupUi(this);
mainWidget = new QWidget(this);
mainLyt = new QHBoxLayout(this);
txtEdit = new QTextEdit(this);
I'm trying to make basic text editor,and when New is triggered, it should open a new window for new text document. Is there some better way to do this?
Yes. It's called a factory, and it can be a static method as it doesn't operate on any object. You can call it from a slot, of course.
I imagine you'll need to pass a file name to the newly created window - that could be an argument to the factory method and the factory slot. If the "new" window is empty, then this is not an issue.
Other issues:
There is no reason to keep the mainWidget member: it is always available as centralWidget().
There's also no reason to have the members other than ui as pointers. It is actually a premature pessimization - it will waste a bit more heap memory.
You don't need a layout for the central widget if it has no child widgets. The QTextEdit instance itself can be the central widget.
The ui instance should be retained using a smart pointer. This makes the destructor completely compiler-generated (it has an empty body).
You don't need anything fancy in the closeWindow slot. Simply delete the instance!
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow * createWindow();
void setFileName(const QString & fileName);
public slots:
void closeWindow();
void newWindow();
private:
QScopedPointer<Ui::MainWindow> const ui;
QTextEdit m_txtEdit;
};
void MainWindow::newWindow() {
createWindow()->show();
}
void MainWindow::closeWindow() {
deleteLater();
}
MainWindow * MainWindow::createWindow(QWidget * parent) {
return new MainWindow(parent);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setCentralWidget(&m_txtEdit);
connect(ui->actionExit, SIGNAL(triggered()), SLOT(closeWindow()));
connect(ui->actionNew, SIGNAL(triggered()), SLOT(newWindow()));
}
MainWindow::~MainWindow()
{}
Let us see your code:
this->close();
delete txtEdit;
delete mainLyt;
delete mainWidget;
this->~MainWindow();
You are trying to destroy them and for the next open you allocate them almost the same way.
What you achieve here is basically performance penalty. I would suggest to hide, modify, and so on the unwanted items instead.
Related
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.
I have a parent-child window in my Qt application. Parent class is a QDialog named A and child class is QMainWindow named B. Now I want that whenever B is closed through the 'X' button a signal is to be emitted which can be caught by a slot in class A through which I want certain functionality to be implemented. Is there a predefined signal in Qt I can use?
I want something like this:
B *b=new B;
//some code
connect(b,SIGNAL(destroyed()),this,&A::doSomething);
B also has a QWidget which I can use to detect the destroyed signal. How do I implement this? Do I need to emit a custom signal from ~B() ?
Edit: I don't want to destroy the object b as this would require a reallocation when I want to recreate the window B from A and I want to keep the parameters of b.
Your solution would only work if you set a Qt::WA_DeleteOnClose attribute to your B widget:
b->setAttribute(Qt::WA_DeleteOnClose);
Another option would be to reimplement close event and emit a custom signal there.
Connect your object like this:
widget = new QWidget();
//widget->show(); //optional using
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
.cpp :
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButtonNew_clicked()
{
widget = new QWidget();
widget->show();
connect(widget, &QWidget::destroyed, this, &MainWindow::widgetDestroy);
widget->setAttribute(Qt::WA_DeleteOnClose);
}
void MainWindow::on_pushButtonDel_clicked()
{
delete widget;
}
void MainWindow::widgetDestroy()
{
qDebug()<< "deleted."; //after destroy widget this function calling.
}
.h :
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QWidget>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void widgetDestroy();
void on_pushButtonNew_clicked();
void on_pushButtonDel_clicked();
private:
Ui::MainWindow *ui;
QWidget *widget;
};
#endif // MAINWINDOW_H
.ui :
I have created my own QGraphicsView so I can use the mousePressEvent method. I then add the "new" widget to the MainWindow. Now I need to access a scene from that object, but I have trouble accessing it.
privqgraphicsview.cpp
#include "privqgraphicsview.h"
#include <QPointF>
MyQGraphicsView::MyQGraphicsView(QWidget *parent) :
QGraphicsView(parent)
{
scene = new QGraphicsScene();
this->setSceneRect(-320, -290, 660, 580);
this->setScene(scene);
this->setRenderHint(QPainter::Antialiasing);
}
privqgraphicsview.h
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsEllipseItem>
#include <QMouseEvent>
class MyQGraphicsView : public QGraphicsView
{
Q_OBJECT
public:
explicit MyQGraphicsView(QWidget *parent = 0);
QGraphicsScene * scene;
public slots:
void mousePressEvent(QMouseEvent * e);
};
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "privqgraphicsview.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// gridLayout is defined in mainwindow.h
gridLayout = new QGridLayout(ui->centralWidget);
gridLayout->addWidget( new MyQGraphicsView() );
}
MainWindow::~MainWindow()
{
delete ui;
}
Now, I have the button in MainWindow on which click event I would like to connect points which are in MyQGraphicsView's scene from gridLayout. I have tried something like this:
void MainWindow::on_connectPointsPB_clicked()
{
QLayoutItem *myView = gridLayout->itemAt(0);
// trying to draw a simple line, code below does not check anything, I am aware of it
dynamic_cast<MyQGraphicsView *>(myView)->scene->addLine(10,10,50,50, QPen(Qt::red, 3));
}
And that does shutdown (crash) the app after the button is clicked.
You should not cast QLayoutItem, but QLayoutItem::widget to your MyQGraphicsView. If you checked the outcome of dynamic_cast<MyQGraphicsView *>(myView), you would have noticed that it returns NULL. Note that it may be useful to use qobject_cast instead of dynamic_cast, which does not require RTTI support.
A cleaner solution would be to store your MyQGraphicsView object as a member of MainWindow, so you do not need to cast anything.
While doing some threading tutorials I got carried away and decided to make a gui which will show me the effect of multiple threads writing to one variable and using mutex.
The app uses mainwindow.ui menu to create a new instance of the threaddialog class every time which then runs it's own thread, displaying it's count loop on labels. Before I get onto doing the loop and having a mutex 'toggle', I am trying to connect the count update between the mainwindow and threaddialog so mainwindow can show the global count updating.
I can't get the connect() right, I am trying to pass it a pointer to the new threaddialog I just made before it, as that will be signalling the count, and the signal itself. Then for slot I use the this pointer to send the address of MainWindow, as that is where the slot is located, and the slot name itself.
As it stands, the connect() line gives me this error for both signal and slot parameters.
C:\Users\btank\Documents\Qt Projects\QThreadClasses\mainwindow.cpp:46: error: C3867: 'ThreadDialog::gCountUpdate': non-standard syntax; use '&' to create a pointer to member
I have read the whole page on Qt signals and slots official docs to try and understand what I'm doing wrong but no luck and need help. I don't believe I'm doing anything wrong regarding sending those pointers to connect().
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGridLayout>
#include <threaddialog.h>
#include <QLinkedList>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
QGridLayout *layout = new QGridLayout();
void NewThread();
~MainWindow();
private slots:
void on_actionNew_Thread_triggered();
void on_actionDelete_Thread_triggered();
public slots:
void setGCount(int gCount);
private:
QLinkedList<ThreadDialog *> list;
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <threaddialog.h>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//Clear memory list before using
list.clear();
qDebug() << list.count();
// Set layout in widget
QWidget *window = new QWidget();
window->setLayout(layout);
// Add widget to main window central widget
setCentralWidget(window);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionNew_Thread_triggered()
{
NewThread();
}
void MainWindow::NewThread()
{
ThreadDialog *newThread = new ThreadDialog(list.count());
qDebug() << list.count();
connect(newThread, newThread->gCountUpdate, this, this->setGCount);
newThread->run();
list << newThread;
layout->addWidget(newThread);
}
void MainWindow::on_actionDelete_Thread_triggered()
{
layout->removeWidget(list.last());
delete list.last();
list.removeLast();
qDebug() << list.count();
}
void MainWindow::setGCount(int gcount)
{
ui->lblGCount->setText(QString::number(gcount));
}
threaddialog.h
#ifndef THREADDIALOG_H
#define THREADDIALOG_H
#include <QDialog>
#include <QThread>
namespace Ui {
class ThreadDialog;
}
class ThreadDialog : public QDialog
{
Q_OBJECT
public:
explicit ThreadDialog(int count, QWidget *parent = 0);
void run();
~ThreadDialog();
signals:
void gCountUpdate(int uCount);
private:
Ui::ThreadDialog *ui;
};
#endif // THREADDIALOG_H
threaddialog.cpp
#include "threaddialog.h"
#include "ui_threaddialog.h"
#include "mainwindow.h"
ThreadDialog::ThreadDialog(int count, QWidget *parent) :
QDialog(parent),
ui(new Ui::ThreadDialog)
{
ui->setupUi(this);
// Setup UI
ui->lblTCount->setText(QString("Thread %1").arg(count));
}
ThreadDialog::~ThreadDialog()
{
delete ui;
}
void ThreadDialog::run()
{
for(int i = 0; i < 100; i++)
{
qDebug() << (QString("Thread loop %1").arg(i));
ui->lblTNum->setText(QString("Thread %1").arg(i));
emit this->gCountUpdate(i);
QThread::sleep(100);
}
}
This is how it should look like:
connect(newThread, &ThreadDialog::gCountUpdate
this, &MainWindow::setGCount);
You need to get a pointer to the method, not call the method.
Hello I am trying to add items to a QListWidget from a QPushButton. Both the QListWidget and QPushButton are added as individual widgets inside of a QGraphicsScene. I want the effect of a box that fills with text lines
main.c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QGraphicsView view;
QGraphicsScene *scene = new QGraphicsScene(0, 0, 1200, 1200, &view);
scene->setBackgroundBrush(Qt::gray);
view.setScene(scene);
QPushButton *PushButton1;
PushButton1 = new QPushButton();
PushButton1->setGeometry(QRect(19, 20, 154, 4));
QListWidget *ListWidget;
ListWidget = new QListWidget;
scene->addWidget(ListWidget);
scene->addWidget(PushButton1);
QObject::connect(PushButton1, SIGNAL(clicked()),&w, SLOT(handleClick(*QListWidget)));
view.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::handleClick(QListWidget *List)
{
int test;
List->addItem("TESTING");
//QApplication::quit();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QListWidget>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
public slots:
void handleClick(QListWidget *List);
};
#endif // MAINWINDOW_H
This code compiles fine. How I get the following error in the console when the application is running
QObject::connect: No such slot MainWindow::handleClick(*ListWidget) in ..\MenuTest\main.cpp:48
Can someone help me do this? I've seen several tutorials but it's using the designer to make the GUI and I'd like to know how to do it in code without using designer. Thanks.
Your slot accepts QListWidget but you're connecting with ListWidget as the parameter, the signature has to be an exact match due to the way signals and slots work in Qt.
Put handleClick under public slots: and change this line:
QObject::connect(PushButton1, SIGNAL(clicked()),&w, SLOT(handleClick(*ListWidget)));
To this:
QObject::connect(PushButton1, SIGNAL(clicked()),&w, SLOT(handleClick(*QListWidget)));
Update:
I see I missed a key point, the signatures have to match, as in parameter to parameter, so the line up there will not work.
To fix this remove the parameter completely, since PushButton1 can't send it automatically.
QObject::connect(PushButton1, SIGNAL(clicked()),&w, SLOT(handleClick()));
Also remove it here:
void MainWindow::handleClick()
To access the QListWidget you'll have to reference it directly, either by passing it to MainWindow's constructor or iterating the window's controls.