I have a Qt GUI application that opens a dialog when I go to Help > About. However, if I go to Help > About again, another dialog pops up. I'm trying to get it so that the already opened About dialog is the only one that can be open (i.e. no additional About dialogs allowed). I feel like this should be simple, but I keep getting a Segmentation Fault. Here's my code:
myApp.h
#ifndef MYAPP_H
#define MYAPP_H
#include <QMainWindow>
#include "about.h"
namespace Ui {
class MyApp;
}
class MyApp : public QMainWindow // inherit all public parts of QMainWindow
{
Q_OBJECT
public:
explicit MyApp(QWidget* parent = 0);
~MyApp();
private slots:
void on_actionAbout_triggered();
private:
Ui::MyApp* ui;
About* aboutDialog;
};
#endif // MYAPP_H
MyApp.cpp
#include "MyApp.h"
#include "ui_MyApp.h"
#include "about.h"
MyApp::MyApp(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MyApp)
{
ui->setupUi(this);
}
MyApp::~MyApp()
{
delete ui;
}
void MyApp::on_actionAbout_triggered()
{
if (!aboutDialog) {
aboutDialog = new About(this); // create new window
}
aboutDialog->show();
aboutDialog->activateWindow();
}
about.h
#ifndef ABOUT_H
#define ABOUT_H
#include <QDialog>
namespace Ui {
class About;
}
class About : public QDialog
{
Q_OBJECT
public:
explicit About(QWidget* parent = 0);
~About();
private:
Ui::About* ui;
};
#endif // ABOUT_H
about.cpp
#include "about.h"
#include "ui_about.h"
About::About(QWidget* parent) :
QDialog(parent),
ui(new Ui::About)
{
ui->setupUi(this);
}
About::~About()
{
delete ui;
}
In MyApp.cpp, when I get rid of the if, it works. But clicking Help > About (actionAbout_triggered) multiple times will open a bunch of About windows. I just want 1. So I figured I'd put in an if statement that says, if the About dialog is already open, don't create another one and just make it the active window instead. I'm met with a Segmentation Fault. I know this means it's trying to access memory somewhere that it shouldn't be, but I don't know why.
Any help would be greatly appreciated.
The normal way of doing this is to have a modal dialog box for your About window. Something like this
void MyApp::on_actionAbout_triggered()
{
About dlg(this);
dlg.exec();
}
Regarding your question specifically, the problem is you did not initialize aboutDialog to anything in the MyApp constructor, so it is "undefined value" - probably not null.
Set aboutDialog to null in your MyApp constructor to solve your segfaults.
Related
Create a simple application in Qt (c ++) to encrypt a text. And I get the error: "Cannot create children for a parent that is in a different thread."
I used threads to update a text edit box in real time while entering text.
I saw other similar topics, but I did not find any solution that I could adapt to myself.
Can you please suggest me how I can solve it?
.h file
#ifndef GENERATORSHACODE_H
#define GENERATORSHACODE_H
#include <QMainWindow>
#include <thread>
QT_BEGIN_NAMESPACE
namespace Ui { class GeneratorShaCode; }
QT_END_NAMESPACE
class GeneratorShaCode : public QMainWindow
{
Q_OBJECT
public:
GeneratorShaCode(QWidget *parent = nullptr);
~GeneratorShaCode();
QString Sha512Generator(QString);
void updateOutputEditText();
std::thread GenerateCode;
private:
Ui::GeneratorShaCode *ui;
};
#endif // GENERATORSHACODE_H
.cpp file
#include "generatorshacode.h"
#include "ui_generatorshacode.h"
#include <windows.h>
#include "sha512.h"
#include <string>
#include <QtDebug>
GeneratorShaCode::GeneratorShaCode(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::GeneratorShaCode)
{
ui->setupUi(this);
GenerateCode = std::thread(&GeneratorShaCode::updateOutputEditText, this);
GenerateCode.detach();
}
GeneratorShaCode::~GeneratorShaCode()
{
delete ui;
}
QString GeneratorShaCode::Sha512Generator(QString Qstr)
{
return QString::fromStdString(sha512(Qstr.toStdString()));
}
void GeneratorShaCode::updateOutputEditText()
{
while(true)
{
ui->textEdit_Output->setText(Sha512Generator(ui->textEdit_Input->toPlainText()));
}
}
GUI thread is the main thread. You can't operate any ui controls directly within a sub thread. Usually you should use signals/slots between GUI thread and sub thread.
I have a QT application and I'm trying to have a button in one of my windows open another window.
The way I have done my window objects so far in the main is like this:
Website control;
control.show();
This displays my first window fine and if I declare my other window in a similar way that also displays at runtime, although this is not what I want
Then in a separate header file:
class Website: public QWidget, public Ui::Website
{
public:
Website();
}
Then in the corresponding Cpp file I have:
Website::Website()
{
setupUi(this);
}
Now all this works and have added a custom slot so that when I click a button it triggers a slot in my other cpp file. The issue is I'm not sure how to show my other window as I declare them in my main so can't access them to do .show()?
Any help would be appreciated, I'm fairly new to C++ and QT
It's not clear to me what you want to do. But i might understand your struggle as I had one myself the first time approaching this framework.
So let's say you have a MainWindow class that controls the main Window view. Than you want to create a second window controlled by Website class.
You then want to connect the two classes so that when you click a button on the Website window something happens in the MainWindow.
I made a simple example for you that is also on GitHub:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "website.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void changeText();
private slots:
void on_openButton_clicked();
private:
Ui::MainWindow *ui;
//You want to keep a pointer to a new Website window
Website* webWindow;
};
#endif // MAINWINDOW_H
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::changeText()
{
ui->text->setText("New Text");
delete webWindow;
}
void MainWindow::on_openButton_clicked()
{
webWindow = new Website();
QObject::connect(webWindow, SIGNAL(buttonPressed()), this, SLOT(changeText()));
webWindow->show();
}
website.h
#ifndef WEBSITE_H
#define WEBSITE_H
#include <QDialog>
namespace Ui {
class Website;
}
class Website : public QDialog
{
Q_OBJECT
public:
explicit Website(QWidget *parent = 0);
~Website();
signals:
void buttonPressed();
private slots:
void on_changeButton_clicked();
private:
Ui::Website *ui;
};
#endif // WEBSITE_H
website.cpp
#include "website.h"
#include "ui_website.h"
Website::Website(QWidget *parent) :
QDialog(parent),
ui(new Ui::Website)
{
ui->setupUi(this);
}
Website::~Website()
{
delete ui;
}
void Website::on_changeButton_clicked()
{
emit buttonPressed();
}
Project composed:
SOURCES += main.cpp\
mainwindow.cpp \
website.cpp
HEADERS += mainwindow.h \
website.h
FORMS += mainwindow.ui \
website.ui
Consider the Uis to be composed:
Main Window: a label called "text" and a button called "openButton"
Website Window: a button called "changeButton"
So the keypoints are the connections between signals and slots and the management of windows pointers or references.
I have a simple QDialog that shows a QLabel in black text. I'd like for the QLabel's text to turn red when I press the a key. I am using the designer to make the dialog. Here is my code:
myDialog.h
#include <QDialog>
#include <QWidget>
namespace Ui {
class myDialog;
}
class myDialog : public QDialog
{
Q_OBJECT
public:
explicit myDialog(QWidget* parent = 0);
~myDialog();
private:
Ui::myDialog* ui;
protected:
void keyPressEvent(QKeyEvent* event);
};
myDialog.cpp
#include "myDialog.h"
#include "ui_myDialog.h"
#include <QKeyEvent>
myDialog::myDialog(QWidget* parent) :
QDialog(parent),
ui(new Ui::myDialog)
{
ui->setupUi(this);
}
void myDialog::eventPressEvent(QKeyEvent* event)
{
if (event->key()==Qt::Key_A){
Ui_myDialog::label1->setStyleSheet(QStringLiteral("QLabel{color: rgb(170, 0, 0);}"));
} else {
qDebug << "FAIL";
}
}
myDialog::~myDialog()
{
delete ui;
}
ui_mydialog.h
/********************************************************************************
** Form generated from reading UI file 'about.ui'
** Created by: Qt User Interface Compiler version 5.5.0
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MYDIALOG_H
#define UI_MYDIALOG_H
...<snip>...
QT_BEGIN_NAMESPACE
class Ui_myDialog
{
public:
QLabel *label1;
void setupUi(QDialog *myDialog)
{
...<snip>...
label1 = new QLabel(myDialog);
label1->setObjectName(QStringLiteral("label1"));
label1->setGeometry(QRect(50, 333, 16, 20));
label1->setFont(font);
label1->setAlignment(Qt::AlignCenter);
...<snip>...
} // setupUi
...<snip>...
namespace Ui {
class myDialog: public Ui_myDialog {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MYDIALOG_H
So, here's the issue. When I build the project, a file called ui_mydialog.h gets created and is generated in the build folder. This file even says it was auto-generated by the Qt User Interface Compiler. When I try to change the stylesheet of label1 (which is declared in ui_mydialog.h) in myDialog.cpp using the line:
Ui_myDialog::label1->setStyleSheet(QStringLiteral("QLabel{color: rgb(170, 0, 0);}"));
...I get an error that says error: invalid use of non-static data member 'Ui_myDialog::label1'. This is where I'm stuck. How would I go about correctly passing label1 into the void myDialog::eventPressEvent(QKeyEvent* event) member function and modifying it?
Any help would be appreciated.
Using Ui_myDialog:: on a non-static member is incorrect.
You need to replace
Ui_myDialog::label1->setStyleSheet(QStringLiteral("QLabel{color: rgb(170, 0, 0);}"));
with
ui->label1->setStyleSheet(QStringLiteral("QLabel{color: rgb(170, 0, 0);}"));
You don't need new Ui::myDialog in 'myDialog.cpp'.
1) myDialog.h
Add #include "ui_mydialog.h"
Change Ui::myDialog* ui; to Ui::myDialog ui;
2) myDialog.cpp
Remove ui(new Ui::myDialog) in constructor.
And, then you can use ui.label1->......
I have an application with a few screens that I would like to load on application launch and keep in memory while the program is running. I want to be able to switch between screens on a button click, hiding the current screen while showing the next screen. There is not a direct path through the application, the user may go back and forth through screens in the application. I'm using Qt and new to c++.
The following is skeleton code I would like to get to work (or get advice about a better way to do it). I'm doing it this way in order to avoid memory leaks from creating new instances of the dialogs when moving back and forth through the application a number of times.
When I compile this, I get an error Undefined Reference to 'Screen2' in Screen2->show(); in Dialog1::on_pushButton_clicked() in dialog1.cpp. I tried everything I could to get this to compile without success. Why isn't Screen2 a valid pointer in dialog1.cpp?
I have a Manager which is run from Main and initialises the dialogs.
manager.cpp:
#include "manager.h"
#include "ui_manager.h"
Manager::Manager(QWidget *parent) :
QDialog(parent),
ui(new Ui::Manager)
{
ui->setupUi(this);
Screen1 = new Dialog1(this);
Screen2 = new Dialog2(this);
Screen1->show();
}
Manager::~Manager()
{
delete ui;
}
manager.h:
#ifndef MANAGER_H
#define MANAGER_H
#include <QDialog>
#include "dialog1.h"
#include "dialog2.h"
namespace Ui {
class Manager;
}
class Manager : public QDialog
{
Q_OBJECT
public:
explicit Manager(QWidget *parent = 0);
~Manager();
Dialog1 *Screen1;
Dialog2 *Screen2;
private:
Ui::Manager *ui;
};
#endif // MANAGER_H
dialog1.cpp:
#include "dialog1.h"
#include "ui_dialog1.h"
#include "manager.h"
#include "dialog2.h"
#include <QDebug>
extern Dialog1 *Screen1;
extern Dialog2 *Screen2;
Dialog1::Dialog1(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog1)
{
ui->setupUi(this);
}
Dialog1::~Dialog1()
{
delete ui;
}
void Dialog1::on_pushButton_clicked()
{
Screen2->show();
}
dialog1.h:
#ifndef DIALOG1_H
#define DIALOG1_H
#include <QDialog>
#include "dialog2.h"
class Manager;
namespace Ui {
class Dialog1;
}
class Dialog1 : public QDialog
{
Q_OBJECT
public:
explicit Dialog1(QWidget *parent = 0);
~Dialog1();
private slots:
void on_pushButton_clicked();
private:
Ui::Dialog1 *ui;
};
#endif // DIALOG1_H
dialog2.cpp:
#include "dialog2.h"
#include "ui_dialog2.h"
#include "dialog1.h"
#include "manager.h"
extern Dialog1 *Screen1;
extern Dialog2 *Screen2;
Dialog2::Dialog2(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog2)
{
ui->setupUi(this);
}
Dialog2::~Dialog2()
{
delete ui;
}
void Dialog2::on_pushButton_clicked()
{
Screen1->show();
}
All help appreciated!
Regards,
James
I'll explain you easiest way to get it work.
Make screen1 and screen2 private members of manager class.
Add signal buttonPressed() to both screens.
Emit signal on button press in each dialog.
Add slot to manager class to handle button press in dialogs
connect signals of dialogs to manager slot
Remove this in both dialogs:
extern Dialog1 *Screen1;
extern Dialog2 *Screen2;
You can not access them directly because thee are members of your manager object.
As a result you will be able to add as many screens as you want. Each screen won't know anything about others (you were trying to do so).
I wanted to create a window from a mainwindow, and send it a pointer to my main window. I did it one time, and i would do it again, but the second time, I always have this error at compilation "no appropriate default constructor available"
The main window:
#include "costsimulator.h"
#include "ui_costsimulator.h"
#include "stonepricewindow.h"
CostSimulator::CostSimulator(AionEnhancingSimulator *parent) : ui(new Ui::CostSimulator)
{
ui->setupUi(this);
parentPtr = parent;
stonePrice = createStonePrice();
connect(ui->aionEnhancingSimulator, SIGNAL(clicked()), this, SLOT(showAionEnhancingSimulatorWindow()));
connect(ui->stonePriceButton, SIGNAL(clicked()), this, SLOT(showStonePriceWindow()));
}
CostSimulator::~CostSimulator()
{
delete ui;
}
void CostSimulator::showAionEnhancingSimulatorWindow()
{
this->hide();
parentPtr->show();
}
QStringList *createStonePrice()
{
QStringList *tmp = new QStringList();
tmp->push_back(QString("80-30000000"));
return (tmp);
}
void CostSimulator::showStonePriceWindow()
{
StonePriceWindow *stonepricewindow = new StonePriceWindow(this);
stonepricewindow->show();
}
QStringList *CostSimulator::getStonePrice()
{
return (stonePrice);
}
and the header:
#ifndef COSTSIMULATOR_H
#define COSTSIMULATOR_H
#include <QDialog>
#include "aionenhancingsimulator.h"
namespace Ui {
class CostSimulator;
}
class CostSimulator : public QDialog
{
Q_OBJECT
public:
AionEnhancingSimulator *parentPtr;
explicit CostSimulator(AionEnhancingSimulator *parent);
~CostSimulator();
QStringList *stonePrice;
QStringList *createStonePrice();
QStringList *getStonePrice();
void showStonePriceWindow();
public slots:
void showAionEnhancingSimulatorWindow();
private:
Ui::CostSimulator *ui;
};
#endif // COSTSIMULATOR_H
and the window that cause the problem:
#include "stonepricewindow.h"
#include "ui_stonepricewindow.h"
#include <QStringListModel>
#include <QStandardItemModel>
#include <QtGui>
StonePriceWindow::StonePriceWindow(CostSimulator *parent) : ui(new Ui::StonePriceWindow)
{
ui->setupUi(this);
displayStonePriceList(parent);
}
StonePriceWindow::~StonePriceWindow()
{
delete ui;
}
void StonePriceWindow::displayStonePriceList(CostSimulator *parent)
{
// To do
}
the header
#ifndef STONEPRICEWINDOW_H
#define STONEPRICEWINDOW_H
#include <QDialog>
#include "costsimulator.h"
namespace Ui {
class StonePriceWindow;
}
class StonePriceWindow : public QDialog
{
Q_OBJECT
public:
explicit StonePriceWindow(CostSimulator *parent = 0);
~StonePriceWindow();
void displayStonePriceList(CostSimulator *parent);
private:
Ui::StonePriceWindow *ui;
};
#endif // STONEPRICEWINDOW_H
if I had this " StonePriceWindow() {}" to the header of StonePriceWindow, I have the following error: "multiple default constructors specified" and always the "no appropriate etc .."
Thanks for any help, I can't understand why.
Sorry, but I could not add a comment on the best answer..
I had a similar problem too, it appeared that there was a mismatch between the classname of the code I created and the dialogs' objectName property value in the Qt .ui file.
I opened the .ui file in QtDesigner, and changed the objectName property value to the classname I had used in my code. Afterwards compilation was going fine.
Try adding StonePriceWindow(){} and removing the default parameter for the other constructor.
When you write code like
StonePriceWindow x;
how does compiler know whether you call the parameterless constructor or another one with default value for parent?
You need to either remove the other one, or remove the default value from it.
I found the problem.
In the StonePrinceWindow.ui, there was an obsolete name of the UI, so the auto-generated ui_stonepricewindow keep the obsolete name (even after a clean) and the compiler never find the ctor.
The solution is to change the strings
#ifndef COSTSIMULATOR_H
#define COSTSIMULATOR_H
in either of the files costsimulator.h and ui_costsimulator.h
Qt places the same #ifndef #define expression in auto generated ui_costsimulator.h